[m-rev.] for review: fix bug in MR_sprintf_float

Ian MacLarty maclarty at csse.unimelb.edu.au
Fri Jul 16 13:50:29 AEST 2010


Still bootchecking this, but it passes float_roundtrip and
test_pretty_print.

runtime/mercury_float.c:
    Fix a bug in MR_sprintf_float where it would convert 1.8e-10
    into "1.80000000000000e-1" instead of "1.8e-10".

    The problem was that it was stripping the zeros off the end of the string
    produced by sprintf without considering the case where the output
    was in scientific notation.

    The fix is to remove the `#' from the sprintf format string and then to
    append ".0" to the string if there is no "." or "e".

tests/general/float_roundtrip.m:
tests/general/float_roundtrip.exp:
    Add regression test.

Index: runtime/mercury_float.c
===================================================================
RCS file: /home/mercury1/repository/mercury/runtime/mercury_float.c,v
retrieving revision 1.10
diff -u -r1.10 mercury_float.c
--- runtime/mercury_float.c	15 Feb 2007 00:41:49 -0000	1.10
+++ runtime/mercury_float.c	16 Jul 2010 03:42:32 -0000
@@ -73,7 +73,7 @@
     ** is round-trippable.
     */
     do {
-        sprintf(buf, "%#.*g", i, f);
+        sprintf(buf, "%.*g", i, f);
         if (i >= MR_FLT_MAX_PRECISION) {
             /*
             ** This should be sufficient precision to round-trip any value.
@@ -87,30 +87,18 @@
     } while (round_trip != f);
 
     /*
-    ** Strip redundant trailing zeroes from the string (this behaviour
-    ** for %g is suppressed by the # modifier).
+    ** Append ".0" if there is no "e" or "." in the string.
     */
-    for (n = strlen(buf) - 1; n > 0; n--) {
-        switch (buf[n]) {
-            case '.': 
-                buf[n + 2] = '\0';
-                return;
-            case '0':
-                continue;
-            case '1':
-            case '2':
-            case '3':
-            case '4':
-            case '5':
-            case '6':
-            case '7':
-            case '8':
-            case '9':
-                buf[n + 1] = '\0';
-                return;
-            default:
-                return;
+    while (1) {
+        if (*buf == 'e' || *buf == '.') {
+            return;
         }
+        if (*buf == '\0') {
+            /* We only get here if there is no '.' or 'e' in the string. */
+            strcpy(buf, ".0");
+            return;
+        }
+        buf++;
     }
 
     return;
Index: tests/general/float_roundtrip.exp
===================================================================
RCS file: /home/mercury1/repository/tests/general/float_roundtrip.exp,v
retrieving revision 1.1
diff -u -r1.1 float_roundtrip.exp
--- tests/general/float_roundtrip.exp	21 Nov 2002 08:00:58 -0000	1.1
+++ tests/general/float_roundtrip.exp	16 Jul 2010 03:42:33 -0000
@@ -2,3 +2,4 @@
 0.123573124         : success.
 0.987654321012345   : success.
 0.12345678901234566 : success.
+1.8e-10             : success.
Index: tests/general/float_roundtrip.m
===================================================================
RCS file: /home/mercury1/repository/tests/general/float_roundtrip.m,v
retrieving revision 1.1
diff -u -r1.1 float_roundtrip.m
--- tests/general/float_roundtrip.m	21 Nov 2002 08:00:58 -0000	1.1
+++ tests/general/float_roundtrip.m	16 Jul 2010 03:42:33 -0000
@@ -14,7 +14,8 @@
 	test_float(7,  0.9092974),
 	test_float(9,  0.123573124),
 	test_float(15, 0.987654321012345),
-	test_float(17, 0.12345678901234566).
+	test_float(17, 0.12345678901234566),
+        test_float_roundtrippable(1.8e-10).
 
 :- pred test_float(int::in, float::in, io::di, io::uo) is det.
 
@@ -35,6 +36,16 @@
 		io__write_string(" digits of precision.\n")
 	).
 
+:- pred test_float_roundtrippable(float::in, io::di, io::uo) is det.
+
+test_float_roundtrippable(Flt, !IO) :-
+        ( roundtrip_float(Flt) ->
+            io.format("%-20s: ", [s(string.float_to_string(Flt))], !IO), 
+            io.write_string("success.\n", !IO)
+        ;
+            io.format("failed to roundtrip %f\n", [f(Flt)], !IO)
+        ).
+
 	% Test that when we round-trip the float that we get the same float
 	% back.
 :- pred roundtrip_float(float::in) is semidet.
--------------------------------------------------------------------------
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