Index: src/func.c ================================================================== --- src/func.c +++ src/func.c @@ -861,12 +861,23 @@ */ 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: { + double r1, r2; + char zBuf[50]; + r1 = sqlite3_value_double(argv[0]); + 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; Index: src/printf.c ================================================================== --- src/printf.c +++ src/printf.c @@ -122,11 +122,12 @@ ** always returned. */ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ int digit; LONGDOUBLE_TYPE d; - if( (*cnt)++ >= 16 ) return '0'; + if( (*cnt)<=0 ) return '0'; + (*cnt)--; digit = (int)*val; d = digit; digit += '0'; *val = (*val - d)*10.0; return (char)digit; @@ -426,13 +427,16 @@ 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++; } + LONGDOUBLE_TYPE scale = 1.0; + while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;} + 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"; @@ -461,11 +465,11 @@ }else{ precision = precision - exp; xtype = etFLOAT; } }else{ - flag_rtz = 0; + flag_rtz = flag_altform2; } if( xtype==etEXP ){ e2 = 0; }else{ e2 = exp; @@ -476,11 +480,11 @@ pAccum->mallocFailed = 1; return; } } zOut = bufpt; - nsd = 0; + 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; } Index: src/test_config.c ================================================================== --- src/test_config.c +++ src/test_config.c @@ -614,10 +614,25 @@ { static const int cv_TEMP_STORE = SQLITE_TEMP_STORE; Tcl_LinkVar(interp, "TEMP_STORE", (char *)&(cv_TEMP_STORE), TCL_LINK_INT | TCL_LINK_READ_ONLY); } + +#ifdef _MSC_VER + { + static const int cv__MSC_VER = 1; + Tcl_LinkVar(interp, "_MSC_VER", (char *)&(cv__MSC_VER), + TCL_LINK_INT | TCL_LINK_READ_ONLY); + } +#endif +#ifdef __GNUC__ + { + static const int cv___GNUC__ = 1; + Tcl_LinkVar(interp, "__GNUC__", (char *)&(cv___GNUC__), + TCL_LINK_INT | TCL_LINK_READ_ONLY); + } +#endif } /* ** Register commands with the TCL interpreter. Index: test/atof1.test ================================================================== --- test/atof1.test +++ test/atof1.test @@ -12,24 +12,48 @@ # Tests of the sqlite3AtoF() function. # set testdir [file dirname $argv0] source $testdir/tester.tcl + +if {![info exists __GNUC__]} { + finish_test + return +} 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] +for {set i 1} {$i<20000} {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 atof1-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} + + # Verify that round-trip real->text->real conversions using the quote() + # function preserve the bits of the numeric value exactly. + # + do_test atof1-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} } Index: test/date.test ================================================================== --- test/date.test +++ test/date.test @@ -149,11 +149,11 @@ 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.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 Index: test/func.test ================================================================== --- test/func.test +++ test/func.test @@ -310,11 +310,11 @@ } {99999999999995.0} do_test func-4.37 { execsql {SELECT round(9999999999999.55,1);} } {9999999999999.6} do_test func-4.38 { - execsql {SELECT round(9999999999999.555,2);} + execsql {SELECT round(9999999999999.556,2);} } {9999999999999.56} } # Test the upper() and lower() functions #