diff options
author | drh <> | 2024-12-07 19:06:25 +0000 |
---|---|---|
committer | drh <> | 2024-12-07 19:06:25 +0000 |
commit | 8703642803df6dc3920239ed85654e92b4cc5451 (patch) | |
tree | d9d4fdbd8a9e844ceec94b386ac2db242b99b5b4 /src | |
parent | 92d252e06db3fcfb06e5d3f45f4aa6f5e0c7cedc (diff) | |
download | sqlite-8703642803df6dc3920239ed85654e92b4cc5451.tar.gz sqlite-8703642803df6dc3920239ed85654e92b4cc5451.zip |
A cleaner and more robust solution to the floating-point conversion problem
originally fixed by [81342fa6dd03fffb].
FossilOrigin-Name: 351de57f80b73045448c71d3402d877ff5d72418b1f5fc34c8147a04f7c5cb78
Diffstat (limited to 'src')
-rw-r--r-- | src/util.c | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/src/util.c b/src/util.c index bb676c5fb..e134f7a7d 100644 --- a/src/util.c +++ b/src/util.c @@ -539,6 +539,7 @@ int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){ int eValid = 1; /* True exponent is either not used or is well-formed */ int nDigit = 0; /* Number of digits processed */ int eType = 1; /* 1: pure integer, 2+: fractional -1 or less: bad UTF16 */ + u64 s2; /* round-tripped significand */ double rr[2]; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); @@ -652,16 +653,16 @@ do_atof_calc: } rr[0] = (double)s; - if( s<(LARGEST_UINT64-0x7ff) ){ - u64 s2 = (u64)rr[0]; -#if defined(_MSC_VER) && _MSC_VER<1700 - if( s2==0x8000000000000000LL ){ s2 = 2*(u64)(0.5*rr[0]); } -#endif - rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); - }else{ + s2 = (u64)rr[0]; + rr[1] = s>=s2 ? (double)(s - s2) : -(double)(s2 - s); + if( rr[1]>1e-10*rr[0] ){ + /* On some floating-point processing units, doing the round + ** trip from u64 to double back to u64 can give a wonky value + ** when the original u64 is close to LARGEST_UINT64. If we + ** did get an overly large error value, just set it to zero. */ rr[1] = 0.0; } - + if( e>0 ){ while( e>=100 ){ e -= 100; |