[m-rev.] for review: implement checked division for uints
Julien Fischer
jfischer at opturion.com
Wed May 10 13:10:07 AEST 2017
For review by anyone.
The int module also provides div/2 and mod/2 which round differently for
negative results than / and rem. The result cannot (obviously) be
negative for uints; do we want to provide div/2 and mod/2 as synonyms for
/ and rem in the uint module? (mod in particular is the obvious name
for the operation.)
Note: I will update the expected output for 32-bit system before I
commit.
-----------------------------
Implement checked division for uints.
library/uint.m:
Add (//)/2, (/)/2 and rem/2 for uints.
tests/hard_coded/uint_arith.m
Enable the division tests.
tests/hard_coded/uint_bitwise.exp:
Update the expected output.
Julien.
diff --git a/library/uint.m b/library/uint.m
index f757cd78e..a0088ab36 100644
--- a/library/uint.m
+++ b/library/uint.m
@@ -77,8 +77,31 @@
%
:- func min(uint, uint) = uint.
+ % Integer division.
+ %
+ % Throws a `math.domain_error' exception if the right operand is zero.
+ %
+:- func (uint::in) // (uint::in) = (uint::uo) is det.
+
+ % (/)/2 is a synonym for (//)/2.
+ %
+:- func (uint::in) / (uint::in) = (uint::uo) is det.
+
+ % unchecked_quotient(X, Y) is the same as X // Y, but the behaviour
+ % is undefined if the right operand is zero.
+ %
:- func unchecked_quotient(uint::in, uint::in) = (uint::uo) is det.
+ % Remainder.
+ % X rem Y = X - (X // Y) * Y.
+ %
+ % Throws a `math.domain_error/` exception if the right operand is zero.
+ %
+:- func (uint::in) rem (uint::in) = (uint::uo) is det.
+
+ % unchecked_rem(X, Y) is the same as X rem Y, but the behaviour
+ % is undefined if the right operand is zero.
+ %
:- func unchecked_rem(uint::in, uint::in) = (uint::uo) is det.
% Left shift.
@@ -244,6 +267,27 @@ cast_to_int(_) = _ :-
%---------------------------------------------------------------------------%
+:- pragma inline('//'/2).
+X // Y = Div :-
+ ( if Y = cast_from_int(0) then
+ throw(math.domain_error("uint.'//': division by zero"))
+ else
+ Div = unchecked_quotient(X, Y)
+ ).
+
+:- pragma inline('/'/2).
+X / Y = X // Y.
+
+:- pragma inline(rem/2).
+X rem Y = Rem :-
+ ( if Y = cast_from_int(0) then
+ throw(math.domain_error("uint.rem: division by zero"))
+ else
+ Rem = unchecked_rem(X, Y)
+ ).
+
+%---------------------------------------------------------------------------%
+
X << Y = Result :-
( if cast_from_int(Y) < cast_from_int(bits_per_uint) then
Result = unchecked_left_shift(X, Y)
diff --git a/tests/hard_coded/uint_arith.exp b/tests/hard_coded/uint_arith.exp
index c10e78c52..985cb719f 100644
--- a/tests/hard_coded/uint_arith.exp
+++ b/tests/hard_coded/uint_arith.exp
@@ -199,3 +199,136 @@
18446744073709551615u * 32u = 18446744073709551584u
18446744073709551615u * 18446744073709551615u = 1u
+*** Test binary operation '/' ***
+
+0u / 0u = <<exception>>
+0u / 1u = 0u
+0u / 2u = 0u
+0u / 8u = 0u
+0u / 10u = 0u
+0u / 16u = 0u
+0u / 32u = 0u
+0u / 18446744073709551615u = 0u
+1u / 0u = <<exception>>
+1u / 1u = 1u
+1u / 2u = 0u
+1u / 8u = 0u
+1u / 10u = 0u
+1u / 16u = 0u
+1u / 32u = 0u
+1u / 18446744073709551615u = 0u
+2u / 0u = <<exception>>
+2u / 1u = 2u
+2u / 2u = 1u
+2u / 8u = 0u
+2u / 10u = 0u
+2u / 16u = 0u
+2u / 32u = 0u
+2u / 18446744073709551615u = 0u
+8u / 0u = <<exception>>
+8u / 1u = 8u
+8u / 2u = 4u
+8u / 8u = 1u
+8u / 10u = 0u
+8u / 16u = 0u
+8u / 32u = 0u
+8u / 18446744073709551615u = 0u
+10u / 0u = <<exception>>
+10u / 1u = 10u
+10u / 2u = 5u
+10u / 8u = 1u
+10u / 10u = 1u
+10u / 16u = 0u
+10u / 32u = 0u
+10u / 18446744073709551615u = 0u
+16u / 0u = <<exception>>
+16u / 1u = 16u
+16u / 2u = 8u
+16u / 8u = 2u
+16u / 10u = 1u
+16u / 16u = 1u
+16u / 32u = 0u
+16u / 18446744073709551615u = 0u
+32u / 0u = <<exception>>
+32u / 1u = 32u
+32u / 2u = 16u
+32u / 8u = 4u
+32u / 10u = 3u
+32u / 16u = 2u
+32u / 32u = 1u
+32u / 18446744073709551615u = 0u
+18446744073709551615u / 0u = <<exception>>
+18446744073709551615u / 1u = 18446744073709551615u
+18446744073709551615u / 2u = 18446744073709551615u
+18446744073709551615u / 8u = 18446744073709551615u
+18446744073709551615u / 10u = 18446744071991564697u
+18446744073709551615u / 16u = 18446744073709551615u
+18446744073709551615u / 32u = 18446744073709551615u
+18446744073709551615u / 18446744073709551615u = 1u
+
+*** Test binary operation 'rem' ***
+
+0u rem 0u = <<exception>>
+0u rem 1u = 0u
+0u rem 2u = 0u
+0u rem 8u = 0u
+0u rem 10u = 0u
+0u rem 16u = 0u
+0u rem 32u = 0u
+0u rem 18446744073709551615u = 0u
+1u rem 0u = <<exception>>
+1u rem 1u = 0u
+1u rem 2u = 1u
+1u rem 8u = 1u
+1u rem 10u = 1u
+1u rem 16u = 1u
+1u rem 32u = 1u
+1u rem 18446744073709551615u = 1u
+2u rem 0u = <<exception>>
+2u rem 1u = 0u
+2u rem 2u = 0u
+2u rem 8u = 2u
+2u rem 10u = 2u
+2u rem 16u = 2u
+2u rem 32u = 2u
+2u rem 18446744073709551615u = 2u
+8u rem 0u = <<exception>>
+8u rem 1u = 0u
+8u rem 2u = 0u
+8u rem 8u = 0u
+8u rem 10u = 8u
+8u rem 16u = 8u
+8u rem 32u = 8u
+8u rem 18446744073709551615u = 8u
+10u rem 0u = <<exception>>
+10u rem 1u = 0u
+10u rem 2u = 0u
+10u rem 8u = 2u
+10u rem 10u = 0u
+10u rem 16u = 10u
+10u rem 32u = 10u
+10u rem 18446744073709551615u = 10u
+16u rem 0u = <<exception>>
+16u rem 1u = 0u
+16u rem 2u = 0u
+16u rem 8u = 0u
+16u rem 10u = 6u
+16u rem 16u = 0u
+16u rem 32u = 16u
+16u rem 18446744073709551615u = 16u
+32u rem 0u = <<exception>>
+32u rem 1u = 0u
+32u rem 2u = 0u
+32u rem 8u = 0u
+32u rem 10u = 2u
+32u rem 16u = 0u
+32u rem 32u = 0u
+32u rem 18446744073709551615u = 32u
+18446744073709551615u rem 0u = <<exception>>
+18446744073709551615u rem 1u = 0u
+18446744073709551615u rem 2u = 1u
+18446744073709551615u rem 8u = 7u
+18446744073709551615u rem 10u = 5u
+18446744073709551615u rem 16u = 15u
+18446744073709551615u rem 32u = 31u
+18446744073709551615u rem 18446744073709551615u = 0u
diff --git a/tests/hard_coded/uint_arith.m b/tests/hard_coded/uint_arith.m
index 785c159d7..049feaef0 100644
--- a/tests/hard_coded/uint_arith.m
+++ b/tests/hard_coded/uint_arith.m
@@ -29,8 +29,10 @@ main(!IO) :-
run_binop_test((func(X, Y) = X - Y), "-", !IO),
io.nl(!IO),
run_binop_test((func(X, Y) = X * Y), "*", !IO),
- io.nl(!IO).
- %run_binop_test(uint.(/), "/", !IO). % NYI.
+ io.nl(!IO),
+ run_binop_test(uint.(/), "/", !IO),
+ io.nl(!IO),
+ run_binop_test(uint.(rem), "rem", !IO).
:- pred run_binop_test((func(uint, uint) = uint)::in, string::in,
io::di, io::uo) is cc_multi.
More information about the reviews
mailing list