Back to index

glibc  2.9
tst-strtod.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991,96,97,98,99,2000,2001,2003 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 #include <ctype.h>
00020 #include <locale.h>
00021 #include <stddef.h>
00022 #include <stdio.h>
00023 #include <stdlib.h>
00024 #include <errno.h>
00025 #include <string.h>
00026 #include <math.h>
00027 
00028 struct ltest
00029   {
00030     const char *str;        /* Convert this.  */
00031     double expect;          /* To get this.  */
00032     char left;                     /* With this left over.  */
00033     int err;                /* And this in errno.  */
00034   };
00035 static const struct ltest tests[] =
00036   {
00037     { "12.345", 12.345, '\0', 0 },
00038     { "12.345e19", 12.345e19, '\0', 0 },
00039     { "-.1e+9", -.1e+9, '\0', 0 },
00040     { ".125", .125, '\0', 0 },
00041     { "1e20", 1e20, '\0', 0 },
00042     { "0e-19", 0, '\0', 0 },
00043     { "4\00012", 4.0, '\0', 0 },
00044     { "5.9e-76", 5.9e-76, '\0', 0 },
00045     { "0x1.4p+3", 10.0, '\0', 0 },
00046     { "0xAp0", 10.0, '\0', 0 },
00047     { "0x0Ap0", 10.0, '\0', 0 },
00048     { "0x0A", 10.0, '\0', 0 },
00049     { "0xA0", 160.0, '\0', 0 },
00050     { "0x0.A0p8", 160.0, '\0', 0 },
00051     { "0x0.50p9", 160.0, '\0', 0 },
00052     { "0x0.28p10", 160.0, '\0', 0 },
00053     { "0x0.14p11", 160.0, '\0', 0 },
00054     { "0x0.0A0p12", 160.0, '\0', 0 },
00055     { "0x0.050p13", 160.0, '\0', 0 },
00056     { "0x0.028p14", 160.0, '\0', 0 },
00057     { "0x0.014p15", 160.0, '\0', 0 },
00058     { "0x00.00A0p16", 160.0, '\0', 0 },
00059     { "0x00.0050p17", 160.0, '\0', 0 },
00060     { "0x00.0028p18", 160.0, '\0', 0 },
00061     { "0x00.0014p19", 160.0, '\0', 0 },
00062     { "0x1p-1023",
00063       1.11253692925360069154511635866620203210960799023116591527666e-308,
00064       '\0', 0 },
00065     { "0x0.8p-1022",
00066       1.11253692925360069154511635866620203210960799023116591527666e-308,
00067       '\0', 0 },
00068 #if __GNUC_PREREQ(2,96)
00069     /* For older GCC release HUGE_VAL is not a constant.  */
00070     { "Inf", HUGE_VAL, '\0', 0 },
00071     { "-Inf", -HUGE_VAL, '\0', 0 },
00072     { "+InFiNiTy", HUGE_VAL, '\0', 0 },
00073 #endif
00074     { "0x80000Ap-23", 0x80000Ap-23, '\0', 0 },
00075     { NULL, 0, '\0', 0 }
00076   };
00077 
00078 static void expand (char *dst, int c);
00079 static int long_dbl (void);
00080 static int locale_test (void);
00081 
00082 int
00083 main (int argc, char ** argv)
00084 {
00085   char buf[100];
00086   register const struct ltest *lt;
00087   char *ep;
00088   int status = 0;
00089   int save_errno;
00090 
00091   for (lt = tests; lt->str != NULL; ++lt)
00092     {
00093       double d;
00094 
00095       errno = 0;
00096       d = strtod(lt->str, &ep);
00097       save_errno = errno;
00098       printf ("strtod (\"%s\") test %u",
00099             lt->str, (unsigned int) (lt - tests));
00100       if (d == lt->expect && *ep == lt->left && save_errno == lt->err)
00101        puts ("\tOK");
00102       else
00103        {
00104          puts ("\tBAD");
00105          if (d != lt->expect)
00106            printf ("  returns %.60g, expected %.60g\n", d, lt->expect);
00107          if (lt->left != *ep)
00108            {
00109              char exp1[5], exp2[5];
00110              expand (exp1, *ep);
00111              expand (exp2, lt->left);
00112              printf ("  leaves '%s', expected '%s'\n", exp1, exp2);
00113            }
00114          if (save_errno != lt->err)
00115            printf ("  errno %d (%s)  instead of %d (%s)\n",
00116                   save_errno, strerror (save_errno),
00117                   lt->err, strerror (lt->err));
00118          status = 1;
00119        }
00120     }
00121 
00122   sprintf (buf, "%f", strtod ("-0.0", NULL));
00123   if (strcmp (buf, "-0.000000") != 0)
00124     {
00125       printf ("  strtod (\"-0.0\", NULL) returns \"%s\"\n", buf);
00126       status = 1;
00127     }
00128 
00129   const char input[] = "3752432815e-39";
00130 
00131   float f1 = strtold (input, NULL);
00132   float f2;
00133   float f3 = strtof (input, NULL);
00134   sscanf (input, "%g", &f2);
00135 
00136   if (f1 != f2)
00137     {
00138       printf ("f1 = %a != f2 = %a\n", f1, f2);
00139       status = 1;
00140     }
00141   if (f1 != f3)
00142     {
00143       printf ("f1 = %a != f3 = %a\n", f1, f3);
00144       status = 1;
00145     }
00146   if (f2 != f3)
00147     {
00148       printf ("f2 = %a != f3 = %a\n", f2, f3);
00149       status = 1;
00150     }
00151 
00152   const char input2[] = "+1.000000000116415321826934814453125";
00153   if (strtold (input2, NULL) != +1.000000000116415321826934814453125L)
00154     {
00155       printf ("input2: %La != %La\n", strtold (input2, NULL),
00156              +1.000000000116415321826934814453125L);
00157       status = 1;
00158     }
00159 
00160   static struct { const char *str; long double l; } ltests[] =
00161     {
00162       { "42.0000000000000000001", 42.0000000000000000001L },
00163       { "42.00000000000000000001", 42.00000000000000000001L },
00164       { "42.000000000000000000001", 42.000000000000000000001L }
00165     };
00166   int n;
00167   for (n = 0; n < sizeof (ltests) / sizeof (ltests[0]); ++n)
00168     if (strtold (ltests[n].str, NULL) != ltests[n].l)
00169       {
00170        printf ("ltests[%d]: %La != %La\n", n,
00171               strtold (ltests[n].str, NULL), ltests[n].l);
00172        status = 1;
00173       }
00174 
00175   status |= long_dbl ();
00176 
00177   status |= locale_test ();
00178 
00179   return status ? EXIT_FAILURE : EXIT_SUCCESS;
00180 }
00181 
00182 static void
00183 expand (dst, c)
00184      char *dst;
00185      register int c;
00186 {
00187   if (isprint (c))
00188     {
00189       dst[0] = c;
00190       dst[1] = '\0';
00191     }
00192   else
00193     (void) sprintf (dst, "%#.3o", (unsigned int) c);
00194 }
00195 
00196 static int
00197 long_dbl (void)
00198 {
00199   /* Regenerate this string using
00200 
00201      echo '(2^53-1)*2^(1024-53)' | bc | sed 's/\([^\]*\)\\*$/    "\1"/'
00202 
00203   */
00204   static const char longestdbl[] =
00205     "17976931348623157081452742373170435679807056752584499659891747680315"
00206     "72607800285387605895586327668781715404589535143824642343213268894641"
00207     "82768467546703537516986049910576551282076245490090389328944075868508"
00208     "45513394230458323690322294816580855933212334827479782620414472316873"
00209     "8177180919299881250404026184124858368";
00210   double d = strtod (longestdbl, NULL);
00211 
00212   printf ("strtod (\"%s\", NULL) = %g\n", longestdbl, d);
00213 
00214   if (d != 179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368.000000)
00215     return 1;
00216 
00217   return 0;
00218 }
00219 
00220 /* Perform a few tests in a locale with thousands separators.  */
00221 static int
00222 locale_test (void)
00223 {
00224   static const struct
00225   {
00226     const char *loc;
00227     const char *str;
00228     double exp;
00229     ptrdiff_t nread;
00230   } tests[] =
00231     {
00232       { "de_DE.UTF-8", "1,5", 1.5, 3 },
00233       { "de_DE.UTF-8", "1.5", 1.0, 1 },
00234       { "de_DE.UTF-8", "1.500", 1500.0, 5 },
00235       { "de_DE.UTF-8", "36.893.488.147.419.103.232", 0x1.0p65, 26 }
00236     };
00237 #define ntests (sizeof (tests) / sizeof (tests[0]))
00238   size_t n;
00239   int result = 0;
00240 
00241   puts ("\nLocale tests");
00242 
00243   for (n = 0; n < ntests; ++n)
00244     {
00245       double d;
00246       char *endp;
00247 
00248       if (setlocale (LC_ALL, tests[n].loc) == NULL)
00249        {
00250          printf ("cannot set locale %s\n", tests[n].loc);
00251          result = 1;
00252          continue;
00253        }
00254 
00255       /* We call __strtod_interal here instead of strtod to tests the
00256         handling of grouping.  */
00257       d = __strtod_internal (tests[n].str, &endp, 1);
00258       if (d != tests[n].exp)
00259        {
00260          printf ("strtod(\"%s\") returns %g and not %g\n",
00261                 tests[n].str, d, tests[n].exp);
00262          result = 1;
00263        }
00264       else if (endp - tests[n].str != tests[n].nread)
00265        {
00266          printf ("strtod(\"%s\") read %td bytes and not %td\n",
00267                 tests[n].str, endp - tests[n].str, tests[n].nread);
00268          result = 1;
00269        }
00270     }
00271 
00272   if (result == 0)
00273     puts ("all OK");
00274 
00275   return result;
00276 }