PageRenderTime 56ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/bigint.ml

https://bitbucket.org/makarius/coq-pide
OCaml | 504 lines | 297 code | 70 blank | 137 comment | 137 complexity | 654e9b170946fab2fab7bef1ed4b4a48 MD5 | raw file
Possible License(s): LGPL-2.1
  1. (************************************************************************)
  2. (* v * The Coq Proof Assistant / The Coq Development Team *)
  3. (* <O___,, * INRIA - CNRS - LIX - LRI - PPS - Copyright 1999-2012 *)
  4. (* \VV/ **************************************************************)
  5. (* // * This file is distributed under the terms of the *)
  6. (* * GNU Lesser General Public License Version 2.1 *)
  7. (************************************************************************)
  8. (***************************************************)
  9. (* Basic operations on (unbounded) integer numbers *)
  10. (***************************************************)
  11. (* An integer is canonically represented as an array of k-digits blocs,
  12. i.e. in base 10^k.
  13. 0 is represented by the empty array and -1 by the singleton [|-1|].
  14. The first bloc is in the range ]0;base[ for positive numbers.
  15. The first bloc is in the range [-base;-1[ for numbers < -1.
  16. All other blocs are numbers in the range [0;base[.
  17. Negative numbers are represented using 2's complementation :
  18. one unit is "borrowed" from the top block for complementing
  19. the other blocs. For instance, with 4-digits blocs,
  20. [|-5;6789|] denotes -43211
  21. since -5.10^4+6789=-((4.10^4)+(10000-6789)) = -43211
  22. The base is a power of 10 in order to facilitate the parsing and printing
  23. of numbers in digital notation.
  24. All functions, to the exception of to_string and of_string should work
  25. with an arbitrary base, even if not a power of 10.
  26. In practice, we set k=4 on 32-bits machines, so that no overflow in ocaml
  27. machine words (i.e. the interval [-2^30;2^30-1]) occur when multiplying two
  28. numbers less than (10^k). On 64-bits machines, k=9.
  29. *)
  30. (* The main parameters *)
  31. let size =
  32. let rec log10 n = if n < 10 then 0 else 1 + log10 (n / 10) in
  33. (log10 max_int) / 2
  34. let format_size =
  35. (* How to parametrize a printf format *)
  36. if size = 4 then Printf.sprintf "%04d"
  37. else if size = 9 then Printf.sprintf "%09d"
  38. else fun n ->
  39. let rec aux j l n =
  40. if j=size then l else aux (j+1) (string_of_int (n mod 10) :: l) (n/10)
  41. in String.concat "" (aux 0 [] n)
  42. (* The base is 10^size *)
  43. let base =
  44. let rec exp10 = function 0 -> 1 | n -> 10 * exp10 (n-1) in exp10 size
  45. (******************************************************************)
  46. (* First, we represent all numbers by int arrays.
  47. Later, we will optimize the particular case of small integers *)
  48. (******************************************************************)
  49. module ArrayInt = struct
  50. (* Basic numbers *)
  51. let zero = [||]
  52. let neg_one = [|-1|]
  53. (* An array is canonical when
  54. - it is empty
  55. - it is [|-1|]
  56. - its first bloc is in [-base;-1[U]0;base[
  57. and the other blocs are in [0;base[. *)
  58. let canonical n =
  59. let ok x = (0 <= x && x < base) in
  60. let rec ok_tail k = (k = 0) || (ok n.(k) && ok_tail (k-1)) in
  61. let ok_init x = (-base <= x && x < base && x <> -1 && x <> 0)
  62. in
  63. (n = [||]) || (n = [|-1|]) ||
  64. (ok_init n.(0) && ok_tail (Array.length n - 1))
  65. (* [normalize_pos] : removing initial blocks of 0 *)
  66. let normalize_pos n =
  67. let k = ref 0 in
  68. while !k < Array.length n & n.(!k) = 0 do incr k done;
  69. Array.sub n !k (Array.length n - !k)
  70. (* [normalize_neg] : avoid (-1) as first bloc.
  71. input: an array with -1 as first bloc and other blocs in [0;base[
  72. output: a canonical array *)
  73. let normalize_neg n =
  74. let k = ref 1 in
  75. while !k < Array.length n & n.(!k) = base - 1 do incr k done;
  76. let n' = Array.sub n !k (Array.length n - !k) in
  77. if Array.length n' = 0 then [|-1|] else (n'.(0) <- n'.(0) - base; n')
  78. (* [normalize] : avoid 0 and (-1) as first bloc.
  79. input: an array with first bloc in [-base;base[ and others in [0;base[
  80. output: a canonical array *)
  81. let rec normalize n =
  82. if Array.length n = 0 then n
  83. else if n.(0) = -1 then normalize_neg n
  84. else if n.(0) = 0 then normalize_pos n
  85. else n
  86. (* Opposite (expects and returns canonical arrays) *)
  87. let neg m =
  88. if m = zero then zero else
  89. let n = Array.copy m in
  90. let i = ref (Array.length m - 1) in
  91. while !i > 0 & n.(!i) = 0 do decr i done;
  92. if !i = 0 then begin
  93. n.(0) <- - n.(0);
  94. (* n.(0) cannot be 0 since m is canonical *)
  95. if n.(0) = -1 then normalize_neg n
  96. else if n.(0) = base then (n.(0) <- 0; Array.append [| 1 |] n)
  97. else n
  98. end else begin
  99. (* here n.(!i) <> 0, hence 0 < base - n.(!i) < base for n canonical *)
  100. n.(!i) <- base - n.(!i); decr i;
  101. while !i > 0 do n.(!i) <- base - 1 - n.(!i); decr i done;
  102. (* since -base <= n.(0) <= base-1, hence -base <= -n.(0)-1 <= base-1 *)
  103. n.(0) <- - n.(0) - 1;
  104. (* since m is canonical, m.(0)<>0 hence n.(0)<>-1,
  105. and m=-1 is already handled above, so here m.(0)<>-1 hence n.(0)<>0 *)
  106. n
  107. end
  108. let push_carry r j =
  109. let j = ref j in
  110. while !j > 0 & r.(!j) < 0 do
  111. r.(!j) <- r.(!j) + base; decr j; r.(!j) <- r.(!j) - 1
  112. done;
  113. while !j > 0 & r.(!j) >= base do
  114. r.(!j) <- r.(!j) - base; decr j; r.(!j) <- r.(!j) + 1
  115. done;
  116. (* here r.(0) could be in [-2*base;2*base-1] *)
  117. if r.(0) >= base then (r.(0) <- r.(0) - base; Array.append [| 1 |] r)
  118. else if r.(0) < -base then (r.(0) <- r.(0) + 2*base; Array.append [| -2 |] r)
  119. else normalize r (* in case r.(0) is 0 or -1 *)
  120. let add_to r a j =
  121. if a = zero then r else begin
  122. for i = Array.length r - 1 downto j+1 do
  123. r.(i) <- r.(i) + a.(i-j);
  124. if r.(i) >= base then (r.(i) <- r.(i) - base; r.(i-1) <- r.(i-1) + 1)
  125. done;
  126. r.(j) <- r.(j) + a.(0);
  127. push_carry r j
  128. end
  129. let add n m =
  130. let d = Array.length n - Array.length m in
  131. if d > 0 then add_to (Array.copy n) m d else add_to (Array.copy m) n (-d)
  132. let sub_to r a j =
  133. if a = zero then r else begin
  134. for i = Array.length r - 1 downto j+1 do
  135. r.(i) <- r.(i) - a.(i-j);
  136. if r.(i) < 0 then (r.(i) <- r.(i) + base; r.(i-1) <- r.(i-1) - 1)
  137. done;
  138. r.(j) <- r.(j) - a.(0);
  139. push_carry r j
  140. end
  141. let sub n m =
  142. let d = Array.length n - Array.length m in
  143. if d >= 0 then sub_to (Array.copy n) m d
  144. else let r = neg m in add_to r n (Array.length r - Array.length n)
  145. let rec mult m n =
  146. if m = zero or n = zero then zero else
  147. let l = Array.length m + Array.length n in
  148. let r = Array.create l 0 in
  149. for i = Array.length m - 1 downto 0 do
  150. for j = Array.length n - 1 downto 0 do
  151. let p = m.(i) * n.(j) + r.(i+j+1) in
  152. let (q,s) =
  153. if p < 0
  154. then (p + 1) / base - 1, (p + 1) mod base + base - 1
  155. else p / base, p mod base in
  156. r.(i+j+1) <- s;
  157. if q <> 0 then r.(i+j) <- r.(i+j) + q;
  158. done
  159. done;
  160. normalize r
  161. (* Comparisons *)
  162. let is_strictly_neg n = n<>[||] && n.(0) < 0
  163. let is_strictly_pos n = n<>[||] && n.(0) > 0
  164. let is_neg_or_zero n = n=[||] or n.(0) < 0
  165. let is_pos_or_zero n = n=[||] or n.(0) > 0
  166. let rec less_than_same_size m n i j =
  167. i < Array.length m &&
  168. (m.(i) < n.(j) or (m.(i) = n.(j) && less_than_same_size m n (i+1) (j+1)))
  169. let less_than m n =
  170. if is_strictly_neg m then
  171. is_pos_or_zero n or Array.length m > Array.length n
  172. or (Array.length m = Array.length n && less_than_same_size m n 0 0)
  173. else
  174. is_strictly_pos n && (Array.length m < Array.length n or
  175. (Array.length m = Array.length n && less_than_same_size m n 0 0))
  176. (* For this equality test it is critical that n and m are canonical *)
  177. let equal m n = (m = n)
  178. let less_than_shift_pos k m n =
  179. (Array.length m - k < Array.length n)
  180. or (Array.length m - k = Array.length n && less_than_same_size m n k 0)
  181. let rec can_divide k m d i =
  182. (i = Array.length d) or
  183. (m.(k+i) > d.(i)) or
  184. (m.(k+i) = d.(i) && can_divide k m d (i+1))
  185. (* For two big nums m and d and a small number q,
  186. computes m - d * q * base^(|m|-|d|-k) in-place (in m).
  187. Both m d and q are positive. *)
  188. let sub_mult m d q k =
  189. if q <> 0 then
  190. for i = Array.length d - 1 downto 0 do
  191. let v = d.(i) * q in
  192. m.(k+i) <- m.(k+i) - v mod base;
  193. if m.(k+i) < 0 then (m.(k+i) <- m.(k+i) + base; m.(k+i-1) <- m.(k+i-1) -1);
  194. if v >= base then begin
  195. m.(k+i-1) <- m.(k+i-1) - v / base;
  196. let j = ref (i-1) in
  197. while m.(k + !j) < 0 do (* result is positive, hence !j remains >= 0 *)
  198. m.(k + !j) <- m.(k + !j) + base; decr j; m.(k + !j) <- m.(k + !j) -1
  199. done
  200. end
  201. done
  202. (** Euclid division m/d = (q,r)
  203. This is the "Floor" variant, as with ocaml's /
  204. (but not as ocaml's Big_int.quomod_big_int).
  205. We have sign r = sign m *)
  206. let euclid m d =
  207. let isnegm, m =
  208. if is_strictly_neg m then (-1),neg m else 1,Array.copy m in
  209. let isnegd, d = if is_strictly_neg d then (-1),neg d else 1,d in
  210. if d = zero then raise Division_by_zero;
  211. let q,r =
  212. if less_than m d then (zero,m) else
  213. let ql = Array.length m - Array.length d in
  214. let q = Array.create (ql+1) 0 in
  215. let i = ref 0 in
  216. while not (less_than_shift_pos !i m d) do
  217. if m.(!i)=0 then incr i else
  218. if can_divide !i m d 0 then begin
  219. let v =
  220. if Array.length d > 1 && d.(0) <> m.(!i) then
  221. (m.(!i) * base + m.(!i+1)) / (d.(0) * base + d.(1) + 1)
  222. else
  223. m.(!i) / d.(0) in
  224. q.(!i) <- q.(!i) + v;
  225. sub_mult m d v !i
  226. end else begin
  227. let v = (m.(!i) * base + m.(!i+1)) / (d.(0) + 1) in
  228. q.(!i) <- q.(!i) + v / base;
  229. sub_mult m d (v / base) !i;
  230. q.(!i+1) <- q.(!i+1) + v mod base;
  231. if q.(!i+1) >= base then
  232. (q.(!i+1) <- q.(!i+1)-base; q.(!i) <- q.(!i)+1);
  233. sub_mult m d (v mod base) (!i+1)
  234. end
  235. done;
  236. (normalize q, normalize m) in
  237. (if isnegd * isnegm = -1 then neg q else q),
  238. (if isnegm = -1 then neg r else r)
  239. (* Parsing/printing ordinary 10-based numbers *)
  240. let of_string s =
  241. let len = String.length s in
  242. let isneg = len > 1 & s.[0] = '-' in
  243. let d = ref (if isneg then 1 else 0) in
  244. while !d < len && s.[!d] = '0' do incr d done;
  245. if !d = len then zero else
  246. let r = (len - !d) mod size in
  247. let h = String.sub s (!d) r in
  248. let e = if h<>"" then 1 else 0 in
  249. let l = (len - !d) / size in
  250. let a = Array.create (l + e) 0 in
  251. if e=1 then a.(0) <- int_of_string h;
  252. for i=1 to l do
  253. a.(i+e-1) <- int_of_string (String.sub s ((i-1)*size + !d + r) size)
  254. done;
  255. if isneg then neg a else a
  256. let to_string_pos sgn n =
  257. if Array.length n = 0 then "0" else
  258. sgn ^
  259. String.concat ""
  260. (string_of_int n.(0) :: List.map format_size (List.tl (Array.to_list n)))
  261. let to_string n =
  262. if is_strictly_neg n then to_string_pos "-" (neg n)
  263. else to_string_pos "" n
  264. end
  265. (******************************************************************)
  266. (* Optimized operations on (unbounded) integer numbers *)
  267. (* integers smaller than base are represented as machine integers *)
  268. (******************************************************************)
  269. open ArrayInt
  270. type bigint = Obj.t
  271. (* Since base is the largest power of 10 such that base*base <= max_int,
  272. we have max_int < 100*base*base : any int can be represented
  273. by at most three blocs *)
  274. let small n = (-base <= n) && (n < base)
  275. let mkarray n =
  276. (* n isn't small, this case is handled separately below *)
  277. let lo = n mod base
  278. and hi = n / base in
  279. let t = if small hi then [|hi;lo|] else [|hi/base;hi mod base;lo|]
  280. in
  281. for i = Array.length t -1 downto 1 do
  282. if t.(i) < 0 then (t.(i) <- t.(i) + base; t.(i-1) <- t.(i-1) -1)
  283. done;
  284. t
  285. let ints_of_int n =
  286. if n = 0 then [| |]
  287. else if small n then [| n |]
  288. else mkarray n
  289. let of_int n =
  290. if small n then Obj.repr n else Obj.repr (mkarray n)
  291. let of_ints n =
  292. let n = normalize n in (* TODO: using normalize here seems redundant now *)
  293. if n = zero then Obj.repr 0 else
  294. if Array.length n = 1 then Obj.repr n.(0) else
  295. Obj.repr n
  296. let coerce_to_int = (Obj.magic : Obj.t -> int)
  297. let coerce_to_ints = (Obj.magic : Obj.t -> int array)
  298. let to_ints n =
  299. if Obj.is_int n then ints_of_int (coerce_to_int n)
  300. else coerce_to_ints n
  301. let int_of_ints =
  302. let maxi = mkarray max_int and mini = mkarray min_int in
  303. fun t ->
  304. let l = Array.length t in
  305. if (l > 3) || (l = 3 && (less_than maxi t || less_than t mini))
  306. then failwith "Bigint.to_int: too large";
  307. let sum = ref 0 in
  308. let pow = ref 1 in
  309. for i = l-1 downto 0 do
  310. sum := !sum + t.(i) * !pow;
  311. pow := !pow*base;
  312. done;
  313. !sum
  314. let to_int n =
  315. if Obj.is_int n then coerce_to_int n
  316. else int_of_ints (coerce_to_ints n)
  317. let app_pair f (m, n) =
  318. (f m, f n)
  319. let add m n =
  320. if Obj.is_int m & Obj.is_int n
  321. then of_int (coerce_to_int m + coerce_to_int n)
  322. else of_ints (add (to_ints m) (to_ints n))
  323. let sub m n =
  324. if Obj.is_int m & Obj.is_int n
  325. then of_int (coerce_to_int m - coerce_to_int n)
  326. else of_ints (sub (to_ints m) (to_ints n))
  327. let mult m n =
  328. if Obj.is_int m & Obj.is_int n
  329. then of_int (coerce_to_int m * coerce_to_int n)
  330. else of_ints (mult (to_ints m) (to_ints n))
  331. let euclid m n =
  332. if Obj.is_int m & Obj.is_int n
  333. then app_pair of_int
  334. (coerce_to_int m / coerce_to_int n, coerce_to_int m mod coerce_to_int n)
  335. else app_pair of_ints (euclid (to_ints m) (to_ints n))
  336. let less_than m n =
  337. if Obj.is_int m & Obj.is_int n
  338. then coerce_to_int m < coerce_to_int n
  339. else less_than (to_ints m) (to_ints n)
  340. let neg n =
  341. if Obj.is_int n then of_int (- (coerce_to_int n))
  342. else of_ints (neg (to_ints n))
  343. let of_string m = of_ints (of_string m)
  344. let to_string m = to_string (to_ints m)
  345. let zero = of_int 0
  346. let one = of_int 1
  347. let two = of_int 2
  348. let sub_1 n = sub n one
  349. let add_1 n = add n one
  350. let mult_2 n = add n n
  351. let div2_with_rest n =
  352. let (q,b) = euclid n two in
  353. (q, b = one)
  354. let is_strictly_neg n = is_strictly_neg (to_ints n)
  355. let is_strictly_pos n = is_strictly_pos (to_ints n)
  356. let is_neg_or_zero n = is_neg_or_zero (to_ints n)
  357. let is_pos_or_zero n = is_pos_or_zero (to_ints n)
  358. let equal m n = (m = n)
  359. (* spiwack: computes n^m *)
  360. (* The basic idea of the algorithm is that n^(2m) = (n^2)^m *)
  361. (* In practice the algorithm performs :
  362. k*n^0 = k
  363. k*n^(2m) = k*(n*n)^m
  364. k*n^(2m+1) = (n*k)*(n*n)^m *)
  365. let pow =
  366. let rec pow_aux odd_rest n m = (* odd_rest is the k from above *)
  367. if m<=0 then
  368. odd_rest
  369. else
  370. let quo = m lsr 1 (* i.e. m/2 *)
  371. and odd = (m land 1) <> 0 in
  372. pow_aux
  373. (if odd then mult n odd_rest else odd_rest)
  374. (mult n n)
  375. quo
  376. in
  377. pow_aux one
  378. (** Testing suite w.r.t. OCaml's Big_int *)
  379. (*
  380. module B = struct
  381. open Big_int
  382. let zero = zero_big_int
  383. let to_string = string_of_big_int
  384. let of_string = big_int_of_string
  385. let add = add_big_int
  386. let opp = minus_big_int
  387. let sub = sub_big_int
  388. let mul = mult_big_int
  389. let abs = abs_big_int
  390. let sign = sign_big_int
  391. let euclid n m =
  392. let n' = abs n and m' = abs m in
  393. let q',r' = quomod_big_int n' m' in
  394. (if sign (mul n m) < 0 && sign q' <> 0 then opp q' else q'),
  395. (if sign n < 0 then opp r' else r')
  396. end
  397. let check () =
  398. let roots = [ 1; 100; base; 100*base; base*base ] in
  399. let rands = [ 1234; 5678; 12345678; 987654321 ] in
  400. let nums = (List.flatten (List.map (fun x -> [x-1;x;x+1]) roots)) @ rands in
  401. let numbers =
  402. List.map string_of_int nums @
  403. List.map (fun n -> string_of_int (-n)) nums
  404. in
  405. let i = ref 0 in
  406. let compare op x y n n' =
  407. incr i;
  408. let s = Printf.sprintf "%30s" (to_string n) in
  409. let s' = Printf.sprintf "%30s" (B.to_string n') in
  410. if s <> s' then Printf.printf "%s%s%s: %s <> %s\n" x op y s s' in
  411. let test x y =
  412. let n = of_string x and m = of_string y in
  413. let n' = B.of_string x and m' = B.of_string y in
  414. let a = add n m and a' = B.add n' m' in
  415. let s = sub n m and s' = B.sub n' m' in
  416. let p = mult n m and p' = B.mul n' m' in
  417. let q,r = try euclid n m with Division_by_zero -> zero,zero
  418. and q',r' = try B.euclid n' m' with Division_by_zero -> B.zero, B.zero
  419. in
  420. compare "+" x y a a';
  421. compare "-" x y s s';
  422. compare "*" x y p p';
  423. compare "/" x y q q';
  424. compare "%" x y r r'
  425. in
  426. List.iter (fun a -> List.iter (test a) numbers) numbers;
  427. Printf.printf "%i tests done\n" !i
  428. *)