[m-rev.] diff: add integer.(det_)from_base_string/2
Julien Fischer
juliensf at csse.unimelb.edu.au
Thu May 10 13:51:57 AEST 2007
The following additions were requested by Nick.
Estimated hours taken: 1.5
Branches: main
library/integer.m:
Add the functions integer.from_base_string/2 and
integer.det_from_base_string/2.
NEWS:
Announce the new functions.
tests/general/Mmakefile:
tests/general/.cvsignore:
tests/general/base_string_to_integer.{m,exp}:
Test the new functions.
Julien.
Index: NEWS
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/NEWS,v
retrieving revision 1.457
diff -u -r1.457 NEWS
--- NEWS 1 May 2007 01:13:09 -0000 1.457
+++ NEWS 10 May 2007 02:19:22 -0000
@@ -17,6 +17,10 @@
Changes to the Mercury standard library:
+* The following functions have been added to the integer module:
+ integer.from_base_string/2
+ integer.det_from_base_string/2
+
* Predicates and functions which create strings from lists of characters
now fail, throw an exception or return an error value if a null character
is found. Unexpected null characters in strings are a potential source of
Index: library/integer.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/integer.m,v
retrieving revision 1.27
diff -u -r1.27 integer.m
--- library/integer.m 23 Oct 2006 00:32:57 -0000 1.27
+++ library/integer.m 10 May 2007 02:06:04 -0000
@@ -42,6 +42,18 @@
:- func integer.det_from_string(string) = integer.
+ % Convert a string in the specified base (2-36) to an integer.
+ % The string must contain one or more digits in the specified base,
+ % optionally preceded by a plus or minus sign. For bases > 10, digits
+ % 10 to 35 are represented by the letters A-z or a-z. If the string
+ % does not match this syntax then the function fails.
+ %
+:- func integer.from_base_string(int, string) = integer is semidet.
+
+ % As above but throws an exception rather than failing.
+ %
+:- func integer.det_from_base_string(int, string) = integer.
+
:- func '+'(integer) = integer.
:- func '-'(integer) = integer.
@@ -1197,4 +1209,42 @@
printbase_mul_by_digit(X, Y)), Y).
%-----------------------------------------------------------------------------%
+
+integer.from_base_string(Base0, String) = Integer :-
+ string.index(String, 0, Char),
+ Base = integer(Base0),
+ Len = string.length(String),
+ ( Char = ('-') ->
+ Len > 1,
+ string.foldl_substring(accumulate_integer(Base), String, 1, Len - 1,
+ integer.zero, N),
+ Integer = -N
+ ; Char = ('+') ->
+ Len > 1,
+ string.foldl_substring(accumulate_integer(Base), String, 1, Len - 1,
+ integer.zero, N),
+ Integer = N
+ ;
+ string.foldl_substring(accumulate_integer(Base), String, 0, Len,
+ integer.zero, N),
+ Integer = N
+ ).
+
+:- pred accumulate_integer(integer::in, char::in, integer::in, integer::out)
+ is semidet.
+
+accumulate_integer(Base, Char, !N) :-
+ char.digit_to_int(Char, Digit0),
+ Digit = integer(Digit0),
+ Digit < Base,
+ !:N = (Base * !.N) + Digit.
+
+integer.det_from_base_string(Base, String) = Integer :-
+ ( Integer0 = integer.from_base_string(Base, String) ->
+ Integer = Integer0
+ ;
+ error("integer.det_from_base_string")
+ ).
+
+%-----------------------------------------------------------------------------%
%-----------------------------------------------------------------------------%
Index: tests/general/.cvsignore
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/general/.cvsignore,v
retrieving revision 1.16
diff -u -r1.16 .cvsignore
--- tests/general/.cvsignore 30 Sep 1998 04:23:25 -0000 1.16
+++ tests/general/.cvsignore 10 May 2007 03:47:36 -0000
@@ -13,3 +13,4 @@
mode_inf
intermod_type
CLEAN
+base_string_to_integer
Index: tests/general/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/general/Mmakefile,v
retrieving revision 1.54
diff -u -r1.54 Mmakefile
--- tests/general/Mmakefile 14 Nov 2006 04:10:22 -0000 1.54
+++ tests/general/Mmakefile 10 May 2007 03:47:22 -0000
@@ -10,6 +10,7 @@
arithmetic \
array_test \
base_string_to_int_test \
+ base_string_to_integer \
commit_bug \
commit_bug_2 \
complex_failure \
Index: tests/general/base_string_to_integer.exp
===================================================================
RCS file: tests/general/base_string_to_integer.exp
diff -N tests/general/base_string_to_integer.exp
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/general/base_string_to_integer.exp 10 May 2007 03:46:00 -0000
@@ -0,0 +1,43 @@
+0 (base 2) = 0
+1 (base 2) = 1
+01 (base 2) = 1
+-000001 (base 2) = -1
+11 (base 2) = 3
+111 (base 2) = 7
+11111 (base 2) = 31
+101010 (base 2) = 42
+10000000000000000000000000000000 (base 2) = 2147483648
+1000000000000000000000000000000000000000000000000000000000000000 (base 2) = 9223372036854775808
+10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 (base 2) = 170141183460469231731687303715884105728
+0 (base 8) = 0
+1 (base 8) = 1
+-1 (base 8) = -1
+10 (base 8) = 8
+-10 (base 8) = -8
+76543210 (base 8) = 16434824
+-76543210 (base 8) = -16434824
+7777777777777777777777777 (base 8) = 37778931862957161709567
+0 (base 10) = 0
+1 (base 10) = 1
+10 (base 10) = 10
+11 (base 10) = 11
+1234567890 (base 10) = 1234567890
+-1 (base 10) = -1
+-10 (base 10) = -10
+-1234567890 (base 10) = -1234567890
+1234567891234567891234567890 (base 10) = 1234567891234567891234567890
+-1234567891234567891234567890 (base 10) = -1234567891234567891234567890
+0 (base 16) = 0
+1 (base 16) = 1
+-1 (base 16) = -1
+10 (base 16) = 16
+A (base 16) = 10
+-A (base 16) = -10
+a (base 16) = 10
+-a (base 16) = -10
+F (base 16) = 15
+-F (base 16) = -15
+fedcba0987654321 (base 16) = 18364757930599072545
+-fedcba0987654321 (base 16) = -18364757930599072545
+fffffffffffffffffffffffffffffffffff (base 16) = 1393796574908163946345982392040522594123775
+-fffffffffffffffffffffffffffffffffff (base 16) = -1393796574908163946345982392040522594123775
Index: tests/general/base_string_to_integer.m
===================================================================
RCS file: tests/general/base_string_to_integer.m
diff -N tests/general/base_string_to_integer.m
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ tests/general/base_string_to_integer.m 10 May 2007 03:46:00 -0000
@@ -0,0 +1,98 @@
+% vim: ft=mercury ts=4 sw=4 et
+% Test converting strings to arbitrary precision integers.
+:- module base_string_to_integer.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+:- import_module integer.
+:- import_module list.
+:- import_module require.
+:- import_module string.
+
+main(!IO) :-
+ Base2 = [
+ "0",
+ "1",
+ "01",
+ "-000001",
+ "11",
+ "111",
+ "11111",
+ "101010",
+ "10000000000000000000000000000000",
+ "1000000000000000000000000000000000000000000000000000000000000000",
+ "10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+ ],
+ check_base_valid(2, Base2, !IO),
+ Base8 = [
+ "0",
+ "1",
+ "-1",
+ "10",
+ "-10",
+ "76543210",
+ "-76543210",
+ "7777777777777777777777777"
+ ],
+ check_base_valid(8, Base8, !IO),
+ Base10 = [
+ "0",
+ "1",
+ "10",
+ "11",
+ "1234567890",
+ "-1",
+ "-10",
+ "-1234567890",
+ "1234567891234567891234567890",
+ "-1234567891234567891234567890"
+ ],
+ check_base_valid(10, Base10, !IO),
+ Base16 = [
+ "0",
+ "1",
+ "-1",
+ "10",
+ "A",
+ "-A",
+ "a",
+ "-a",
+ "F",
+ "-F",
+ "fedcba0987654321",
+ "-fedcba0987654321",
+ "fffffffffffffffffffffffffffffffffff",
+ "-fffffffffffffffffffffffffffffffffff"
+ ],
+ check_base_valid(16, Base16, !IO),
+ InvalidBase2 = ["3", "4", "5", "6", "a", "A", "z", "13"],
+ check_base_invalid(2, InvalidBase2, !IO),
+ InvalidBase10 = ["abc", "-123a", "ZZZ"],
+ check_base_invalid(10, InvalidBase10, !IO).
+
+:- pred check_base_valid(int::in, list(string)::in, io::di, io::uo) is det.
+
+check_base_valid(_, [], !IO).
+check_base_valid(Base, [ String | Strings ], !IO) :-
+ Num = integer.det_from_base_string(Base, String),
+ NumStr = integer.to_string(Num),
+ io.format("%s (base %d) = %s\n", [s(String), i(Base), s(NumStr)],
+ !IO),
+ check_base_valid(Base, Strings, !IO).
+
+:- pred check_base_invalid(int::in, list(string)::in, io::di, io::uo) is det.
+
+check_base_invalid(_, [], !IO).
+check_base_invalid(Base, [ String | Strings ], !IO) :-
+ ( Num = integer.from_base_string(Base, String) ->
+ NumStr = integer.to_string(Num),
+ string.format("ERROR: %s (base %d) = %s\n",
+ [s(String), i(Base), s(NumStr)], ErrorMsg),
+ error(ErrorMsg)
+ ;
+ check_base_invalid(Base, Strings, !IO)
+ ).
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list