-
Notifications
You must be signed in to change notification settings - Fork 16
/
number.ml
180 lines (150 loc) · 5.24 KB
/
number.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
(***********************************************************************)
(* number.ml - Basic operations and definitions for multi-precision *)
(* integers *)
(* *)
(* Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, *)
(* 2011, 2012, 2013 Yaron Minsky and Contributors *)
(* *)
(* This file is part of SKS. SKS is free software; you can *)
(* redistribute it and/or modify it under the terms of the GNU General *)
(* Public License as published by the Free Software Foundation; either *)
(* version 2 of the License, or (at your option) any later version. *)
(* *)
(* This program is distributed in the hope that it will be useful, but *)
(* WITHOUT ANY WARRANTY; without even the implied warranty of *)
(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *)
(* General Public License for more details. *)
(* *)
(* You should have received a copy of the GNU General Public License *)
(* along with this program; if not, write to the Free Software *)
(* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *)
(* USA or see <http://www.gnu.org/licenses/>. *)
(***********************************************************************)
open Big_int
open Bytes
open MoreLabels
open Printf
open Common
type z = Big_int.big_int
module Infix =
struct
let two = big_int_of_int 2
let one = unit_big_int
let zero = zero_big_int
let neg_one = big_int_of_int (-1)
let ( *! ) = mult_big_int
let ( +! ) = add_big_int
let ( -! ) = sub_big_int
let ( %! ) = mod_big_int
let ( /! ) = div_big_int
let ( **! ) = power_big_int_positive_int
let ( <>! ) x y = not (eq_big_int x y)
let ( =! ) = eq_big_int
let ( <! ) = lt_big_int
let ( >! ) = gt_big_int
let ( <=! ) = le_big_int
let ( >=! ) = ge_big_int
end
open Infix
let int_mult = mult_int_big_int
let int_posint_power = power_int_positive_int
let width = 8
let width_pow = power_int_positive_int 2 width
let revstring s =
let len = String.length s in
let copy = Bytes.create len in
for i = 0 to len - 1 do
Bytes.set copy i s.[len - 1 - i]
done;
Bytes.unsafe_to_string copy
let revstring_inplace s =
let len = Bytes.length s in
for i = 0 to (len - 2)/2 do
let j = len - 1 - i in
let tmp = Bytes.unsafe_get s i in
Bytes.set s i (Bytes.unsafe_get s j);
Bytes.set s j tmp
done
let to_bytes ~nbytes n =
if sign_big_int n = -1
then raise (Invalid_argument "N.to_bytes: negative argument");
let string = Bytes.create nbytes in
let rec loop n i =
if i < 0 then string
else
let (a,b) = quomod_big_int n width_pow in
Bytes.set string i (char_of_int (int_of_big_int b));
loop a (i - 1)
in
let str = loop n (nbytes - 1) in
revstring_inplace str;
Bytes.unsafe_to_string str
let of_bytes str =
let str = revstring str in
let nbytes = String.length str in
let rec loop n i =
if i >= nbytes then n
else
let m = big_int_of_int (int_of_char str.[i]) in
loop (n *! width_pow +! m) (i+1)
in
loop zero 0
open Big_int
open Nat
let nbits_slow x =
let rec loop i two_to_i =
if two_to_i >! x then i
else loop (succ i) (two *! two_to_i)
in
if x =! zero then 1 else loop 1 two
let nbits_less_slow x =
let nwords = num_digits_big_int x in
let wsize = Sys.word_size in
let lowbits = (nwords - 1) * wsize in
let lastword = x /! two **! lowbits in
nbits_slow lastword + (nwords - 1) * wsize
(** returns the number of bits required to represent the number, i.e.,
the index (starting from 1) of the most significant non-zero bit *)
let nbits x =
let nat = nat_of_big_int (abs_big_int x) in
let nwords = num_digits_nat nat 0 (length_nat nat) in
Sys.word_size * nwords - num_leading_zero_bits_in_digit nat (nwords - 1)
let nth_bit x n =
one =! ( x /! (two **! n)) %! two
let print_bits x =
for i = nbits x - 1 downto 0 do
if nth_bit x i then print_string "1" else print_string "0"
done
let squaremod x m =
(x *! x) %! m
let rec powmod x y m =
if y =! zero then one
else
let base = squaremod (powmod x ( y /! two) m) m in
if y %! two =! zero then base
else (base *! x) %! m
let dumb_powmod x y m =
(x **! int_of_big_int y) %! m
let rec gcd_ex' a b =
if b =! zero then (one,zero,a)
else
let (q,r) = quomod_big_int a b in
let (u',v',gcd) = gcd_ex' b r in
(v',u' -! v' *! q, gcd)
let gcd_ex a b =
if b <=! a then gcd_ex' a b
else
let (u,v,gcd) = gcd_ex' b a in
(v,u,gcd)
let gcd_ex_test a b =
let (a,b) = (big_int_of_int a,big_int_of_int b) in
let (u,v,gcd) = gcd_ex a b in
if (u *! a +! v *! b <>! gcd)
then failwith (sprintf "gcd_ex failed on %s and %s"
(string_of_big_int a) (string_of_big_int b))
(** conversion functions *)
let of_int = big_int_of_int
let to_int = int_of_big_int
let to_string = string_of_big_int
let of_string = big_int_of_string
let compare = compare_big_int