132 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			132 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
| ** 2013-04-17
 | |
| **
 | |
| ** The author disclaims copyright to this source code.  In place of
 | |
| ** a legal notice, here is a blessing:
 | |
| **
 | |
| **    May you do good and not evil.
 | |
| **    May you find forgiveness for yourself and forgive others.
 | |
| **    May you share freely, never taking more than you give.
 | |
| **
 | |
| ******************************************************************************
 | |
| **
 | |
| ** This SQLite extension implements functions for the exact display
 | |
| ** and input of IEEE754 Binary64 floating-point numbers.
 | |
| **
 | |
| **   ieee754(X)
 | |
| **   ieee754(Y,Z)
 | |
| **
 | |
| ** In the first form, the value X should be a floating-point number.
 | |
| ** The function will return a string of the form 'ieee754(Y,Z)' where
 | |
| ** Y and Z are integers such that X==Y*pow(2,Z).
 | |
| **
 | |
| ** In the second form, Y and Z are integers which are the mantissa and
 | |
| ** base-2 exponent of a new floating point number.  The function returns
 | |
| ** a floating-point value equal to Y*pow(2,Z).
 | |
| **
 | |
| ** Examples:
 | |
| **
 | |
| **     ieee754(2.0)       ->     'ieee754(2,0)'
 | |
| **     ieee754(45.25)     ->     'ieee754(181,-2)'
 | |
| **     ieee754(2, 0)      ->     2.0
 | |
| **     ieee754(181, -2)   ->     45.25
 | |
| */
 | |
| #include "sqlite3ext.h"
 | |
| SQLITE_EXTENSION_INIT1
 | |
| #include <assert.h>
 | |
| #include <string.h>
 | |
| 
 | |
| /*
 | |
| ** Implementation of the ieee754() function
 | |
| */
 | |
| static void ieee754func(
 | |
|   sqlite3_context *context,
 | |
|   int argc,
 | |
|   sqlite3_value **argv
 | |
| ){
 | |
|   if( argc==1 ){
 | |
|     sqlite3_int64 m, a;
 | |
|     double r;
 | |
|     int e;
 | |
|     int isNeg;
 | |
|     char zResult[100];
 | |
|     assert( sizeof(m)==sizeof(r) );
 | |
|     if( sqlite3_value_type(argv[0])!=SQLITE_FLOAT ) return;
 | |
|     r = sqlite3_value_double(argv[0]);
 | |
|     if( r<0.0 ){
 | |
|       isNeg = 1;
 | |
|       r = -r;
 | |
|     }else{
 | |
|       isNeg = 0;
 | |
|     }
 | |
|     memcpy(&a,&r,sizeof(a));
 | |
|     if( a==0 ){
 | |
|       e = 0;
 | |
|       m = 0;
 | |
|     }else{
 | |
|       e = a>>52;
 | |
|       m = a & ((((sqlite3_int64)1)<<52)-1);
 | |
|       m |= ((sqlite3_int64)1)<<52;
 | |
|       while( e<1075 && m>0 && (m&1)==0 ){
 | |
|         m >>= 1;
 | |
|         e++;
 | |
|       }
 | |
|       if( isNeg ) m = -m;
 | |
|     }
 | |
|     sqlite3_snprintf(sizeof(zResult), zResult, "ieee754(%lld,%d)",
 | |
|                      m, e-1075);
 | |
|     sqlite3_result_text(context, zResult, -1, SQLITE_TRANSIENT);
 | |
|   }else if( argc==2 ){
 | |
|     sqlite3_int64 m, e, a;
 | |
|     double r;
 | |
|     int isNeg = 0;
 | |
|     m = sqlite3_value_int64(argv[0]);
 | |
|     e = sqlite3_value_int64(argv[1]);
 | |
|     if( m<0 ){
 | |
|       isNeg = 1;
 | |
|       m = -m;
 | |
|       if( m<0 ) return;
 | |
|     }else if( m==0 && e>1000 && e<1000 ){
 | |
|       sqlite3_result_double(context, 0.0);
 | |
|       return;
 | |
|     }
 | |
|     while( (m>>32)&0xffe00000 ){
 | |
|       m >>= 1;
 | |
|       e++;
 | |
|     }
 | |
|     while( m!=0 && ((m>>32)&0xfff00000)==0 ){
 | |
|       m <<= 1;
 | |
|       e--;
 | |
|     }
 | |
|     e += 1075;
 | |
|     if( e<0 ) e = m = 0;
 | |
|     if( e>0x7ff ) e = 0x7ff;
 | |
|     a = m & ((((sqlite3_int64)1)<<52)-1);
 | |
|     a |= e<<52;
 | |
|     if( isNeg ) a |= ((sqlite3_uint64)1)<<63;
 | |
|     memcpy(&r, &a, sizeof(r));
 | |
|     sqlite3_result_double(context, r);
 | |
|   }
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef _WIN32
 | |
| __declspec(dllexport)
 | |
| #endif
 | |
| int sqlite3_ieee_init(
 | |
|   sqlite3 *db, 
 | |
|   char **pzErrMsg, 
 | |
|   const sqlite3_api_routines *pApi
 | |
| ){
 | |
|   int rc = SQLITE_OK;
 | |
|   SQLITE_EXTENSION_INIT2(pApi);
 | |
|   (void)pzErrMsg;  /* Unused parameter */
 | |
|   rc = sqlite3_create_function(db, "ieee754", 1, SQLITE_UTF8, 0,
 | |
|                                ieee754func, 0, 0);
 | |
|   if( rc==SQLITE_OK ){
 | |
|     rc = sqlite3_create_function(db, "ieee754", 2, SQLITE_UTF8, 0,
 | |
|                                  ieee754func, 0, 0);
 | |
|   }
 | |
|   return rc;
 | |
| }
 | 
