nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

grisu3_test.c (4678B)


      1 #include <inttypes.h>
      2 #include <string.h>
      3 #include <stdio.h>
      4 
      5 #include "grisu3_parse.h"
      6 #include "grisu3_print.h"
      7 
      8 #define TEST(x, s) do {                                                     \
      9         if (!(x)) {                                                         \
     10             fprintf(stderr,                                                 \
     11                 "fail: %s\n"                                                \
     12                 "    input: %s\n"                                           \
     13                 "    expected: %.17g\n"                                     \
     14                 "    got: %.17g\n"                                          \
     15                 "    binary xor: 0x%016"PRId64"\n",                         \
     16                 s, buf, expect, v, (a ^ b));                                \
     17             return 1;                                                       \
     18         }                                                                   \
     19     } while (0)
     20 
     21 static int test_parse_double(char *buf)
     22 {
     23     const char *k, *end;
     24     double v, expect;
     25     uint64_t a = 0, b = 0;
     26     int len = strlen(buf);
     27 
     28     end = buf + len;
     29 
     30     expect = strtod(buf, 0);
     31     /* Include '\0' in bytes being parsed to make strtod safe. */
     32     k = grisu3_parse_double(buf, len, &v);
     33 
     34     /* Make sure we parsed and accepted everything. */
     35     TEST(k == end, "didn't parse to end");
     36 
     37     a = grisu3_cast_uint64_from_double(expect);
     38     b = grisu3_cast_uint64_from_double(v);
     39 
     40 #ifdef GRISU3_PARSE_ALLOW_ERROR
     41     /*
     42      * Just where exponent wraps, this assumption will be incorrect.
     43      * TODO: need next higher double function.
     44      */
     45     TEST(a - b <= 1, "binary representation differs by more than lsb");
     46 #else
     47     /* Binary comparison should match. */
     48     TEST(expect == v, "double representation differs");
     49     TEST(a == b, "binary representation differs");
     50 #endif
     51 
     52 #if 0
     53     /* This will print the test data also when correct. */
     54     TEST(0, "test case passed, just debugging");
     55 #endif
     56 
     57     return 0;
     58 }
     59 
     60 /*
     61  * We currently do not test grisu3_print_double because
     62  * it is a direct port of dtoa_grisu3 from grisu3.c
     63  * which presumably has been tested in MathGeoLib.
     64  *
     65  * grisu3_parse_double is a new implementation.
     66  */
     67 int test_suite()
     68 {
     69     char buf[50];
     70     int fail = 0;
     71 
     72     fail += test_parse_double("1.23434");
     73     fail += test_parse_double("1234.34");
     74     fail += test_parse_double("1234.34e4");
     75     fail += test_parse_double("1234.34e-4");
     76     fail += test_parse_double("1.23434E+4");
     77     fail += test_parse_double("3.2897984798741413E+194");
     78     fail += test_parse_double("-3.2897984798741413E-194");
     79 
     80     sprintf(buf, "3289798479874141.314124124128497098e109");
     81     fail += test_parse_double(buf);
     82     sprintf(buf, "3289798479874141.314124124128497098e209");
     83     fail += test_parse_double(buf);
     84     sprintf(buf, "-3289798479874141.314124124128497098e209");
     85     fail += test_parse_double(buf);
     86     sprintf(buf, "3289798479874141.314124124128497098e+209");
     87     fail += test_parse_double(buf);
     88     sprintf(buf, "-3289798479874141.314124124128497098e-209");
     89     fail += test_parse_double(buf);
     90 
     91     return fail;
     92 }
     93 
     94 void example()
     95 {
     96     double v;
     97     const char *buf = "1234.34e-4";
     98     const char *x, *end;
     99     char result_buf[50];
    100     int len;
    101 
    102     fprintf(stderr, "grisu3_parse_double example:\n  parsing '%s' as double\n", buf);
    103     /* A non-numeric terminator (e.g. '\0') is required to ensure strtod fallback is safe. */
    104     len = strlen(buf);
    105     end = buf + len;
    106     x = grisu3_parse_double(buf, len, &v);
    107     if (x == 0) {
    108         fprintf(stderr, "syntax or range error\n");
    109     } else if (x == buf) {
    110         fprintf(stderr, "parse double failed\n");
    111     } else if (x != end) {
    112         fprintf(stderr, "parse double did not read everything\n");
    113     } else {
    114         fprintf(stderr, "got: %.17g\n", v);
    115     }
    116     /*
    117      * TODO: with the current example: the input "0.123434" is printed
    118      * as "1.23434e-1" which is sub-optimal and different from sprintf.
    119      *
    120      * This is not the grisu3 algorithm but a post formatting step
    121      * in grisu3_print_double (originally dtoa_grisu) and may be a bug
    122      * in the logic choosing the best print format.
    123      * sprintf "%.17g" and "%g" both print as "0.123434"
    124      */
    125     fprintf(stderr, "grisu3_print_double example:\n  printing %g\n", v);
    126     grisu3_print_double(v, result_buf);
    127     fprintf(stderr, "got: %s\n", result_buf);
    128 }
    129 
    130 int main()
    131 {
    132     example();
    133     fprintf(stderr, "running tests\n");
    134     if (test_suite()) {
    135         fprintf(stderr, "GRISU3 PARSE TEST FAILED\n");
    136         return -1;
    137     } else {
    138         fprintf(stderr, "GRISU3 PARSE TEST PASSED\n");
    139         return 0;
    140     }
    141 }