diff options
author | drh <> | 2023-06-30 18:35:43 +0000 |
---|---|---|
committer | drh <> | 2023-06-30 18:35:43 +0000 |
commit | a1b0ff173520fc73a182e57b06b1d0228b343711 (patch) | |
tree | 5f2283b7e1e6d2e93076869fcdd955104256862c /src/util.c | |
parent | 24b368da8dac15cb7d3997ae4fa27d76f0fc682a (diff) | |
download | sqlite-a1b0ff173520fc73a182e57b06b1d0228b343711.tar.gz sqlite-a1b0ff173520fc73a182e57b06b1d0228b343711.zip |
Experiments with a new algorithm for converting ieee-754 binary64 numbers
into decimal.
FossilOrigin-Name: e923405e448385085224f9289991b303d86b02763535ea77d6fcee98ba6fc1f2
Diffstat (limited to 'src/util.c')
-rw-r--r-- | src/util.c | 63 |
1 files changed, 63 insertions, 0 deletions
diff --git a/src/util.c b/src/util.c index abd36eda8..29bc8524d 100644 --- a/src/util.c +++ b/src/util.c @@ -929,6 +929,69 @@ int sqlite3Atoi(const char *z){ } /* +** Decode a floating-point value into an approximate decimal +** representation. +*/ +void sqlite3FpDecode(FpDecode *p, double r){ + int i; + u64 v; + int e, exp = 0; + if( r<0.0 ){ + p->sign = '-'; + r = -r; + }else if( r==0.0 ){ + p->sign = '+'; + p->n = 1; + p->iDP = 1; + p->z[0] = '0'; + return; + }else{ + p->sign = '+'; + } + memcpy(&v,&r,8); + e = v>>52; + if( e==0x7ff ){ + if( v==0x7ff0000000000000L ){ + p->isInf = 1; + p->isNan = 0; + p->z[0] = 'I'; + p->z[1] = 'n'; + p->z[2] = 'f'; + }else{ + p->isInf = 0; + p->isNan = 1; + p->z[0] = 'N'; + p->z[1] = 'a'; + p->z[2] = 'N'; + } + p->n = 3; + p->iDP = 3; + return; + } + /* At this point, r is positive (non-zero) and is not Inf or NaN. + ** The strategy is to multiple or divide r by powers of 10 until + ** it is in between 1.0e+17 and 1.0e+19. Then convert r into + ** an unsigned 64-bit integer v, and extract digits from v. + */ + if( r>=1.0e+19 ){ + while( r>=1.0e+119 ){ exp+=100; r /= 1.0e+100; } + while( r>=1.0e+29 ){ exp+=10; r /= 1.0e+10; } + while( r>=1.0e+19 ){ exp++; r /= 10.0; } + }else if( r<1.0e+17 ){ + while( r<1.0e-97 ){ exp-=100; r *= 1.0e+100; } + while( r<1.0e+07 ){ exp-=10; r *= 1.0e+10; } + while( r<1.0e+17 ){ exp--; r *= 10.0; } + } + v = (u64)r; + i = sizeof(p->z); + while( v ){ p->z[i--] = (v%10) + '0'; v /= 10; } + p->n = sizeof(p->z) - i; + p->iDP = p->n + exp; + memmove(p->z, &p->z[i+1], p->n); + while( p->n>0 && p->z[p->n-1]=='0' ){ p->n--; } +} + +/* ** Try to convert z into an unsigned 32-bit integer. Return true on ** success and false if there is an error. ** |