Library
Module
Module type
Parameter
Class
Class type
Arithmetic on overflowing integers.
All operations defined here act on overflowing integers. An overflowing integer is any native integer (type int
) except Stdlib.min_int
. Otherwise said, it is an integer whose absolute value is at most max_int
= 2int_size
−1 − 1, implying that the minimum value is min_int
= −max_int
= −2int_size
−1 + 1 = Stdlib.min_int
+1 (!). This makes the range of overflowing integers symmetrical, so that computing the opposite ( ~- )
or the absolute value abs
never overflows (the presence of an additional value 2int_size
−1 being arbitrarily interpreted as a negative value fits the modulo semantics of integers, but is alien to an overflowing semantics).
Incidentally, this allows to use Stdlib.min_int
as a special value, for example to signal that an overflow occurred. However in this library we rather raise an exception for that purpose. All functions in this library may fail when given Stdlib.min_int
where an overflowing integer was expected.
All operations defined here either are free of overflows, or raise Overflow
when their result would exceed the range of overflowing integers (and only in that case). Functions which can overflow are signaled explicitly in this documentation.
Functions in this library may raise Assert_failure
, instead of the more traditional Invalid_argument
, when some precondition is not met. This is not necessarily signaled in this documentation, but all preconditions are stated in the English description of functions. However, we still treat division‐by‐zero differently than other preconditions; for that we raise Division_by_zero
, and signal it in this documentation.
As much as possible, time and space complexities are indicated (time complexities are termed as a count of machine-arithmetic operations). If absent, constant time or constant space is implied.
By opening it, this module can mostly be used as a drop-in replacement for Stdlib arithmetic operations. This allows lightweight notations and avoids accidental uses of overflow-unsafe Stdlib operations. Beware of the following changes:
min_int
has a different value (as explained);min
, max
and compare
are monomorphic functions for type int
, instead of polymorphic functions;(**)
is redefined as the integer exponentation (the floating-point exponentiation is available as (**.)
);(/)
is restricted to an exact division (a possibly-rounded division is available as (//)
, which differs from Stdlib.(/)
in that it does an Euclidean division);(mod)
is redefined as the Euclidean remainder.The smallest representable integer. This is the opposite of max_int
, and differs from Stdlib.min_int
.
Raised when an operation was expected to perform an exact division but the dividend was not a multiple of the divisor.
mul_sign0 s n
is n
if s
is positive, 0 if it is null, and −n
if it is negative. In other words, it is equivalent to mul (sign s) a
, but much faster.
compare a b
returns 0
when a
is equal to b
, a negative integer when a
is smaller than b
, and a positive integer when a
is greater than b
. It is the same as Stdlib.compare
but much faster.
val sum_of_seq : int Seq.t -> int
Overflowing integer summation. Unlike a naive iteration of add
, this succeeds as long as the result is representable, even when partial sums overflow. Beware that the input sequence is read twice. If that is undesirable, use Seq.memoize
(OCaml 4.14). Complexity: time 𝒪(n), space 𝒪(1) where n is the length of the sequence.
Same as sum_of_seq
but where the input sequence is a list.
val prod_of_seq : int Seq.t -> int
Overflowing n-ary multiplication. Unlike a naive iteration of mul
, this succeeds as long as the result is representable even when partial products overflow (this situation only happens when one of the operands is zero). Every operand is read at most once; when an operand is zero, following operands are not read. Complexity: time 𝒪(n), space 𝒪(1) where n is the length of the sequence.
Same as prod_of_seq
but where the input sequence is a list.
Exact integer division. By contrast with Stdlib.(/)
, it cannot overflow.
sdiv a b
is the “signed” division of a
by b
; it returns (q, r)
such that a
= b
×q
+ r
and |r
| < |a
| and r
is of the same sign as a
.
This is the standard library’s division. However, using sdiv
is better than computing both Stdlib.(a / b)
and Stdlib.(a mod b)
separately, because sdiv
spares one machine division, which is much more costly than a multiplication.
sdiv
is slightly faster than ediv
, so it is also useful when we don’t need the remainder to be positive or when we know that a
≥ 0.
ediv a b
is the Euclidean division of a
by b
; it returns (q, r)
such that a
= b
×q
+ r
and 0 ≤ r
< b
. By contrast with sdiv
, the remainder is never negative.
Faster alternatives when the divisor is 2.
Faster alternatives when the divisor is a power of 2. ediv_pow2 a k
is equivalent to ediv a (pow2 k)
.
mul_div_exact a b c
computes a
×b
∕c
when c
does divide a
×b
.
mul_ediv a b c
computes the Euclidean division of a
×b
by c
, even when the intermediate product would overflow.
mul_equo a b c
is the quotient of the Euclidean division of a
×b
by c
.
mul_erem a b c
is the remainder of the Euclidean division of a
×b
by c
. It cannot overflow.
If you are interested in modular arithmetic, see also Modular.mul
.
Overflowing integer exponentiation. pow a n
is a
to the power n
, provided that n
is non‐negative. Of course, 00 = 1. Complexity: 𝒪(log(n
)) integer multiplications.
powm1 n
is equivalent to pow (-1) (abs n)
, but much faster. n
may be negative. Complexity: 𝒪(1).
ilog ~base n
is the logarithm of n
in base base
rounded towards zero, provided that base
is at least 2 and that n
is non‐negative. In other words, it returns ⌊ln(n
)∕ln(base
)⌋, This is the unique integer k
such that base
k
≤ n
< base
k
+1. This is a relatively slow operation in general, but it is specially optimized for bases 2, 16, 64, 10 and 60. The default base is 10. Complexity: 𝒪(log(log(n
))) integer multiplications.
ilogsup ~base n
is the number of digits of n
in base base
, provided that base
is at least 2 and that n
is non‐negative. It is equal to ⌈ln(n
+1)∕ln(base
)⌉ and also (when n
is not null) to ⌊ln(n
)∕ln(base
)⌋ + 1. This is the unique integer k
such that base
k
−1 ≤ n
< base
k
. As for ilog
, this is relatively slow but it is fast for bases 2, 16, 64, 10 and 60. The default base is 10. Complexity: 𝒪(log(log(n
))) integer multiplications.
is_pow ~base ~exp n
is true if and only if n
= base
exp
. When exp
is omitted, is_kth_pow ~base n
says whether n
is some power of base
. When exp
is provided, it is equivalent to is_kth_pow
~k:exp ~root:base n
. The default base is 10.
kth_root ~k n
is the integer k
th root of n
, rounded towards zero. In other words, it is sign n × r
where r
is the greatest integer such that r
k
≤ |n
|. k
must be positive. If k
is even, n
must be non-negative.
isqrt n
is the integer square root of n
, provided that n
is non‐negative. In other words, it is the greatest integer r
such that r
² ≤ n
, that is, ⌊√n
⌋. It is equivalent to kth_root ~k:2 n
but should be faster.
icbrt n
is the integer cube root of n
, rounded towards zero. In other words, it is sign n × r
where r
is the greatest integer such that r
³ ≤ |n
|. It is equivalent to kth_root ~k:3 n
but may be faster.
is_kth_pow ~k ~root n
is true if and only if n
= root
k
. When root
is omitted, is_kth_pow n
says whether n
is a k
th power. When root
is provided, it is equivalent to is_pow
~base:root ~exp:k n
.
is_square ~root n
is true if and only if n
is the square of root
. When root
is omitted, is_square n
says whether n
is a perfect square. It is equivalent to is_kth_pow ~k:2 ~root n
but faster.
is_multiple ~of_:a b
is true
iff b
is a multiple of a
. This function never raises Division_by_zero
, but returns true
when a
= 0 and b
= 0.
gcd a b
is the positive greatest common divisor of a
and b
. Complexity: 𝒪(log(min(|a
|,|b
|))) integer divisions.
val gcd_of_seq : int Seq.t -> int
The positive greatest common divisor of a sequence of numbers. Complexity: 𝒪(n × log(m)) integer divisions where n is the length of the sequence and m is its maximum element.
gcdext a b
is the extended Euclidean algorithm; it returns (d, u, v)
where d
is the positive greatest common divisor of a
and b
, and u
and v
are Bézout’s coefficients, such that u
×a
+ v
×b
= d
. Bézout’s coefficients (u, v)
are defined modulo (b/d, −a/d)
.
If a
≠ 0, b
≠ 0 and |a
| ≠ |b
|, then this function returns the unique pair of coefficients whose magnitude is minimal; this pair is in the following range (in particular, the function never overflows):
u
| ≤ ½|b/d
|v
| ≤ ½|a/d
|In the edge cases (a
= 0 or b
= 0 or |a
| = |b
|), it returns (u, v)
= (0, 0) or (±1, 0) or (0, ±1).
Complexity: 𝒪(log(min(|a
|,|b
|))) integer divisions.
val gcdext_of_seq : int Seq.t -> int * int list
The positive greatest common divisor of a sequence of numbers, with Bézout coefficients. gcdext_of_seq @@ List.to_seq [ a1 ; … ; an ]
returns a pair (d, [ u1 ; … ; un ])
such that d
is the positive greatest common divisor of a1, …, an, and the ui are coefficients such that a1×u1 + … + an×un = d.
Complexity: 𝒪(n × log(m)) integer divisions where n is the length of the sequence and m is its maximum element.
lcm a b
is the lesser common multiple of a
and b
. Its sign is that of a
×b
. Complexity: 𝒪(log(min(|a
|,|b
|))) integer divisions.
val lcm_of_seq : int Seq.t -> int
The lesser common multiple of a sequence of numbers. Complexity: 𝒪(n × log(m)) integer divisions where n is the length of the sequence and m is its maximum element.
valuation ~factor:d n
returns (k, m)
such that n
= d
k
×m
and m
is not divisible by d
. This assumes that n
is not null and that d
is not ±1. Complexity: 𝒪(k
) = 𝒪(log(n
)) integer divisions.
valuation_of_2
is equivalent to valuation ~factor:2
, but much faster.
smallest_root n
returns (r, k)
such that n
= r
k
and |r
| is minimal (which also implies that k
is maximal). n
must be non-zero.
jacobi a n
is the Jacobi symbol (a
|n
), provided that n
is odd and positive. Complexity: 𝒪(log(min(|a
|,n
))) integer divisions.
binoms n
returns the n
th row of Pascal’s triangle, provided that n
is a non-negative integer. Complexity: time 𝒪(n
), space 𝒪(n
).
binom n p
is the p
th element of the n
th row of Pascal’s triangle, provided that 0 ≤ p
≤ n
. Complexity: time 𝒪(min(p
,n
−p
)) = 𝒪(n
), space 𝒪(1).
central_binom p
is the p
th element of the (2×p
)th row of Pascal’s triangle, provided that 0 ≤ p
. Complexity: time 𝒪(p
), space 𝒪(1).
Most standard bitwise functions are omitted, because it is not clear what to do with overflowing integers. One common usage, dividing or multiplying by powers of 2, is covered by other, specialized functions.
Missing functions from the standard library: (land)
/ Int.logand
, (lor)
/ Int.logor
, (lxor)
/ Int.logxor
, lnot
/ Int.lognot
, (lsl)
/ Int.shift_left
, (lsr)
/ Int.shift_right_logical
, (asr)
/ Int.shift_right
.
number_of_bits_set n
is the number of non-zero bits in the binary writing of the integer n
(assuming two’s complement for negative numbers). Complexity: 𝒪(result
).
rand ~min ~max ()
draws a random integer with the uniform distribution between min
and max
(inclusive). max
must be greater than or equal to min
. min
defaults to 0, max
defaults to max_int
.
rand_signed ~max ()
draws a random integer with the uniform distribution, with an absolute value at most max
. max
must be non-negative.
val range' : ?step:int -> ?from:int -> ?til:int -> unit -> int Seq.t
range' ~step ~from ~til ()
returns the sequence of integers between from
(inclusive) and til
(exclusive), by increments of step
. step
must be non-zero, but it can be negative, in which case the sequence is decreasing. step
defaults to 1, from
defaults to 0; when til
is not given, the default is to build the sequence of all representable integers starting from from
with increment step
. The sequence is persistent (the unit argument is meaningless, it just erases optional arguments). Complexity: 𝒪(1) time and space.
val range : from:int -> til:int -> int Seq.t
range ~from ~til
are the integers from from
up to til
−1. In other words it is range' ~step:1 ~from ~til ()
.
val range_down : from:int -> til:int -> int Seq.t
range_down ~from ~til
are the integers from from
down to til
+1. In other words it is range' ~step:~-1 ~from ~til ()
.
val range0 : int -> int Seq.t
range0 n
are the n
integers from 0 up to n
−1. In other words, it is range ~from:0 ~til:n
.
val range1 : int -> int Seq.t
range0 n
are the n
integers from 1 up to n
. In other words, it is range ~from:1 ~til:(n+1)
(except that n
is allowed to be max_int
).
We deliberately override the standard operators. This is to make sure we don’t write unsafe arithmetic by accident.
Prefix notation for opp
.
Infix notation for add
.
Infix notation for sub
.
Infix notation for mul
.
Infix notation for equo
. Note that this is not the same as Stdlib.(/)
when the dividend is negative.
New infix notation for Stdlib.( ** )
, the floating-point exponentiation.
module Unsafe : sig ... end
Module Unsafe
gives access to the old operations for when we know what we are doing (i.e. we know that a given operation cannot overflow) and we absolutely don’t want to pay for the overhead of the safe functions. Operators in that module are suffixed with a !
so as to distinguish them clearly.