Commit 05abb346 by Tobias Burnus Committed by Tobias Burnus

quadmath-rounding-mode.h: New.

2012-11-23  Tobias Burnus  <burnus@net-b.de>
            Joseph Myers  <joseph@codesourcery.com>

        * quadmath-rounding-mode.h: New.
        * printf/fpioconst.c: Update from GLIBC. Fix strtod rounding.
        * printf/fpioconst.h: Ditto.
        * printf/printf_fp.c (__quadmath_printf_fp): Update from GLIBC.
        Make printf respect the rounding mode for decimal output.
        * printf/printf_fphex.c (__quadmath_printf_fphex): Update from
        GLIBC.  Make printf respect the rounding mode for hex output.
        * strtod/strtod_l.c: Update from GLIBC. Make strtod respect the
        rounding mode. Fix strtod handling of underflow.


Co-Authored-By: Joseph Myers <joseph@codesourcery.com>

From-SVN: r193770
parent aa66b299
2012-11-23 Tobias Burnus <burnus@net-b.de>
Joseph Myers <joseph@codesourcery.com>
* quadmath-rounding-mode.h: New.
* printf/fpioconst.c: Update from GLIBC. Fix strtod rounding.
* printf/fpioconst.h: Ditto.
* printf/printf_fp.c (__quadmath_printf_fp): Update from GLIBC.
Make printf respect the rounding mode for decimal output.
* printf/printf_fphex.c (__quadmath_printf_fphex): Update from
GLIBC. Make printf respect the rounding mode for hex output.
* strtod/strtod_l.c: Update from GLIBC. Make strtod respect the
rounding mode. Fix strtod handling of underflow.
2012-11-22 David S. Miller <davem@davemloft.net> 2012-11-22 David S. Miller <davem@davemloft.net>
Tobias Burnus <burnus@net-b.de> Tobias Burnus <burnus@net-b.de>
Joseph Myers <joseph@codesourcery.com> Joseph Myers <joseph@codesourcery.com>
......
...@@ -35,6 +35,14 @@ ...@@ -35,6 +35,14 @@
#define FLT128_MAX_10_EXP_LOG 12 /* = floor(log_2(FLT128_MAX_10_EXP)) */ #define FLT128_MAX_10_EXP_LOG 12 /* = floor(log_2(FLT128_MAX_10_EXP)) */
/* For strtoq, we need powers of 10 up to floor (log_2 (FLT128_MANT_DIG
- FLT128_MIN_EXP + 2)). */
#if !defined __NO_LONG_DOUBLE_MATH && FLT128_MAX_EXP > 1024
# define FPIOCONST_POW10_ARRAY_SIZE 15
#else
# define FPIOCONST_POW10_ARRAY_SIZE 11
#endif
/* The array with the number representation. */ /* The array with the number representation. */
#define __tens __quadmath_tens #define __tens __quadmath_tens
...@@ -50,7 +58,7 @@ struct mp_power ...@@ -50,7 +58,7 @@ struct mp_power
int m_expo; /* Exponent of the number 10^-(2^i-1). */ int m_expo; /* Exponent of the number 10^-(2^i-1). */
}; };
#define _fpioconst_pow10 __quadmath_fpioconst_pow10 #define _fpioconst_pow10 __quadmath_fpioconst_pow10
extern const struct mp_power _fpioconst_pow10[FLT128_MAX_10_EXP_LOG + 1] extern const struct mp_power _fpioconst_pow10[FPIOCONST_POW10_ARRAY_SIZE]
attribute_hidden; attribute_hidden;
/* The constants in the array `_fpioconst_pow10' have an offset. */ /* The constants in the array `_fpioconst_pow10' have an offset. */
......
/* Floating point output for `printf'. /* Floating point output for `printf'.
Copyright (C) 1995-2003, 2006-2008, 2011 Free Software Foundation, Inc. Copyright (C) 1995-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
...@@ -15,16 +15,17 @@ ...@@ -15,16 +15,17 @@
Lesser General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free License along with the GNU C Library; if not, see
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA <http://www.gnu.org/licenses/>. */
02111-1307 USA. */
#include <config.h> #include <config.h>
#include <float.h> #include <float.h>
#include <limits.h>
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h>
#define NDEBUG #define NDEBUG
#include <assert.h> #include <assert.h>
#ifdef HAVE_ERRNO_H #ifdef HAVE_ERRNO_H
...@@ -32,6 +33,9 @@ ...@@ -32,6 +33,9 @@
#endif #endif
#include <stdio.h> #include <stdio.h>
#include <stdarg.h> #include <stdarg.h>
#ifdef HAVE_FENV_H
#include "quadmath-rounding-mode.h"
#endif
#include "quadmath-printf.h" #include "quadmath-printf.h"
#include "fpioconst.h" #include "fpioconst.h"
...@@ -162,7 +166,8 @@ __quadmath_printf_fp (struct __quadmath_printf_file *fp, ...@@ -162,7 +166,8 @@ __quadmath_printf_fp (struct __quadmath_printf_file *fp,
MPN_VAR(tmp); MPN_VAR(tmp);
/* Digit which is result of last hack_digit() call. */ /* Digit which is result of last hack_digit() call. */
wchar_t digit; wchar_t last_digit, next_digit;
bool more_bits;
/* The type of output format that will be used: 'e'/'E' or 'f'. */ /* The type of output format that will be used: 'e'/'E' or 'f'. */
int type; int type;
...@@ -935,20 +940,14 @@ __quadmath_printf_fp (struct __quadmath_printf_file *fp, ...@@ -935,20 +940,14 @@ __quadmath_printf_fp (struct __quadmath_printf_file *fp,
} }
/* Do rounding. */ /* Do rounding. */
digit = hack_digit (); last_digit = wcp[-1] != decimalwc ? wcp[-1] : wcp[-2];
if (digit > L_('4')) next_digit =hack_digit ();
{
wchar_t *wtp = wcp; if (next_digit != L_('0') && next_digit != L_('5'))
more_bits = true;
if (digit == L_('5') else if (fracsize == 1 && frac[0] == 0)
&& ((*(wcp - 1) != decimalwc && (*(wcp - 1) & 1) == 0) /* Rest of the number is zero. */
|| ((*(wcp - 1) == decimalwc && (*(wcp - 2) & 1) == 0)))) more_bits = false;
{
/* This is the critical case. */
if (fracsize == 1 && frac[0] == 0)
/* Rest of the number is zero -> round to even.
(IEEE 754-1985 4.1 says this is the default rounding.) */
goto do_expo;
else if (scalesize == 0) else if (scalesize == 0)
{ {
/* Here we have to see whether all limbs are zero since no /* Here we have to see whether all limbs are zero since no
...@@ -956,12 +955,17 @@ __quadmath_printf_fp (struct __quadmath_printf_file *fp, ...@@ -956,12 +955,17 @@ __quadmath_printf_fp (struct __quadmath_printf_file *fp,
size_t lcnt = fracsize; size_t lcnt = fracsize;
while (lcnt >= 1 && frac[lcnt - 1] == 0) while (lcnt >= 1 && frac[lcnt - 1] == 0)
--lcnt; --lcnt;
if (lcnt == 0) more_bits = lcnt > 0;
/* Rest of the number is zero -> round to even.
(IEEE 754-1985 4.1 says this is the default rounding.) */
goto do_expo;
}
} }
else
more_bits = true;
#ifdef HAVE_FENV_H
int rounding_mode = get_rounding_mode ();
if (round_away (is_neg, (last_digit - L_('0')) & 1, next_digit >= L_('5'),
more_bits, rounding_mode))
{
wchar_t *wtp = wcp;
if (fracdig_no > 0) if (fracdig_no > 0)
{ {
...@@ -1055,8 +1059,8 @@ __quadmath_printf_fp (struct __quadmath_printf_file *fp, ...@@ -1055,8 +1059,8 @@ __quadmath_printf_fp (struct __quadmath_printf_file *fp,
} }
} }
} }
#endif
do_expo:
/* Now remove unnecessary '0' at the end of the string. */ /* Now remove unnecessary '0' at the end of the string. */
while (fracdig_no > fracdig_min + added_zeros && *(wcp - 1) == L_('0')) while (fracdig_no > fracdig_min + added_zeros && *(wcp - 1) == L_('0'))
{ {
...@@ -1249,15 +1253,19 @@ guess_grouping (unsigned int intdig_max, const char *grouping) ...@@ -1249,15 +1253,19 @@ guess_grouping (unsigned int intdig_max, const char *grouping)
++groups; ++groups;
intdig_max -= *grouping++; intdig_max -= *grouping++;
if (*grouping == 0) if (*grouping == CHAR_MAX
#if CHAR_MIN < 0
|| *grouping < 0
#endif
)
/* No more grouping should be done. */
break;
else if (*grouping == 0)
{ {
/* Same grouping repeats. */ /* Same grouping repeats. */
groups += (intdig_max - 1) / grouping[-1]; groups += (intdig_max - 1) / grouping[-1];
break; break;
} }
else if (*grouping == CHAR_MAX || *grouping <= 0)
/* No more grouping should be done. */
break;
} }
return groups; return groups;
...@@ -1289,12 +1297,16 @@ group_number (wchar_t *buf, wchar_t *bufend, unsigned int intdig_no, ...@@ -1289,12 +1297,16 @@ group_number (wchar_t *buf, wchar_t *bufend, unsigned int intdig_no,
while (--len > 0); while (--len > 0);
*p-- = thousands_sep; *p-- = thousands_sep;
if (*grouping == 0) if (*grouping == CHAR_MAX
/* Same grouping repeats. */ #if CHAR_MIN < 0
--grouping; || *grouping < 0
else if (*grouping == CHAR_MAX || *grouping <= 0) #endif
)
/* No more grouping should be done. */ /* No more grouping should be done. */
break; break;
else if (*grouping == 0)
/* Same grouping repeats. */
--grouping;
} while (intdig_no > (unsigned int) *grouping); } while (intdig_no > (unsigned int) *grouping);
/* Copy the remaining ungrouped digits. */ /* Copy the remaining ungrouped digits. */
......
/* Print floating point number in hexadecimal notation according to ISO C99. /* Print floating point number in hexadecimal notation according to ISO C99.
Copyright (C) 1997-2002,2004,2006 Free Software Foundation, Inc. Copyright (C) 1997-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library. This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
...@@ -14,17 +14,18 @@ ...@@ -14,17 +14,18 @@
Lesser General Public License for more details. Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free License along with the GNU C Library; if not, see
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA <http://www.gnu.org/licenses/>. */
02111-1307 USA. */
#include <config.h> #include <config.h>
#include <math.h> #include <math.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdbool.h>
#define NDEBUG #define NDEBUG
#include <assert.h> #include <assert.h>
#include "quadmath-rounding-mode.h"
#include "quadmath-printf.h" #include "quadmath-printf.h"
#include "_itoa.h" #include "_itoa.h"
#include "_itowa.h" #include "_itowa.h"
...@@ -116,6 +117,8 @@ __quadmath_printf_fphex (struct __quadmath_printf_file *fp, ...@@ -116,6 +117,8 @@ __quadmath_printf_fphex (struct __quadmath_printf_file *fp,
/* Nonzero if this is output on a wide character stream. */ /* Nonzero if this is output on a wide character stream. */
int wide = info->wide; int wide = info->wide;
bool do_round_away;
/* Figure out the decimal point character. */ /* Figure out the decimal point character. */
#ifdef USE_NL_LANGINFO #ifdef USE_NL_LANGINFO
if (info->extra == 0) if (info->extra == 0)
...@@ -274,8 +277,8 @@ __quadmath_printf_fphex (struct __quadmath_printf_file *fp, ...@@ -274,8 +277,8 @@ __quadmath_printf_fphex (struct __quadmath_printf_file *fp,
/* Fill with zeroes. */ /* Fill with zeroes. */
while (numstr > numbuf + (sizeof numbuf - 112 / 4)) while (numstr > numbuf + (sizeof numbuf - 112 / 4))
{ {
*--numstr = '0';
*--wnumstr = L_('0'); *--wnumstr = L_('0');
*--numstr = '0';
} }
leading = fpnum.ieee.exponent == 0 ? '0' : '1'; leading = fpnum.ieee.exponent == 0 ? '0' : '1';
...@@ -316,21 +319,35 @@ __quadmath_printf_fphex (struct __quadmath_printf_file *fp, ...@@ -316,21 +319,35 @@ __quadmath_printf_fphex (struct __quadmath_printf_file *fp,
--numend; --numend;
} }
do_round_away = false;
if (precision != -1 && precision < numend - numstr)
{
char last_digit = precision > 0 ? numstr[precision - 1] : leading;
char next_digit = numstr[precision];
int last_digit_value = (last_digit >= 'A' && last_digit <= 'F'
? last_digit - 'A' + 10
: (last_digit >= 'a' && last_digit <= 'f'
? last_digit - 'a' + 10
: last_digit - '0'));
int next_digit_value = (next_digit >= 'A' && next_digit <= 'F'
? next_digit - 'A' + 10
: (next_digit >= 'a' && next_digit <= 'f'
? next_digit - 'a' + 10
: next_digit - '0'));
bool more_bits = ((next_digit_value & 7) != 0
|| precision + 1 < numend - numstr);
#ifdef HAVE_FENV_H
int rounding_mode = get_rounding_mode ();
do_round_away = round_away (negative, last_digit_value & 1,
next_digit_value >= 8, more_bits,
rounding_mode);
#endif
}
if (precision == -1) if (precision == -1)
precision = numend - numstr; precision = numend - numstr;
else if (precision < numend - numstr else if (do_round_away)
&& (numstr[precision] > '8'
|| (('A' < '0' || 'a' < '0')
&& numstr[precision] < '0')
|| (numstr[precision] == '8'
&& (precision + 1 < numend - numstr
/* Round to even. */
|| (precision > 0
&& ((numstr[precision - 1] & 1)
^ (isdigit (numstr[precision - 1]) == 0)))
|| (precision == 0
&& ((leading & 1)
^ (isdigit (leading) == 0)))))))
{ {
/* Round up. */ /* Round up. */
int cnt = precision; int cnt = precision;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment