aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <>2024-12-07 19:06:25 +0000
committerdrh <>2024-12-07 19:06:25 +0000
commit8703642803df6dc3920239ed85654e92b4cc5451 (patch)
treed9d4fdbd8a9e844ceec94b386ac2db242b99b5b4 /src
parent92d252e06db3fcfb06e5d3f45f4aa6f5e0c7cedc (diff)
downloadsqlite-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.c17
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;