SQLite

Check-in [8ecffca900]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improved accuracy on text-to-real and real-to-text conversions. Most conversions now round-trip correctly. Still need to fix some corner cases.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | floating-point-conversions
Files: files | file ages | folders
SHA1: 8ecffca900cd6a8922001fd458a266ce8c83fb66
User & Date: drh 2012-06-19 03:11:25.621
Context
2012-06-19
03:35
Round-trip conversions of real->text->real are now lossless on x64 with GCC. Untested on other platforms so far. Still a corner-case problem with round(). (check-in: fd7bd4a593 user: drh tags: floating-point-conversions)
03:11
Improved accuracy on text-to-real and real-to-text conversions. Most conversions now round-trip correctly. Still need to fix some corner cases. (check-in: 8ecffca900 user: drh tags: floating-point-conversions)
00:45
Improved rounding accuracy on text-to-float conversions. (check-in: 699b792c6a user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/func.c.
859
860
861
862
863
864
865
866











867
868
869
870
871
872
873
874
** "NULL".  Otherwise, the argument is enclosed in single quotes with
** single-quote escapes.
*/
static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
  assert( argc==1 );
  UNUSED_PARAMETER(argc);
  switch( sqlite3_value_type(argv[0]) ){
    case SQLITE_INTEGER:











    case SQLITE_FLOAT: {
      sqlite3_result_value(context, argv[0]);
      break;
    }
    case SQLITE_BLOB: {
      char *zText = 0;
      char const *zBlob = sqlite3_value_blob(argv[0]);
      int nBlob = sqlite3_value_bytes(argv[0]);







|
>
>
>
>
>
>
>
>
>
>
>
|







859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
** "NULL".  Otherwise, the argument is enclosed in single quotes with
** single-quote escapes.
*/
static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
  assert( argc==1 );
  UNUSED_PARAMETER(argc);
  switch( sqlite3_value_type(argv[0]) ){
    case SQLITE_FLOAT: {
      double r1, r2;
      r1 = sqlite3_value_double(argv[0]);
      char zBuf[50];
      sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.15g", r1);
      sqlite3AtoF(zBuf, &r2, 20, SQLITE_UTF8);
      if( r1!=r2 ){
        sqlite3_snprintf(sizeof(zBuf), zBuf, "%!.20e", r1);
      }
      sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT);
      break;
    }
    case SQLITE_INTEGER: {
      sqlite3_result_value(context, argv[0]);
      break;
    }
    case SQLITE_BLOB: {
      char *zText = 0;
      char const *zBlob = sqlite3_value_blob(argv[0]);
      int nBlob = sqlite3_value_bytes(argv[0]);
Changes to src/printf.c.
120
121
122
123
124
125
126
127

128
129
130
131
132
133
134
** The counter *cnt is incremented each time.  After counter exceeds
** 16 (the number of significant digits in a 64-bit float) '0' is
** always returned.
*/
static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
  int digit;
  LONGDOUBLE_TYPE d;
  if( (*cnt)++ >= 16 ) return '0';

  digit = (int)*val;
  d = digit;
  digit += '0';
  *val = (*val - d)*10.0;
  return (char)digit;
}
#endif /* SQLITE_OMIT_FLOATING_POINT */







|
>







120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
** The counter *cnt is incremented each time.  After counter exceeds
** 16 (the number of significant digits in a 64-bit float) '0' is
** always returned.
*/
static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
  int digit;
  LONGDOUBLE_TYPE d;
  if( (*cnt)<=0 ) return '0';
  (*cnt)--;
  digit = (int)*val;
  d = digit;
  digit += '0';
  *val = (*val - d)*10.0;
  return (char)digit;
}
#endif /* SQLITE_OMIT_FLOATING_POINT */
424
425
426
427
428
429
430

431
432
433

434
435
436
437
438
439
440
        exp = 0;
        if( sqlite3IsNaN((double)realvalue) ){
          bufpt = "NaN";
          length = 3;
          break;
        }
        if( realvalue>0.0 ){

          while( realvalue>=1e32 && exp<=350 ){ realvalue *= 1e-32; exp+=32; }
          while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; }
          while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; }

          while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
          while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
          if( exp>350 ){
            if( prefix=='-' ){
              bufpt = "-Inf";
            }else if( prefix=='+' ){
              bufpt = "+Inf";







>
|
|
|
>







425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
        exp = 0;
        if( sqlite3IsNaN((double)realvalue) ){
          bufpt = "NaN";
          length = 3;
          break;
        }
        if( realvalue>0.0 ){
          LONGDOUBLE_TYPE scale = 1.0;
          while( realvalue>=1e64*scale && exp<=350 ){ scale *= 1e64; exp+=64; }
          while( realvalue>=1e8*scale && exp<=350 ){ scale *= 1e8; exp+=8; }
          while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
          realvalue /= scale;
          while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
          while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
          if( exp>350 ){
            if( prefix=='-' ){
              bufpt = "-Inf";
            }else if( prefix=='+' ){
              bufpt = "+Inf";
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
          if( exp<-4 || exp>precision ){
            xtype = etEXP;
          }else{
            precision = precision - exp;
            xtype = etFLOAT;
          }
        }else{
          flag_rtz = 0;
        }
        if( xtype==etEXP ){
          e2 = 0;
        }else{
          e2 = exp;
        }
        if( e2+precision+width > etBUFSIZE - 15 ){
          bufpt = zExtra = sqlite3Malloc( e2+precision+width+15 );
          if( bufpt==0 ){
            pAccum->mallocFailed = 1;
            return;
          }
        }
        zOut = bufpt;
        nsd = 0;
        flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
        /* The sign in front of the number */
        if( prefix ){
          *(bufpt++) = prefix;
        }
        /* Digits prior to the decimal point */
        if( e2<0 ){







|














|







462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
          if( exp<-4 || exp>precision ){
            xtype = etEXP;
          }else{
            precision = precision - exp;
            xtype = etFLOAT;
          }
        }else{
          flag_rtz = flag_altform2;
        }
        if( xtype==etEXP ){
          e2 = 0;
        }else{
          e2 = exp;
        }
        if( e2+precision+width > etBUFSIZE - 15 ){
          bufpt = zExtra = sqlite3Malloc( e2+precision+width+15 );
          if( bufpt==0 ){
            pAccum->mallocFailed = 1;
            return;
          }
        }
        zOut = bufpt;
        nsd = 16 + flag_altform2*10;
        flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
        /* The sign in front of the number */
        if( prefix ){
          *(bufpt++) = prefix;
        }
        /* Digits prior to the decimal point */
        if( e2<0 ){
Changes to test/atof1.test.
13
14
15
16
17
18
19
20
21
22
23





24
25
26
27
28
29
30




















31
32
33
34
35
36
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

expr srand(1)
for {set i 1} {$i<10000} {incr i} {
  do_test 1.$i {
    set pow [expr {int((rand()-0.5)*100)}]
    set x [expr {pow((rand()-0.5)*2*rand(),$pow)}]
    set xf [format %.45e $x]





    set y [db eval "SELECT $xf=\$x"]
    if {!$y} {
      puts -nonewline \173[db eval "SELECT real2hex($xf), real2hex(\$x)"]\175
      db eval "SELECT $xf+0.0 AS a, \$x AS b" {
        puts [format "\n%.60e\n%.60e\n%.60e" $x $a $b]
      }
    }




















    set y
  } {1}
}


finish_test







<
|
|
|
>
>
>
>
>







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






13
14
15
16
17
18
19

20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl

expr srand(1)
for {set i 1} {$i<10000} {incr i} {

  set pow [expr {int((rand()-0.5)*100)}]
  set x [expr {pow((rand()-0.5)*2*rand(),$pow)}]
  set xf [format %.32e $x]

  # Verify that text->real conversions get exactly same ieee754 floating-
  # point value in SQLite as they do in TCL.
  #
  do_test 1.$i.1 {
    set y [db eval "SELECT $xf=\$x"]
    if {!$y} {
      puts -nonewline \173[db eval "SELECT real2hex($xf), real2hex(\$x)"]\175
      db eval "SELECT $xf+0.0 AS a, \$x AS b" {
        puts [format "\n%.60e\n%.60e\n%.60e" $x $a $b]
      }
    }
    set y
  } {1}

  # FIX ME.  The following tests (real->text->real round-trips) sometimes
  # fail for large floating-point values.  Skip them for now...
  #
  if {abs($x)>1e50} continue

  # Verify that round-trip real->text->real conversions using the quote()
  # function preserve the bits of the numeric value exactly.
  #
  do_test 1.$i.2 {
    set y [db eval {SELECT $x=CAST(quote($x) AS real)}]
    if {!$y} {
      db eval {SELECT real2hex($x) a, real2hex(CAST(quote($x) AS real)) b} {}
      puts "\nIN:    $a $xf"
      puts [format {QUOTE: %16s %s} {} [db eval {SELECT quote($x)}]]
      db eval {SELECT CAST(quote($x) AS real) c} {}
      puts "OUT:   $b [format %.32e $c]"
    }
    set y
  } {1}
}


finish_test
Changes to test/date.test.
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
datetest 2.51 {datetime('2003-10-22 12:24','nonsense')} NULL

datetest 3.1 {strftime('%d','2003-10-31 12:34:56.432')} 31
datetest 3.2.1 {strftime('pre%fpost','2003-10-31 12:34:56.432')} pre56.432post
datetest 3.2.2 {strftime('%f','2003-10-31 12:34:59.9999999')} 59.999
datetest 3.3 {strftime('%H','2003-10-31 12:34:56.432')} 12
datetest 3.4 {strftime('%j','2003-10-31 12:34:56.432')} 304
datetest 3.5 {strftime('%J','2003-10-31 12:34:56.432')} 2452944.02426426
datetest 3.6 {strftime('%m','2003-10-31 12:34:56.432')} 10
datetest 3.7 {strftime('%M','2003-10-31 12:34:56.432')} 34
datetest 3.8.1 {strftime('%s','2003-10-31 12:34:56.432')} 1067603696
datetest 3.8.2 {strftime('%s','2038-01-19 03:14:07')} 2147483647
datetest 3.8.3 {strftime('%s','2038-01-19 03:14:08')} 2147483648
datetest 3.8.4 {strftime('%s','2201-04-09 12:00:00')} 7298164800
datetest 3.8.5 {strftime('%s','9999-12-31 23:59:59')} 253402300799







|







147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
datetest 2.51 {datetime('2003-10-22 12:24','nonsense')} NULL

datetest 3.1 {strftime('%d','2003-10-31 12:34:56.432')} 31
datetest 3.2.1 {strftime('pre%fpost','2003-10-31 12:34:56.432')} pre56.432post
datetest 3.2.2 {strftime('%f','2003-10-31 12:34:59.9999999')} 59.999
datetest 3.3 {strftime('%H','2003-10-31 12:34:56.432')} 12
datetest 3.4 {strftime('%j','2003-10-31 12:34:56.432')} 304
datetest 3.5 {strftime('%J','2003-10-31 12:34:56.432')} 2452944.024264259
datetest 3.6 {strftime('%m','2003-10-31 12:34:56.432')} 10
datetest 3.7 {strftime('%M','2003-10-31 12:34:56.432')} 34
datetest 3.8.1 {strftime('%s','2003-10-31 12:34:56.432')} 1067603696
datetest 3.8.2 {strftime('%s','2038-01-19 03:14:07')} 2147483647
datetest 3.8.3 {strftime('%s','2038-01-19 03:14:08')} 2147483648
datetest 3.8.4 {strftime('%s','2201-04-09 12:00:00')} 7298164800
datetest 3.8.5 {strftime('%s','9999-12-31 23:59:59')} 253402300799