/
batInt.ml
173 lines (132 loc) · 4.88 KB
/
batInt.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
(*
* ExtInt - Extended integers
* Copyright (C) 2007 Bluestorm <bluestorm dot dylc on-the-server gmail dot com>
* 2008 David Teller
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version,
* with the special exception on linking described in file LICENSE.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*)
open BatNumber
let enum () =
let current_value = ref min_int in
let already_through = ref false in
let f () =
if !current_value = max_int then
if !already_through then raise BatEnum.No_more_elements
else ( already_through := true; max_int )
else BatRef.post_incr current_value
in BatEnum.from f
module BaseInt = struct
type t = int
let zero, one = 0, 1
external neg : int -> int = "%negint"
external add : int -> int -> int = "%addint"
external sub : int -> int -> int = "%subint"
external mul : int -> int -> int = "%mulint"
external div : int -> int -> int = "%divint"
external ( + ) : int -> int -> int = "%addint"
external ( - ) : int -> int -> int = "%subint"
external ( * ) : int -> int -> int = "%mulint"
external ( / ) : int -> int -> int = "%divint"
external pred: int -> int = "%predint"
external succ: int -> int = "%succint"
let abs = abs
external modulo : int -> int -> int = "%modint"
let pow = generic_pow ~zero ~one ~div_two:(fun n -> n / 2) ~mod_two:(fun n -> n mod 2) ~mul
let min_num, max_num = min_int, max_int
let compare x y = if x > y then 1 else if y > x then -1 else 0
external of_int : int -> int = "%identity"
external to_int : int -> int = "%identity"
let of_string x =
try int_of_string x
with Failure "int_of_string" -> raise (Invalid_argument "int_of_string")
let to_string = string_of_int
let enum = enum
let minus_one = ( - 1)
external to_float : int -> float = "%floatofint"
external of_float : float -> int = "%intoffloat"
external of_string : string -> int = "caml_int_of_string"
external rem : int -> int -> int = "%modint"
let ( <> ) a b = a <> b
let ( <= ) a b = a <= b
let ( >= ) a b = a >= b
let ( < ) a b = a < b
let ( > ) a b = a > b
let ( = ) a b = a = b
let ( ** ) a b = pow a b
let print out t = BatInnerIO.nwrite out (string_of_int t)
let xprint out t = BatInnerIO.Printf.fprintf out "%X" t
let t_printer paren out t = print out t
let ( -- ) x y = BatEnum.seq x (add one) ((>=) y)
let ( --- ) x y =
if x <= y then x -- y
else BatEnum.seq x pred ((<=) y)
end
include BaseInt
module N = BatNumber.MakeNumeric(BaseInt)
let operations = N.operations
module BaseSafeInt = struct
include BaseInt
(**
Open this module and [SafeInt] to replace traditional integer operators with
their safe counterparts
*)
let add a b =
let c = Pervasives.( + ) a b in
if a < 0 && b < 0 && c >= 0 || a > 0 && b > 0 && c <= 0 then raise Overflow
else c
let ( + ) = add
let sub a b =
let c = Pervasives.( - ) a b in
if a < 0 && b > 0 && c >= 0 || a > 0 && b < 0 && c <= 0 then raise Overflow
else c
let ( - ) a b = sub a b
let neg x =
if x <> min_int then ~- x
else raise Overflow
let succ x =
if x <> max_int then succ x
else raise Overflow
let pred x =
if x <> min_int then pred x
else raise Overflow
let abs x =
if x <> min_int then abs x
else raise Overflow
(*This function used to assume that in case of overflow the result would be
different when computing in 31 bits (resp 63 bits) and in 32 bits (resp 64
bits). This trick turned out to be *wrong* on 64-bit machines, where
[Nativeint.mul 2432902008176640000n 21n] and [2432902008176640000 * 21]
yield the same result, [-4249290049419214848]. *)
let mul a b =
if b = 0 then 0
else if (abs a) > max_int / (abs b) then raise Overflow else a * b
let ( * ) = mul
let pow = BatNumber.generic_pow ~zero ~one ~div_two:(fun n -> n/2) ~mod_two:(fun n -> n mod 2) ~mul
end
module Safe_int = struct
include BaseSafeInt
let operations = let module N = BatNumber.MakeNumeric(BaseSafeInt) in N.operations
end
(*
module Int = struct
include BaseInt
module Numeric = struct include Numeric(BaseInt) end
end
module SafeInt = struct
include BaseSafeInt
module Numeric = struct include Numeric(BaseSafeInt) end
end
*)