[m-rev.] for review: do not allow std_util.pow/3 with negative values
Julien Fischer
jfischer at opturion.com
Wed Jan 11 16:03:54 AEDT 2023
For review by anyone.
----------------------
Do not allow std_util.pow/3 with negative values.
library/std_util.m:
Make std_util.pow/3 throw an exception if it is called with a negative
integer as its second argument.
tests/hard_coded/Mmakefile:
tests/hard_coded/func_exp.{m,exp}:
Add a test of pow/3.
NEWS:
Announce the above change.
Julien.
diff --git a/NEWS b/NEWS
index 866343d..dc7e936 100644
--- a/NEWS
+++ b/NEWS
@@ -667,6 +667,12 @@ Changes to the Mercury standard library
- pred `empty/1`
+### Changes to the `std_util` module
+
+* We have changed the behaviour of `pow/3` so that it throws an
+ exception if it is called with a negative integer as its second
+ argument.
+
### Changes to the `string` module
* The following predicate has been added:
diff --git a/library/std_util.m b/library/std_util.m
index 8d5dc15..f795e7a 100644
--- a/library/std_util.m
+++ b/library/std_util.m
@@ -37,6 +37,7 @@
% pow(F, N, X) = F^N(X)
%
% Function exponentiation.
+ % Throws an exception if N is negative.
%
:- func pow(func(T) = T, int, T) = T.
@@ -67,6 +68,7 @@
:- implementation.
:- import_module int.
+:- import_module require.
%---------------------------------------------------------------------------%
@@ -77,7 +79,16 @@ converse(F, X, Y) =
F(Y, X).
pow(F, N, X) =
- ( if N = 0 then X else pow(F, N - 1, F(X)) ).
+ ( if N < 0 then
+ func_error($pred, "N is negative")
+ else
+ do_pow(F, N, X)
+ ).
+
+:- func do_pow(func(T) = T, int, T) = T.
+
+do_pow(F, N, X) =
+ ( if N = 0 then X else do_pow(F, N - 1, F(X)) ).
id(X) = X.
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 22e781b..fc38c1a 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -815,6 +815,7 @@ ifeq "$(findstring profdeep,$(GRADE))" ""
cmp_uint8 \
dir_test \
final_excp \
+ func_exp \
ho_array_ops \
init_excp \
int8_static_data \
diff --git a/tests/hard_coded/func_exp.exp b/tests/hard_coded/func_exp.exp
index e69de29..e71d43c 100644
--- a/tests/hard_coded/func_exp.exp
+++ b/tests/hard_coded/func_exp.exp
@@ -0,0 +1,4 @@
+pow(double, -1, 1) = software_error("function `std_util.pow\'/3: N is negative")
+pow(double, 0, 1) = 1
+pow(double, 1, 1) = 2
+pow(double, 10, 1) = 1024
diff --git a/tests/hard_coded/func_exp.m b/tests/hard_coded/func_exp.m
index e69de29..ea8c274 100644
--- a/tests/hard_coded/func_exp.m
+++ b/tests/hard_coded/func_exp.m
@@ -0,0 +1,52 @@
+%---------------------------------------------------------------------------%
+% vim: ft=mercury ts=4 sw=4 et
+%---------------------------------------------------------------------------%
+
+:- module func_exp.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is cc_multi.
+
+%---------------------------------------------------------------------------%
+%---------------------------------------------------------------------------%
+
+:- implementation.
+
+:- import_module int.
+:- import_module list.
+:- import_module std_util.
+:- import_module string.
+
+%---------------------------------------------------------------------------%
+
+main(!IO) :-
+ do_test(-1, 1, !IO),
+ do_test(0, 1, !IO),
+ do_test(1, 1, !IO),
+ do_test(10, 1, !IO).
+
+%---------------------------------------------------------------------------%
+
+:- pred do_test(int::in, int::in, io::di, io::uo) is cc_multi.
+
+do_test(N, X, !IO) :-
+ io.format("pow(double, %d, %d) = ", [i(N), i(X)], !IO),
+ ( try []
+ Result = std_util.pow(double, N, X)
+ then
+ io.print_line(Result, !IO)
+ catch_any S ->
+ io.print_line(S, !IO)
+ ).
+
+%---------------------------------------------------------------------------%
+
+:- func double(int) = int.
+
+double(X) = 2 * X.
+
+%---------------------------------------------------------------------------%
+:- end_module func_exp.
+%---------------------------------------------------------------------------%
More information about the reviews
mailing list