Commit bb11ac5a authored by MARCHE Claude's avatar MARCHE Claude

Merge branch 'claude'

parents f7b45e7c 12855fcc
......@@ -226,6 +226,8 @@ pvsbin/
/examples/vstte12_combinators/*__*.ml
/examples/in_progress/bigInt/jsmain.js
/examples/in_progress/bigInt/*__*.ml
/examples/in_progress/mp/jsmain.js
/examples/in_progress/mp/*__*.ml
# modules
......
......@@ -45,6 +45,14 @@ module mach.int.UInt32
syntax val (<) "(<)"
syntax val (>=) "(>=)"
syntax val (>) "(>)"
(* direct realization of add_with_carry.
Remind that parameters x y and c are assumed to denote unsigned integers
less than 2^{32} *)
syntax val add_with_carry "(fun x y c ->
let r = Int64.add x (Int64.add y c) in
(Int64.logand r 0xFFFFFFFFL,Int64.shift_right_logical r 32))"
end
module mach.int.Int63
......
(** A library for arbitrary-precision integer arithmetic *)
(** {1 A library for arbitrary-precision integer arithmetic} *)
module N
......@@ -11,10 +11,18 @@ module N
use import int.Int
use import int.Power
(** {2 data type for unbound integers and invariants} *)
constant base : int = 10000
(** a power of ten whose square fits on 31 bits *)
type t = { mutable digits: array int31 }
(** an unbounded integer is stored in an array of 31 bits integers,
with all values between 0 included and [base] excluded
index 0 is the lsb. the msb is never 0.
*)
predicate ok_array (a:array int31) =
(to_int a.length >= 1 -> to_int a[to_int a.length - 1] <> 0) /\
forall i:int. 0 <= i < to_int a.length ->
......@@ -22,6 +30,9 @@ module N
predicate ok (x:t) = ok_array x.digits
(** {2 value stored in an array} *)
(* [value_sub x n m] denotes the integer represented by
the digits x[n..m-1] with lsb at index n *)
function value_sub (x:map int int31) (n:int) (m:int) (l:int): int
......@@ -79,6 +90,46 @@ module N
function value (x:t) : int = value_array x.digits
(** {2 general lemmas} *)
(* moved to stdlib
lemma power_monotonic:
forall x y z. 0 <= x <= y -> power z x <= power z y
*)
lemma power_non_neg:
forall x y. x >= 0 /\ y >= 0 -> power x y >= 0
lemma value_zero:
forall x:array int31.
let l = to_int x.length in
l = 0 -> value_array x = 0
lemma value_sub_upper_bound:
forall x:map int int31, n l:int. 0 <= n <= l ->
(forall i:int. 0 <= i < n -> 0 <= to_int (Map.get x i) < base) ->
value_sub x 0 n l < power base n
lemma value_sub_lower_bound:
forall x:map int int31, n l:int. 0 <= n <= l ->
(forall i:int. 0 <= i < n -> 0 <= to_int (Map.get x i) < base) ->
0 <= value_sub x 0 n l
lemma value_sub_lower_bound_tight:
forall x:map int int31, n l:int. 0 < n <= l ->
(forall i:int. 0 <= i < n-1 -> 0 <= to_int (Map.get x i) < base) ->
0 < to_int (Map.get x (n-1)) < base ->
power base (n-1) <= value_sub x 0 n l
lemma value_bounds_array:
forall x:array int31. ok_array x ->
let l = to_int x.length in
l > 0 -> power base (l-1) <= value_array x < power base l
(** {2 conversion from a small integer} *)
let from_small_int (n:int31) : t
requires { 0 <= to_int n < base }
ensures { ok result }
......@@ -92,6 +143,98 @@ module N
in
{ digits = a }
(** {2 Comparisons} *)
exception Break
(* Comparisons *)
let compare_array (x y:array int31) : int31
requires { ok_array x /\ ok_array y }
ensures { -1 <= to_int result <= 1 }
ensures { to_int result = -1 -> value_array x < value_array y }
ensures { to_int result = 0 -> value_array x = value_array y }
ensures { to_int result = 1 -> value_array x > value_array y }
= let zero = of_int 0 in
let one = of_int 1 in
let minus_one = of_int (-1) in
let l1 = x.length in
let l2 = y.length in
if Int31.(<) l1 l2 then minus_one else
if Int31.(>) l1 l2 then one else
let i = ref l1 in
let res = ref zero in
let ghost acc = ref 0 in
try
while Int31.(>) !i zero do
invariant { to_int !res = 0 }
(* needed to be sure it is zero at normal exit ! *)
invariant { 0 <= to_int !i <= to_int l1 }
invariant {
value_sub x.elts 0 (to_int !i) (to_int l1) = value_array x - !acc
}
invariant {
value_sub y.elts 0 (to_int !i) (to_int l1) = value_array y - !acc
}
variant { to_int !i }
assert { value_array x - !acc =
value_sub x.elts 0 (to_int !i - 1) (to_int l1) +
power base (to_int !i - 1) * (to_int x[to_int !i - 1])
};
assert { value_array y - !acc =
value_sub y.elts 0 (to_int !i - 1) (to_int l1) +
power base (to_int !i - 1) * (to_int y[to_int !i - 1])
};
i := Int31.(-) !i one;
if Int31.(<) x[!i] y[!i] then
begin
assert { value_sub y.elts 0 (to_int !i) (to_int l1) >= 0 };
assert { value_sub x.elts 0 (to_int !i) (to_int l1) <
power base (to_int !i)
};
assert { value_array y - !acc >=
power base (to_int !i) * (to_int y[to_int !i])
};
assert { to_int y[to_int !i] >= to_int x[to_int !i] + 1 };
assert { power base (to_int !i) * (to_int y[to_int !i]) >=
power base (to_int !i) * (to_int x[to_int !i] + 1) };
assert { power base (to_int !i) * (to_int y[to_int !i]) >=
power base (to_int !i) * (to_int x[to_int !i])
+ power base (to_int !i) };
res := minus_one;
raise Break;
end;
if Int31.(>) x[!i] y[!i] then
begin
assert { value_sub x.elts 0 (to_int !i) (to_int l1) >= 0 };
assert { value_sub y.elts 0 (to_int !i) (to_int l1) <
power base (to_int !i)
};
assert { value_array x - !acc >=
power base (to_int !i) * (to_int x[to_int !i])
};
assert { to_int x[to_int !i] >= to_int y[to_int !i] + 1 };
assert { power base (to_int !i) * (to_int x[to_int !i]) >=
power base (to_int !i) * (to_int y[to_int !i] + 1) };
assert { power base (to_int !i) * (to_int x[to_int !i]) >=
power base (to_int !i) * (to_int y[to_int !i])
+ power base (to_int !i) };
res := one;
raise Break
end;
acc := !acc + power base (to_int !i) * to_int x[!i];
done;
raise Break
with Break -> !res
end
let eq (x y:t) : bool
requires { ok x /\ ok y }
ensures { if result then value x = value y else value x <> value y }
= Int31.eq (compare_array x.digits y.digits) (of_int 0)
(** {2 arithmetic operations} *)
exception TooManyDigits
let add_array (x y:array int31) : array int31
......@@ -176,7 +319,7 @@ module N
assert { value_sub arr.elts 0 (to_int !i) (to_int h + 1) =
value_sub (at arr 'L).elts 0 (to_int !i) (to_int h + 1) };
assert { value_array arr = value_array x + value_array y };
abstract
abstract
ensures { -1 <= to_int !non_null_idx <= to_int !i }
ensures { to_int !non_null_idx >= 0 -> to_int arr[to_int !non_null_idx] <> 0 }
ensures {
......@@ -194,9 +337,9 @@ module N
MapEq.map_eq_sub arr.elts arr'.elts 0 (to_int len) };
assert { value_sub arr.elts 0 (to_int len) (to_int len) =
value_sub arr'.elts 0 (to_int len) (to_int len) } ;
assert { to_int arr'.length >= 1 ->
assert { to_int arr'.length >= 1 ->
to_int arr'[to_int arr'.length - 1] <> 0 };
assert { forall j. 0 <= j < to_int arr'.length ->
assert { forall j. 0 <= j < to_int arr'.length ->
0 <= to_int arr'[j] < base };
arr'
......@@ -214,7 +357,26 @@ module N
in
{ digits = res }
(* Multiplication: school book algorithm *)
(*
let rec mul_array (x y:array int31) : array int31
requires { ok_array x /\ ok_array y }
ensures { ok_array result }
ensures { value_array result = value_array x * value_array y }
raises { TooManyDigits -> true }
= let zero = of_int 0 in
let one = of_int 1 in
let two = of_int 2 in
let base31 = of_int 10000 in
assert { to_int base31 = base };
let l1 = x.digits.length in
let l2 = y.digits.length in
TODO
*)
(* Multiplication: Karatsuba algorithm
let rec mul_array (x y:array int31) : array int31
requires { ok_array x /\ ok_array y }
ensures { ok_array result }
......@@ -233,8 +395,12 @@ module N
let h = Int31.(/) n base31 in
let l = Int31.(-) n (Int31.(*) h base31) in
if Int31.eq h zero then
let arr = Array31.make one l in
{ digits = arr }
if Int31.eq l zero then
let arr = Array31.make zero zero in
{ digits = arr }
else
let arr = Array31.make one l in
{ digits = arr }
else
let arr = Array31.make two l in
arr.(1) <- h;
......@@ -260,6 +426,8 @@ module N
let z2 = mul_array high1 high2 in
(*
return (z2*10^(2*m2))+((z1-z2-z0)*10^(m2))+(z0)
-> we need subtraction !
*)
let mul (x y:t) : t
......
This diff is collapsed.
(** {1 Multi-precision integer arithmetic} *)
(** {1 Natural numbers} *)
module N
use import map.Map
use import mach.array.Array31
use import mach.int.Int31
use import ref.Ref
use import int.Int
use import int.Power
(** {2 unbounded precision natural numbers}
these are represented by an array of "limbs". A limb is expected to
be a machine word, abstractly it can be any unsigned integer type
*)
(* does not allow extraction...
type limb
clone mach.int.Unsigned as Limb
with type t = limb
axiom limb_max_bound: 1 <= Limb.max
constant radix : int = Limb.max + 1
*)
(* temporary: stick to uint32 *)
use mach.int.UInt32 as Limb
type limb = Limb.uint32
lemma limb_max_bound: 1 <= Limb.max_uint32
constant radix : int = Limb.max_uint32 + 1
(**)
function l2i (x:limb) : int = Limb.to_int x
function p2i (i:int31) : int = Int31.to_int i
type t = { mutable digits: array limb }
(** {2 Integer value of a natural number} *)
(** [value_sub x n m] denotes the integer represented by
the digits x[n..m-1] with lsb at index n *)
function value_sub (x:map int limb) (n:int) (m:int) : int
(* =
if n < m then
x.[n] + radix * value_sub x (n+1) m
else 0
*)
axiom value_sub_next:
forall x,n,m.
value_sub x n m =
if n < m then
l2i (Map.get x n) + radix * value_sub x (n+1) m
else 0
use map.MapEq
let rec lemma value_sub_frame (x y:map int limb) (n m:int)
requires { MapEq.map_eq_sub x y n m }
variant { m - n }
ensures { value_sub x n m = value_sub y n m }
=
if n < m then value_sub_frame x y (n+1) m else ()
let rec lemma value_sub_tail (x:map int limb) (n m:int)
requires { n <= m }
variant { m - n }
ensures {
value_sub x n (m+1) =
value_sub x n m + l2i (Map.get x m) * power radix (m-n) }
= if n < m then value_sub_tail x (n+1) m else ()
let rec lemma value_sub_concat (x:map int limb) (n m l:int)
requires { n <= m <= l}
variant { m - n }
ensures {
value_sub x n l =
value_sub x n m + value_sub x m l * power radix (m-n) }
= if n < m then value_sub_concat x (n+1) m l else ()
function value_array (x:array limb) : int =
value_sub x.elts 0 (p2i x.length)
function value (x:t) : int = value_array x.digits
let lemma value_sub_update (x:map int limb) (i n m:int) (v:limb)
requires { n <= i < m }
ensures {
value_sub (Map.set x i v) n m =
value_sub x n m + power radix (i - n) * (l2i v - l2i (Map.get x i))
}
= assert { MapEq.map_eq_sub x (Map.set x i v) n i };
assert { MapEq.map_eq_sub x (Map.set x i v) (i+1) m };
value_sub_concat x n i m;
value_sub_concat (Map.set x i v) n i m
let rec lemma value_zero (x:map int limb) (n m:int)
requires { MapEq.map_eq_sub x (Map.const Limb.zero_unsigned) n m }
variant { m - n }
ensures { value_sub x n m = 0 }
= if n < m then value_zero x (n+1) m else ()
(** {2 conversion from a small integer} *)
let zero () =
{ digits = Array31.make (Int31.of_int 0) (Limb.of_int 0) }
let from_limb (n:limb) : t
ensures { value result = l2i n }
= { digits = Array31.make (Int31.of_int 1) n }
(** {2 copy, enlarge} *)
let copy (x:t) : t
ensures { value result = value x }
= let limb_zero = Limb.of_int 0 in
let zero = Int31.of_int 0 in
let lx = x.digits.length in
let r = Array31.make lx limb_zero in
Array31.blit x.digits zero r zero lx;
assert { MapEq.map_eq_sub x.digits.elts r.elts 0 (p2i lx) };
{ digits = r }
let enlarge (x:t) (l:int31) : unit
requires { p2i l > p2i x.digits.length }
writes { x }
ensures { x.digits.length = l }
ensures { MapEq.map_eq_sub x.digits.elts (Map.const Limb.zero_unsigned)
(p2i (old x).digits.length) (p2i l) }
ensures { value x = value (old x) }
= 'Init:
let limb_zero = Limb.of_int 0 in
let zero = Int31.of_int 0 in
let lx = x.digits.length in
let r = Array31.make l limb_zero in
assert { MapEq.map_eq_sub r.elts (Map.const limb_zero) (p2i lx) (p2i l) };
Array31.blit x.digits zero r zero lx;
assert { MapEq.map_eq_sub x.digits.elts r.elts 0 (p2i lx) };
assert { value_sub x.digits.elts 0 (p2i lx) = value (at x 'Init) };
assert { MapEq.map_eq_sub r.elts (Map.const limb_zero) (p2i lx) (p2i l) };
assert { value_sub r.elts (p2i lx) (p2i l) = 0 };
assert { value_sub r.elts 0 (p2i l) = value_sub r.elts 0 (p2i lx)
+ value_sub r.elts (p2i lx) (p2i l) * power radix (p2i lx) };
x.digits <- r
(** {2 Comparisons} *)
let rec lemma value_sub_lower_bound (x:map int limb) (x1 x2:int)
requires { x1 <= x2 }
variant { x2 - x1 }
ensures { 0 <= value_sub x x1 x2 }
= if x1 = x2 then () else
begin
assert { value_sub x x1 x2 = l2i (Map.get x x1) + radix * value_sub x (x1+1) x2};
value_sub_lower_bound x (x1+1) x2
end
let rec lemma value_sub_upper_bound (x:map int limb) (x1 x2:int)
requires { x1 <= x2 }
variant { x2 - x1 }
ensures { value_sub x x1 x2 < power radix (x2 - x1) }
= if x1 = x2 then () else
begin
assert { value_sub x x1 x2 <= value_sub x x1 (x2-1) + power radix (x2-x1-1) * (radix - 1) };
value_sub_upper_bound x x1 (x2-1)
end
let lemma value_sub_lower_bound_tight (x:map int limb) (x1 x2:int)
requires { x1 < x2 }
ensures { power radix (x2-x1-1) * l2i (Map.get x (x2-1)) <= value_sub x x1 x2 }
= assert { value_sub x x1 x2 = value_sub x x1 (x2-1)
+ power radix (x2-x1-1) * l2i (Map.get x (x2-1)) }
let rec lemma value_sub_upper_bound_tight (x:map int limb) (x1 x2:int)
requires { x1 <= x2 }
variant { x2 - x1 }
ensures { value_sub x x1 x2 < power radix (x2-x1) }
= if x1 = x2 then () else
value_sub_upper_bound_tight x x1 (x2-1)
let lemma value_sub_upper_bound_tighter (x:map int limb) (x1 x2:int)
requires { x1 < x2 }
ensures { value_sub x x1 x2 < power radix (x2-x1-1) * (l2i (Map.get x (x2-1)) + 1) }
= value_sub_upper_bound_tight x x1 (x2-1)
exception Break31 int31
function compare_int (x y:int) : int =
if x < y then -1 else if x=y then 0 else 1
let compare_limbs (x y:array limb) (x1 x2 y1 y2:int31) : int31
requires { 0 <= p2i x1 <= p2i x2 <= p2i x.length }
requires { 0 <= p2i y1 <= p2i y2 <= p2i y.length }
requires { p2i x2 - p2i x1 >= p2i y2 - p2i y1 }
ensures { p2i result = compare_int
(value_sub x.elts (p2i x1) (p2i x2))
(value_sub y.elts (p2i y1) (p2i y2)) }
= let limb_zero = Limb.of_int 0 in
let zero = Int31.of_int 0 in
let one = Int31.of_int 1 in
let minus_one = Int31.(-_) one in
let i = ref x2 in
let x3 = Int31.(+) x1 (Int31.(-) y2 y1) in
try
while Int31.(>) !i x3 do
invariant { p2i x3 <= p2i !i <= p2i x2 }
invariant { value_sub x.elts (p2i !i) (p2i x2) = 0 }
variant { p2i !i }
i := Int31.(-) !i one;
if Limb.ne x[!i] limb_zero then
begin
assert { l2i x[p2i !i] >= 1 };
assert { value_sub x.elts (p2i x1) (p2i !i + 1) >=
power radix (p2i !i - p2i x1) * l2i x[p2i !i] };
assert { power radix (p2i !i - p2i x1) * l2i x[p2i !i] >= power radix (p2i !i - p2i x1) };
assert { value_sub x.elts (p2i x1) (p2i x2) = value_sub x.elts (p2i x1) (p2i !i + 1)
+ power radix (p2i !i + 1 - p2i x1) * value_sub x.elts (p2i !i + 1) (p2i x2)};
assert { value_sub x.elts (p2i x1) (p2i x2) >= power radix (p2i !i - p2i x1) };
assert { value_sub y.elts (p2i y1) (p2i y2) < power radix (p2i y2 - p2i y1) };
assert { power radix (p2i y2 - p2i y1) <= power radix (p2i !i - p2i x1) };
raise (Break31 one);
end
done;
while Int31.(>) !i x1 do
invariant { p2i x1 <= p2i !i <= p2i x3 }
invariant {
value_sub x.elts (p2i !i) (p2i x2) =
value_sub y.elts (p2i y1 + (p2i !i - p2i x1)) (p2i y2) }
variant { p2i !i }
i := Int31.(-) !i one;
let j = Int31.(+) y1 (Int31.(-) !i x1) in
assert { value_sub x.elts (p2i x1) (p2i x2) = value_sub x.elts (p2i x1) (p2i !i + 1)
+ power radix (p2i !i + 1 - p2i x1) * value_sub x.elts (p2i !i + 1) (p2i x2)};
assert { value_sub y.elts (p2i y1) (p2i y2) = value_sub y.elts (p2i y1) (p2i j + 1)
+ power radix (p2i j + 1 - p2i y1) * value_sub y.elts (p2i j + 1) (p2i y2)};
if Limb.(<) x[!i] y[j] then
begin
assert { value_sub x.elts (p2i x1) (p2i !i + 1) < power radix (p2i !i - p2i x1) * (l2i x[p2i !i] + 1) };
assert { power radix (p2i !i - p2i x1) * (l2i x[p2i !i] + 1) <= power radix (p2i j - p2i y1) * l2i y[p2i j] };
assert { power radix (p2i j - p2i y1) * l2i y[p2i j] <= value_sub y.elts (p2i y1) (p2i j + 1) };
raise (Break31 minus_one);
end;
if Limb.(>) x[!i] y[j] then
begin
assert { value_sub y.elts (p2i y1) (p2i j + 1) < power radix (p2i j - p2i y1) * (l2i y[p2i j] + 1) };
assert { power radix (p2i j - p2i y1) * (l2i y[p2i j] + 1) <= power radix (p2i !i - p2i x1) * l2i x[p2i !i] };
assert { power radix (p2i !i - p2i x1) * l2i x[p2i !i] <= value_sub x.elts (p2i x1) (p2i !i + 1) };
raise (Break31 one);
end
done;
zero
with Break31 x -> x
end
let compare (x y:t) : int31
ensures { p2i result = compare_int (value x) (value y) }
= let zero = Int31.of_int 0 in
let lx = x.digits.length in
let ly = y.digits.length in
if Int31.(>=) lx ly then compare_limbs x.digits y.digits zero lx zero ly
else Int31.(-_) (compare_limbs y.digits x.digits zero ly zero lx)
(** {2 addition} *)
exception Break
let add_limb (x:array limb) (y:limb) (x1 x2:int31) : limb
requires { 0 <= p2i x1 <= p2i x2 <= p2i x.length }
writes { x }
ensures { forall j. 0 <= j < p2i x1 \/ p2i x2 <= j < p2i x.length -> x[j] = (old x)[j] }
ensures { value_array x + power radix (p2i x2) * l2i result
= value_array (old x) + power radix (p2i x1) * l2i y }
= 'Init:
let limb_zero = Limb.of_int 0 in
let one = Int31.of_int 1 in
let i = ref x1 in
let c = ref y in
while Int31.(<) !i x2 && Limb.ne !c limb_zero do
invariant { forall j. 0 <= j < p2i x1 \/ p2i x2 <= j < p2i x.length ->
x[j] = (at x 'Init)[j] }
invariant { p2i x1 <= p2i !i <= p2i x2 }
invariant {
value_array x + power radix (p2i !i) * l2i !c =
value_array (at x 'Init) + power radix (p2i x1) * l2i y }
variant { p2i x2 - p2i !i }
let (r,c') = Limb.add_with_carry x[!i] limb_zero !c in
'L:
x[!i] <- r;
assert { value_array x = value_array (at x 'L)
+ power radix (p2i !i) * (l2i r - l2i (at x 'L)[p2i !i]) };
c := c';
i := Int31.(+) !i one;
done;
!c
let add_limbs (x y:array limb) (x1 x2 y1 y2:int31) : limb
requires { 0 <= p2i x1 <= p2i x2 <= p2i x.length }
requires { 0 <= p2i y1 <= p2i y2 <= p2i y.length }
requires { p2i x2 - p2i x1 >= p2i y2 - p2i y1 }
writes { x }
ensures { forall j. 0 <= j < p2i x1 \/ p2i x2 <= j < p2i x.length -> x[j] = (old x)[j] }
ensures {
value_array x + power radix (p2i x2) * l2i result
= value_array (old x) +
power radix (p2i x1) * value_sub y.elts (p2i y1) (p2i y2) }
= 'Init:
let limb_zero = Limb.of_int 0 in
let one = Int31.of_int 1 in
let i = ref y1 in
let c = ref limb_zero in
while Int31.(<) !i y2 do
invariant { forall j. 0 <= j < p2i x1 \/ p2i x2 <= j < p2i x.length ->
x[j] = (at x 'Init)[j] }
invariant { p2i y1 <= p2i !i <= p2i y2 }
invariant {
let j = p2i x1 + (p2i !i - p2i y1) in
value_array x + power radix j * l2i !c
= value_array (at x 'Init) +
power radix (p2i x1) * value_sub y.elts (p2i y1) (p2i !i) }
variant { p2i y2 - p2i !i }
let j = Int31.(+) x1 (Int31.(-) !i y1) in
let (r,c') = Limb.add_with_carry x[j] y[!i] !c in
'L:
x[j] <- r;
assert { value_array x = value_array (at x 'L)
+ power radix (p2i j) * (l2i r - l2i (at x 'L)[p2i j]) };
assert { value_sub y.elts (p2i y1) (p2i !i + 1) =
value_sub y.elts (p2i y1) (p2i !i)
+ power radix (p2i !i - p2i y1) * l2i y[p2i !i] };
assert { power radix (p2i x1 + (p2i !i + 1 - p2i y1)) = power radix (p2i j) * radix };
assert { power radix (p2i x1 + (p2i !i - p2i y1))
= power radix (p2i x1) * power radix (p2i !i - p2i y1) };
c := c';
i := Int31.(+) !i one;
done;
add_limb x !c (Int31.(+) x1 (Int31.(-) y2 y1)) x2
exception TooManyDigits
let add_aux_in_place (x:t) (y:array limb) : unit
requires { p2i x.digits.length >= p2i y.length }
(* what is the right clause ? writes { x, x.digits } *)
ensures { value x = value (old x) + value_array y }
raises { TooManyDigits -> true }
= 'Init:
let zero = Int31.of_int 0 in
let one = Int31.of_int 1 in
let limb_zero = Limb.of_int 0 in
let lx = x.digits.length in