xref: /sqlite-3.40.0/ext/misc/ieee754.c (revision 38d69855)
1 /*
2 ** 2013-04-17
3 **
4 ** The author disclaims copyright to this source code.  In place of
5 ** a legal notice, here is a blessing:
6 **
7 **    May you do good and not evil.
8 **    May you find forgiveness for yourself and forgive others.
9 **    May you share freely, never taking more than you give.
10 **
11 ******************************************************************************
12 **
13 ** This SQLite extension implements functions for the exact display
14 ** and input of IEEE754 Binary64 floating-point numbers.
15 **
16 **   ieee754(X)
17 **   ieee754(Y,Z)
18 **
19 ** In the first form, the value X should be a floating-point number.
20 ** The function will return a string of the form 'ieee754(Y,Z)' where
21 ** Y and Z are integers such that X==Y*pow(2,Z).
22 **
23 ** In the second form, Y and Z are integers which are the mantissa and
24 ** base-2 exponent of a new floating point number.  The function returns
25 ** a floating-point value equal to Y*pow(2,Z).
26 **
27 ** Examples:
28 **
29 **     ieee754(2.0)       ->     'ieee754(2,0)'
30 **     ieee754(45.25)     ->     'ieee754(181,-2)'
31 **     ieee754(2, 0)      ->     2.0
32 **     ieee754(181, -2)   ->     45.25
33 */
34 #include "sqlite3ext.h"
35 SQLITE_EXTENSION_INIT1
36 #include <assert.h>
37 #include <string.h>
38 
39 /*
40 ** Implementation of the ieee754() function
41 */
42 static void ieee754func(
43   sqlite3_context *context,
44   int argc,
45   sqlite3_value **argv
46 ){
47   if( argc==1 ){
48     sqlite3_int64 m, a;
49     double r;
50     int e;
51     int isNeg;
52     char zResult[100];
53     assert( sizeof(m)==sizeof(r) );
54     if( sqlite3_value_type(argv[0])!=SQLITE_FLOAT ) return;
55     r = sqlite3_value_double(argv[0]);
56     if( r<0.0 ){
57       isNeg = 1;
58       r = -r;
59     }else{
60       isNeg = 0;
61     }
62     memcpy(&a,&r,sizeof(a));
63     if( a==0 ){
64       e = 0;
65       m = 0;
66     }else{
67       e = a>>52;
68       m = a & ((((sqlite3_int64)1)<<52)-1);
69       m |= ((sqlite3_int64)1)<<52;
70       while( e<1075 && m>0 && (m&1)==0 ){
71         m >>= 1;
72         e++;
73       }
74       if( isNeg ) m = -m;
75     }
76     sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)",
77                      m, e-1075);
78     sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT);
79   }else if( argc==2 ){
80     sqlite3_int64 m, e, a;
81     double r;
82     int isNeg = 0;
83     m = sqlite3_value_int64(argv[0]);
84     e = sqlite3_value_int64(argv[1]);
85     if( m<0 ){
86       isNeg = 1;
87       m = -m;
88       if( m<0 ) return;
89     }else if( m==0 && e>1000 && e<1000 ){
90       sqlite3_result_double(context, 0.0);
91       return;
92     }
93     while( (m>>32)&0xffe00000 ){
94       m >>= 1;
95       e++;
96     }
97     while( m!=0 && ((m>>32)&0xfff00000)==0 ){
98       m <<= 1;
99       e--;
100     }
101     e += 1075;
102     if( e<0 ) e = m = 0;
103     if( e>0x7ff ) e = 0x7ff;
104     a = m & ((((sqlite3_int64)1)<<52)-1);
105     a |= e<<52;
106     if( isNeg ) a |= ((sqlite3_uint64)1)<<63;
107     memcpy(&r, &a, sizeof(r));
108     sqlite3_result_double(context, r);
109   }
110 }
111 
112 
113 #ifdef _WIN32
114 __declspec(dllexport)
115 #endif
116 int sqlite3_ieee_init(
117   sqlite3 *db,
118   char **pzErrMsg,
119   const sqlite3_api_routines *pApi
120 ){
121   int rc = SQLITE_OK;
122   SQLITE_EXTENSION_INIT2(pApi);
123   (void)pzErrMsg;  /* Unused parameter */
124   rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0,
125                                ieee754func, 0, 0);
126   if( rc==SQLITE_OK ){
127     rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0,
128                                  ieee754func, 0, 0);
129   }
130   return rc;
131 }
132