[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Bash floating-point printf floating-point precision improvement
From: |
Paul Eggert |
Subject: |
Bash floating-point printf floating-point precision improvement |
Date: |
Mon, 19 Nov 2001 15:46:23 -0800 (PST) |
Configuration Information [Automatically generated, do not change]:
Machine: i686
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i686'
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i686-pc-linux-gnu'
-DCONF_VENDOR='pc' -DSHELL -DHAVE_CONFIG_H -I. -I.. -I../include -I../lib -g
-O2
uname output: Linux dum.twinsun.com 2.2.18ss.e820-bda652a #4 SMP Tue Jun 5
11:24:08 PDT 2001 i686 unknown
Machine Type: i686-pc-linux-gnu
Bash Version: 2.05a
Patch Level: 0
Release Status: release
Description:
Bash's printf builtin always uses 'long int' to print integers
(or 'intmax_t', the widest available integer type, assuming my
earlier patches of today are installed).
For consistency, Bash's printf should also use the widest
available floating-point type to format floating-point
numbers. This will yield more precise results, and it won't
cost much CPU as the code is so rarely used. Also, this
simplifies the code a bit.
Repeat-By:
$ printf '%.17g\n' 0.1
0.10000000000000001
$ printf '%g\n' 1e-321
9.98013e-322
$ printf '%g\n' 1e400
bash: printf: warning: 1e400: Numerical result out of range
inf
With the patch below, the outputs are "0.1", "1e-321", and
"1e+400" respectively; these outputs are more precise and are
more what a naive user would expect.
Fix:
2001-11-19 Paul Eggert <eggert@twinsun.com>
* builtins/printf.def (getdouble, getldouble): Remove, replacing with:
(getfloatmax): New function.
(FLOATMAX_CONV): New macro.
(floatmax): New type decl.
(printf_builtin): Always convert floating-point values using
the widest available floating-point type. This makes the code
more consistent with integer printing, and generates more precise
results on many platforms.
===================================================================
RCS file: builtins/printf.def,v
retrieving revision 2.5.1.4.0.2
retrieving revision 2.5.1.4.0.3
diff -pc -r2.5.1.4.0.2 -r2.5.1.4.0.3
*** builtins/printf.def 2001/11/19 18:06:21 2.5.1.4.0.2
--- builtins/printf.def 2001/11/19 23:40:57 2.5.1.4.0.3
*************** static char *getstr __P((void));
*** 112,121 ****
static int getint __P((void));
static intmax_t getintmax __P((void));
static uintmax_t getuintmax __P((void));
- static double getdouble __P((void));
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD
! static long double getldouble __P((void));
#endif
static int asciicode __P((void));
static WORD_LIST *garglist;
--- 112,127 ----
static int getint __P((void));
static intmax_t getintmax __P((void));
static uintmax_t getuintmax __P((void));
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD
! typedef long double floatmax;
! # define FLOATMAX_CONV "L"
! # define string_to_floatmax strtold
! #else
! typedef double floatmax;
! # define FLOATMAX_CONV ""
! # define string_to_floatmax strtod
#endif
+ static floatmax getfloatmax __P((void));
static int asciicode __P((void));
static WORD_LIST *garglist;
*************** printf_builtin (list)
*** 386,409 ****
#endif
{
char *f;
! #if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD
! if (thisch == 'L')
! {
! long double p;
!
! p = getldouble ();
! f = mklong (start, "L", 1);
! PF (f, p);
! }
! else
! #endif
! {
! double p;
! p = getdouble ();
! f = mklong (start, "", 0);
! PF (f, p);
! }
break;
}
--- 392,402 ----
#endif
{
char *f;
! floatmax p;
! p = getfloatmax ();
! f = mklong (start, FLOATMAX_CONV, sizeof FLOATMAX_CONV - 1);
! PF (f, p);
break;
}
*************** getuintmax ()
*** 812,821 ****
return (ret);
}
! static double
! getdouble ()
{
! double ret;
char *ep;
if (garglist == 0)
--- 805,814 ----
return (ret);
}
! static floatmax
! getfloatmax ()
{
! floatmax ret;
char *ep;
if (garglist == 0)
*************** getdouble ()
*** 825,861 ****
return asciicode ();
errno = 0;
! ret = strtod (garglist->word->word, &ep);
!
! if (*ep)
! {
! builtin_error ("%s: invalid number", garglist->word->word);
! /* Same thing about POSIX.2 conversion error requirements. */
! ret = 0;
! conversion_error = 1;
! }
! else if (errno == ERANGE)
! builtin_error ("warning: %s: %s", garglist->word->word, strerror(ERANGE));
!
! garglist = garglist->next;
! return (ret);
! }
!
! #if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD
! static long double
! getldouble ()
! {
! long double ret;
! char *ep;
!
! if (garglist == 0)
! return (0);
!
! if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
! return (asciicode ());
!
! errno = 0;
! ret = strtold (garglist->word->word, &ep);
if (*ep)
{
--- 818,824 ----
return asciicode ();
errno = 0;
! ret = string_to_floatmax (garglist->word->word, &ep);
if (*ep)
{
*************** getldouble ()
*** 870,876 ****
garglist = garglist->next;
return (ret);
}
- #endif /* HAVE_LONG_DOUBLE && HAVE_DECL_STRTOLD */
/* NO check is needed for garglist here. */
static int
--- 833,838 ----
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Bash floating-point printf floating-point precision improvement,
Paul Eggert <=