···5252let max_int = 0x7FFFFFFFl
5353let lognot n = logxor n (-1l)
54545555+let unsigned_to_int =
5656+ match Sys.word_size with
5757+ | 32 ->
5858+ let max_int = of_int Stdlib.max_int in
5959+ fun n ->
6060+ if compare zero n <= 0 && compare n max_int <= 0 then
6161+ Some (to_int n)
6262+ else
6363+ None
6464+ | 64 ->
6565+ (* So that it compiles in 32-bit *)
6666+ let move = int_of_string "0x1_0000_0000" in
6767+ fun n -> let i = to_int n in Some (if i < 0 then i + move else i)
6868+ | _ ->
6969+ assert false
7070+5571external format : string -> int32 -> string = "caml_int32_format"
5672let to_string n = format "%d" n
5773···66826783let compare (x: t) (y: t) = Stdlib.compare x y
6884let equal (x: t) (y: t) = compare x y = 0
8585+8686+let unsigned_compare n m =
8787+ compare (sub n min_int) (sub m min_int)
8888+8989+(* Unsigned division from signed division of the same
9090+ bitness. See Warren Jr., Henry S. (2013). Hacker's Delight (2 ed.), Sec 9-3.
9191+*)
9292+let unsigned_div n d =
9393+ if d < zero then
9494+ if unsigned_compare n d < 0 then zero else one
9595+ else
9696+ let q = shift_left (div (shift_right_logical n 1) d) 1 in
9797+ let r = sub n (mul q d) in
9898+ if unsigned_compare r d >= 0 then succ q else q
9999+100100+let unsigned_rem n d =
101101+ sub n (mul (unsigned_div n d) d)
+25
stdlib/int32.mli
···6060 argument is zero. This division rounds the real quotient of
6161 its arguments towards zero, as specified for {!Stdlib.(/)}. *)
62626363+val unsigned_div : int32 -> int32 -> int32
6464+(** Same as {!div}, except that arguments and result are interpreted as {e
6565+ unsigned} 32-bit integers.
6666+6767+ @since 4.08.0 *)
6868+6369external rem : int32 -> int32 -> int32 = "%int32_mod"
6470(** Integer remainder. If [y] is not zero, the result
6571 of [Int32.rem x y] satisfies the following property:
6672 [x = Int32.add (Int32.mul (Int32.div x y) y) (Int32.rem x y)].
6773 If [y = 0], [Int32.rem x y] raises [Division_by_zero]. *)
7474+7575+val unsigned_rem : int32 -> int32 -> int32
7676+(** Same as {!rem}, except that arguments and result are interpreted as {e
7777+ unsigned} 32-bit integers.
7878+7979+ @since 4.08.0 *)
68806981val succ : int32 -> int32
7082(** Successor. [Int32.succ x] is [Int32.add x Int32.one]. *)
···121133 during the conversion. On 64-bit platforms, the conversion
122134 is exact. *)
123135136136+val unsigned_to_int : int32 -> int option
137137+(** Same as {!to_int}, but interprets the argument as an {e unsigned} integer.
138138+ Returns [None] if the unsigned value of the argument cannot fit into an
139139+ [int].
140140+141141+ @since 4.08.0 *)
142142+124143external of_float : float -> int32
125144 = "caml_int32_of_float" "caml_int32_of_float_unboxed"
126145 [@@unboxed] [@@noalloc]
···183202 {!Stdlib.compare}. Along with the type [t], this function [compare]
184203 allows the module [Int32] to be passed as argument to the functors
185204 {!Set.Make} and {!Map.Make}. *)
205205+206206+val unsigned_compare: t -> t -> int
207207+(** Same as {!compare}, except that arguments are interpreted as {e unsigned}
208208+ 32-bit integers.
209209+210210+ @since 4.08.0 *)
186211187212val equal: t -> t -> bool
188213(** The equal function for int32s.
+25
stdlib/int64.ml
···5050let max_int = 0x7FFFFFFFFFFFFFFFL
5151let lognot n = logxor n (-1L)
52525353+let unsigned_to_int =
5454+ let max_int = of_int Stdlib.max_int in
5555+ fun n ->
5656+ if compare zero n <= 0 && compare n max_int <= 0 then
5757+ Some (to_int n)
5858+ else
5959+ None
6060+5361external format : string -> int64 -> string = "caml_int64_format"
5462let to_string n = format "%d" n
5563···73817482let compare (x: t) (y: t) = Stdlib.compare x y
7583let equal (x: t) (y: t) = compare x y = 0
8484+8585+let unsigned_compare n m =
8686+ compare (sub n min_int) (sub m min_int)
8787+8888+(* Unsigned division from signed division of the same
8989+ bitness. See Warren Jr., Henry S. (2013). Hacker's Delight (2 ed.), Sec 9-3.
9090+*)
9191+let unsigned_div n d =
9292+ if d < zero then
9393+ if unsigned_compare n d < 0 then zero else one
9494+ else
9595+ let q = shift_left (div (shift_right_logical n 1) d) 1 in
9696+ let r = sub n (mul q d) in
9797+ if unsigned_compare r d >= 0 then succ q else q
9898+9999+let unsigned_rem n d =
100100+ sub n (mul (unsigned_div n d) d)
+25
stdlib/int64.mli
···6060 argument is zero. This division rounds the real quotient of
6161 its arguments towards zero, as specified for {!Stdlib.(/)}. *)
62626363+val unsigned_div : int64 -> int64 -> int64
6464+(** Same as {!div}, except that arguments and result are interpreted as {e
6565+ unsigned} 64-bit integers.
6666+6767+ @since 4.08.0 *)
6868+6369external rem : int64 -> int64 -> int64 = "%int64_mod"
6470(** Integer remainder. If [y] is not zero, the result
6571 of [Int64.rem x y] satisfies the following property:
6672 [x = Int64.add (Int64.mul (Int64.div x y) y) (Int64.rem x y)].
6773 If [y = 0], [Int64.rem x y] raises [Division_by_zero]. *)
7474+7575+val unsigned_rem : int64 -> int64 -> int64
7676+(** Same as {!rem}, except that arguments and result are interpreted as {e
7777+ unsigned} 64-bit integers.
7878+7979+ @since 4.08.0 *)
68806981val succ : int64 -> int64
7082(** Successor. [Int64.succ x] is [Int64.add x Int64.one]. *)
···121133 is taken modulo 2{^31}, i.e. the top 33 bits are lost
122134 during the conversion. *)
123135136136+val unsigned_to_int : int64 -> int option
137137+(** Same as {!to_int}, but interprets the argument as an {e unsigned} integer.
138138+ Returns [None] if the unsigned value of the argument cannot fit into an
139139+ [int].
140140+141141+ @since 4.08.0 *)
142142+124143external of_float : float -> int64
125144 = "caml_int64_of_float" "caml_int64_of_float_unboxed"
126145 [@@unboxed] [@@noalloc]
···203222 {!Stdlib.compare}. Along with the type [t], this function [compare]
204223 allows the module [Int64] to be passed as argument to the functors
205224 {!Set.Make} and {!Map.Make}. *)
225225+226226+val unsigned_compare: t -> t -> int
227227+(** Same as {!compare}, except that arguments are interpreted as {e unsigned}
228228+ 64-bit integers.
229229+230230+ @since 4.08.0 *)
206231207232val equal: t -> t -> bool
208233(** The equal function for int64s.
+25
stdlib/nativeint.ml
···4949let max_int = sub min_int 1n
5050let lognot n = logxor n (-1n)
51515252+let unsigned_to_int =
5353+ let max_int = of_int Stdlib.max_int in
5454+ fun n ->
5555+ if compare zero n <= 0 && compare n max_int <= 0 then
5656+ Some (to_int n)
5757+ else
5858+ None
5959+5260external format : string -> nativeint -> string = "caml_nativeint_format"
5361let to_string n = format "%d" n
5462···63716472let compare (x: t) (y: t) = Stdlib.compare x y
6573let equal (x: t) (y: t) = compare x y = 0
7474+7575+let unsigned_compare n m =
7676+ compare (sub n min_int) (sub m min_int)
7777+7878+(* Unsigned division from signed division of the same
7979+ bitness. See Warren Jr., Henry S. (2013). Hacker's Delight (2 ed.), Sec 9-3.
8080+*)
8181+let unsigned_div n d =
8282+ if d < zero then
8383+ if unsigned_compare n d < 0 then zero else one
8484+ else
8585+ let q = shift_left (div (shift_right_logical n 1) d) 1 in
8686+ let r = sub n (mul q d) in
8787+ if unsigned_compare r d >= 0 then succ q else q
8888+8989+let unsigned_rem n d =
9090+ sub n (mul (unsigned_div n d) d)
+25
stdlib/nativeint.mli
···6363 argument is zero. This division rounds the real quotient of
6464 its arguments towards zero, as specified for {!Stdlib.(/)}. *)
65656666+val unsigned_div : nativeint -> nativeint -> nativeint
6767+(** Same as {!div}, except that arguments and result are interpreted as {e
6868+ unsigned} native integers.
6969+7070+ @since 4.08.0 *)
7171+6672external rem : nativeint -> nativeint -> nativeint = "%nativeint_mod"
6773(** Integer remainder. If [y] is not zero, the result
6874 of [Nativeint.rem x y] satisfies the following properties:
···7076 [x = Nativeint.add (Nativeint.mul (Nativeint.div x y) y)
7177 (Nativeint.rem x y)].
7278 If [y = 0], [Nativeint.rem x y] raises [Division_by_zero]. *)
7979+8080+val unsigned_rem : nativeint -> nativeint -> nativeint
8181+(** Same as {!rem}, except that arguments and result are interpreted as {e
8282+ unsigned} native integers.
8383+8484+ @since 4.08.0 *)
73857486val succ : nativeint -> nativeint
7587(** Successor.
···138150 integer (type [int]). The high-order bit is lost during
139151 the conversion. *)
140152153153+val unsigned_to_int : nativeint -> int option
154154+(** Same as {!to_int}, but interprets the argument as an {e unsigned} integer.
155155+ Returns [None] if the unsigned value of the argument cannot fit into an
156156+ [int].
157157+158158+ @since 4.08.0 *)
159159+141160external of_float : float -> nativeint
142161 = "caml_nativeint_of_float" "caml_nativeint_of_float_unboxed"
143162 [@@unboxed] [@@noalloc]
···193212 {!Stdlib.compare}. Along with the type [t], this function [compare]
194213 allows the module [Nativeint] to be passed as argument to the functors
195214 {!Set.Make} and {!Map.Make}. *)
215215+216216+val unsigned_compare: t -> t -> int
217217+(** Same as {!compare}, except that arguments are interpreted as {e unsigned}
218218+ native integers.
219219+220220+ @since 4.08.0 *)
196221197222val equal: t -> t -> bool
198223(** The equal function for native ints.
+86-18
testsuite/tests/basic/boxedints.ml
···3535 val sub: t -> t -> t
3636 val mul: t -> t -> t
3737 val div: t -> t -> t
3838+ val unsigned_div: t -> t -> t
3839 val rem: t -> t -> t
3940 val logand: t -> t -> t
4041 val logor: t -> t -> t
···4445 val shift_right_logical: t -> int -> t
4546 val of_int: int -> t
4647 val to_int: t -> int
4848+ val unsigned_to_int: t -> int option
4749 val of_float: float -> t
4850 val to_float: t -> float
4951 val zero: t
···5557 val to_string: t -> string
5658 val of_string: string -> t
5759 end
5858- val testcomp: t -> t -> bool*bool*bool*bool*bool*bool*int
6060+ val testcomp: t -> t -> bool*bool*bool*bool*bool*bool*int*int
5961 val skip_float_tests: bool
6062end
6163···7274 test 4 (to_int (of_int 0x3FFFFFFF)) 0x3FFFFFFF;
7375 test 5 (to_int (of_int (-0x40000000))) (-0x40000000);
74767777+ testing_function "unsigned_to_int";
7878+ test 1 (unsigned_to_int (of_int 0)) (Some 0);
7979+ test 2 (unsigned_to_int (of_int 123)) (Some 123);
8080+ test 3 (unsigned_to_int minus_one)
8181+ (match Sys.word_size with
8282+ | 32 -> None
8383+ | 64 -> Some (int_of_string "0xFFFFFFFF")
8484+ | _ -> assert false);
8585+ test 4 (unsigned_to_int max_int)
8686+ (match Sys.word_size with
8787+ | 32 -> None
8888+ | 64 -> Some (to_int max_int)
8989+ | _ -> assert false);
9090+ test 5 (unsigned_to_int min_int)
9191+ (match Sys.word_size with
9292+ | 32 -> None
9393+ | 64 -> Some (int_of_string "0x80000000")
9494+ | _ -> assert false);
9595+ test 6 (unsigned_to_int (of_int Stdlib.max_int))
9696+ (match Sys.word_size with
9797+ | 32 -> Some Stdlib.max_int
9898+ | 64 -> Some (int_of_string "0xFFFFFFFF")
9999+ | _ -> assert false);
100100+75101 testing_function "of_string";
76102 test 1 (of_string "0") (of_int 0);
77103 test 2 (of_string "123") (of_int 123);
···170196 11, 1234567, -12345678];
171197 test 12 (div min_int (of_int (-1))) min_int;
172198199199+ testing_function "unsigned_div";
200200+ List.iter
201201+ (fun (n, a, b, c) -> test n (unsigned_div a b) c)
202202+ [1, of_int 0, of_int 2, of_int 0;
203203+ 2, of_int 123, of_int 1, of_int 123;
204204+ 3, of_int (-123), of_int 1, of_int (-123);
205205+ 4, of_int (123), of_int (-1), of_int 0;
206206+ 5, of_int (-123), of_int (-1), of_int 0;
207207+ 6, of_int 127531236, of_int 365, of_int (127531236/365);
208208+ 7, of_int 16384, of_int 256, of_int (16384/256);
209209+ 8, of_int (-1), of_int 2, max_int;
210210+ 9, of_int (-1), max_int, of_int 2;
211211+ 10, min_int, of_int 2, shift_left (of_int 1) 30;
212212+ 11, of_int (-1), of_int 8, shift_right_logical (of_int (-1)) 3];
213213+173214 testing_function "mod";
174215 List.iter
175216 (fun (n, a, b) -> test n (rem (of_int a) (of_int b)) (of_int (a mod b)))
···271312272313 testing_function "Comparisons";
273314 test 1 (testcomp (of_int 0) (of_int 0))
274274- (true,false,false,false,true,true,0);
315315+ (true,false,false,false,true,true,0,0);
275316 test 2 (testcomp (of_int 1234567) (of_int 1234567))
276276- (true,false,false,false,true,true,0);
317317+ (true,false,false,false,true,true,0, 0);
277318 test 3 (testcomp (of_int 0) (of_int 1))
278278- (false,true,true,false,true,false,-1);
319319+ (false,true,true,false,true,false,-1,-1);
279320 test 4 (testcomp (of_int (-1)) (of_int 0))
280280- (false,true,true,false,true,false,-1);
321321+ (false,true,true,false,true,false,-1,1);
281322 test 5 (testcomp (of_int 1) (of_int 0))
282282- (false,true,false,true,false,true,1);
323323+ (false,true,false,true,false,true,1,1);
283324 test 6 (testcomp (of_int 0) (of_int (-1)))
284284- (false,true,false,true,false,true,1);
325325+ (false,true,false,true,false,true,1,-1);
285326 test 7 (testcomp max_int min_int)
286286- (false,true,false,true,false,true,1);
327327+ (false,true,false,true,false,true,1,-1);
287328288329 ()
289330end
···302343 test 3 (to_int (of_int (-456))) (-456);
303344 test 4 (to_int (of_int 0x3FFFFFFF)) 0x3FFFFFFF;
304345 test 5 (to_int (of_int (-0x40000000))) (-0x40000000);
346346+347347+ testing_function "unsigned_to_int";
348348+ test 1 (unsigned_to_int (of_int 0)) (Some 0);
349349+ test 2 (unsigned_to_int (of_int 123)) (Some 123);
350350+ test 3 (unsigned_to_int minus_one) None;
351351+ test 4 (unsigned_to_int max_int) None;
352352+ test 5 (unsigned_to_int min_int) None;
353353+ test 6 (unsigned_to_int (of_int Stdlib.max_int))
354354+ (Some Stdlib.max_int);
305355306356 testing_function "of_string";
307357 test 1 (of_string "0") (of_int 0);
···406456 11, 1234567, -12345678];
407457 test 12 (div min_int (of_int (-1))) min_int;
408458459459+ testing_function "unsigned_div";
460460+ List.iter
461461+ (fun (n, a, b, c) -> test n (unsigned_div a b) c)
462462+ [1, of_int 0, of_int 2, of_int 0;
463463+ 2, of_int 123, of_int 1, of_int 123;
464464+ 3, of_int (-123), of_int 1, of_int (-123);
465465+ 4, of_int (123), of_int (-1), of_int 0;
466466+ 5, of_int (-123), of_int (-1), of_int 0;
467467+ 6, of_int 127531236, of_int 365, of_int (127531236/365);
468468+ 7, of_int 16384, of_int 256, of_int (16384/256);
469469+ 8, of_int (-1), of_int 2, max_int;
470470+ 9, of_int (-1), max_int, of_int 2;
471471+ 10, min_int, of_int 2, shift_left (of_int 1) 62;
472472+ 11, of_int (-1), of_int 8, shift_right_logical (of_int (-1)) 3];
473473+409474 testing_function "mod";
410475 List.iter
411476 (fun (n, a, b) -> test n (rem (of_int a) (of_int b)) (of_int (a mod b)))
···489554490555 testing_function "Comparisons";
491556 test 1 (testcomp (of_int 0) (of_int 0))
492492- (true,false,false,false,true,true,0);
557557+ (true,false,false,false,true,true,0,0);
493558 test 2 (testcomp (of_int 1234567) (of_int 1234567))
494494- (true,false,false,false,true,true,0);
559559+ (true,false,false,false,true,true,0,0);
495560 test 3 (testcomp (of_int 0) (of_int 1))
496496- (false,true,true,false,true,false,-1);
561561+ (false,true,true,false,true,false,-1,-1);
497562 test 4 (testcomp (of_int (-1)) (of_int 0))
498498- (false,true,true,false,true,false,-1);
563563+ (false,true,true,false,true,false,-1,1);
499564 test 5 (testcomp (of_int 1) (of_int 0))
500500- (false,true,false,true,false,true,1);
565565+ (false,true,false,true,false,true,1,1);
501566 test 6 (testcomp (of_int 0) (of_int (-1)))
502502- (false,true,false,true,false,true,1);
567567+ (false,true,false,true,false,true,1,-1);
503568 test 7 (testcomp max_int min_int)
504504- (false,true,false,true,false,true,1);
569569+ (false,true,false,true,false,true,1,-1);
505570506571 ()
507572end
···509574(******** The test proper **********)
510575511576let testcomp_int32 (a : int32) (b : int32) =
512512- (a = b, a <> b, a < b, a > b, a <= b, a >= b, compare a b)
577577+ (a = b, a <> b, a < b, a > b, a <= b, a >= b, compare a b,
578578+ Int32.unsigned_compare a b)
513579let testcomp_int64 (a : int64) (b : int64) =
514514- (a = b, a <> b, a < b, a > b, a <= b, a >= b, compare a b)
580580+ (a = b, a <> b, a < b, a > b, a <= b, a >= b, compare a b,
581581+ Int64.unsigned_compare a b)
515582let testcomp_nativeint (a : nativeint) (b : nativeint) =
516516- (a = b, a <> b, a < b, a > b, a <= b, a >= b, compare a b)
583583+ (a = b, a <> b, a < b, a > b, a <= b, a >= b, compare a b,
584584+ Nativeint.unsigned_compare a b)
517585518586let _ =
519587 testing_function "-------- Int32 --------";
···2828 val sub : t -> t -> t
2929 val mul : t -> t -> t
3030 val div : t -> t -> t
3131+ val unsigned_div : t -> t -> t
3132 val rem : t -> t -> t
3333+ val unsigned_rem : t -> t -> t
3234 val succ : t -> t
3335 val pred : t -> t
3436 val abs : t -> t
···5355 val of_string : string -> t
5456 val to_string : t -> string
5557 val compare: t -> t -> int
5858+ val unsigned_compare : t -> t -> int
5659 val equal: t -> t -> bool
5760 val repr: t -> repr
5861 val print : Format.formatter -> t -> unit
+12
utils/targetint.mli
···5858 argument is zero. This division rounds the real quotient of
5959 its arguments towards zero, as specified for {!Stdlib.(/)}. *)
60606161+val unsigned_div : t -> t -> t
6262+(** Same as {!div}, except that arguments and result are interpreted as {e
6363+ unsigned} 32-bit integers. *)
6464+6165val rem : t -> t -> t
6266(** Integer remainder. If [y] is not zero, the result
6367 of [Targetint.rem x y] satisfies the following properties:
···6569 [x = Targetint.add (Targetint.mul (Targetint.div x y) y)
6670 (Targetint.rem x y)].
6771 If [y = 0], [Targetint.rem x y] raises [Division_by_zero]. *)
7272+7373+val unsigned_rem : t -> t -> t
7474+(** Same as {!rem}, except that arguments and result are interpreted as {e
7575+ unsigned} integers. *)
68766977val succ : t -> t
7078(** Successor.
···180188 {!Stdlib.compare}. Along with the type [t], this function [compare]
181189 allows the module [Targetint] to be passed as argument to the functors
182190 {!Set.Make} and {!Map.Make}. *)
191191+192192+val unsigned_compare: t -> t -> int
193193+(** Same as {!compare}, except that arguments are interpreted as {e unsigned}
194194+ integers. *)
183195184196val equal: t -> t -> bool
185197(** The equal function for target ints. *)