summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2008-04-19 17:26:36 +0200
committerBruno Haible <bruno@clisp.org>2008-04-19 17:26:36 +0200
commitf797ae74856a21b4471baec28dbbfd82b48fe2dc (patch)
treefc1a1a25bd9a89d66437e96c4259e249b3599557 /lib
parent2e8956774250d3f5636898fea193c5abaf041d08 (diff)
downloadgnulib-f797ae74856a21b4471baec28dbbfd82b48fe2dc.tar.gz
Fix rounding when a precision is given.
Diffstat (limited to 'lib')
-rw-r--r--lib/vasnprintf.c112
1 files changed, 110 insertions, 2 deletions
diff --git a/lib/vasnprintf.c b/lib/vasnprintf.c
index 74b30374cb..2ee0c05ce6 100644
--- a/lib/vasnprintf.c
+++ b/lib/vasnprintf.c
@@ -1404,6 +1404,20 @@ floorlog10 (double x)
# endif
+/* Tests whether a string of digits consists of exactly PRECISION zeroes and
+ a single '1' digit. */
+static int
+is_borderline (const char *digits, size_t precision)
+{
+ for (; precision > 0; precision--, digits++)
+ if (*digits != '0')
+ return 0;
+ if (*digits != '1')
+ return 0;
+ digits++;
+ return *digits == '\0';
+}
+
#endif
DCHAR_T *
@@ -2853,8 +2867,32 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
exponent += 1;
adjusted = 1;
}
-
/* Here ndigits = precision+1. */
+ if (is_borderline (digits, precision))
+ {
+ /* Maybe the exponent guess was too high
+ and a smaller exponent can be reached
+ by turning a 10...0 into 9...9x. */
+ char *digits2 =
+ scale10_round_decimal_long_double (arg,
+ (int)precision - exponent + 1);
+ if (digits2 == NULL)
+ {
+ free (digits);
+ END_LONG_DOUBLE_ROUNDING ();
+ goto out_of_memory;
+ }
+ if (strlen (digits2) == precision + 1)
+ {
+ free (digits);
+ digits = digits2;
+ exponent -= 1;
+ }
+ else
+ free (digits2);
+ }
+ /* Here ndigits = precision+1. */
+
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || precision > 0)
{
@@ -2966,6 +3004,30 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
adjusted = 1;
}
/* Here ndigits = precision. */
+ if (is_borderline (digits, precision - 1))
+ {
+ /* Maybe the exponent guess was too high
+ and a smaller exponent can be reached
+ by turning a 10...0 into 9...9x. */
+ char *digits2 =
+ scale10_round_decimal_long_double (arg,
+ (int)(precision - 1) - exponent + 1);
+ if (digits2 == NULL)
+ {
+ free (digits);
+ END_LONG_DOUBLE_ROUNDING ();
+ goto out_of_memory;
+ }
+ if (strlen (digits2) == precision)
+ {
+ free (digits);
+ digits = digits2;
+ exponent -= 1;
+ }
+ else
+ free (digits2);
+ }
+ /* Here ndigits = precision. */
/* Determine the number of trailing zeroes
that have to be dropped. */
@@ -3206,8 +3268,31 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
exponent += 1;
adjusted = 1;
}
-
/* Here ndigits = precision+1. */
+ if (is_borderline (digits, precision))
+ {
+ /* Maybe the exponent guess was too high
+ and a smaller exponent can be reached
+ by turning a 10...0 into 9...9x. */
+ char *digits2 =
+ scale10_round_decimal_double (arg,
+ (int)precision - exponent + 1);
+ if (digits2 == NULL)
+ {
+ free (digits);
+ goto out_of_memory;
+ }
+ if (strlen (digits2) == precision + 1)
+ {
+ free (digits);
+ digits = digits2;
+ exponent -= 1;
+ }
+ else
+ free (digits2);
+ }
+ /* Here ndigits = precision+1. */
+
*p++ = digits[--ndigits];
if ((flags & FLAG_ALT) || precision > 0)
{
@@ -3332,6 +3417,29 @@ VASNPRINTF (DCHAR_T *resultbuf, size_t *lengthp,
adjusted = 1;
}
/* Here ndigits = precision. */
+ if (is_borderline (digits, precision - 1))
+ {
+ /* Maybe the exponent guess was too high
+ and a smaller exponent can be reached
+ by turning a 10...0 into 9...9x. */
+ char *digits2 =
+ scale10_round_decimal_double (arg,
+ (int)(precision - 1) - exponent + 1);
+ if (digits2 == NULL)
+ {
+ free (digits);
+ goto out_of_memory;
+ }
+ if (strlen (digits2) == precision)
+ {
+ free (digits);
+ digits = digits2;
+ exponent -= 1;
+ }
+ else
+ free (digits2);
+ }
+ /* Here ndigits = precision. */
/* Determine the number of trailing zeroes
that have to be dropped. */