1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-11 01:42:22 +03:00

Experiments with a new algorithm for converting ieee-754 binary64 numbers

into decimal.

FossilOrigin-Name: e923405e448385085224f9289991b303d86b02763535ea77d6fcee98ba6fc1f2
This commit is contained in:
drh
2023-06-30 18:35:43 +00:00
parent 24b368da8d
commit a1b0ff1735
5 changed files with 113 additions and 11 deletions

View File

@@ -928,6 +928,69 @@ int sqlite3Atoi(const char *z){
return x;
}
/*
** 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.