aboutsummaryrefslogtreecommitdiff
path: root/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c63
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.
**