[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