4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
11 *************************************************************************
12 ** This file contains a simple command-line utility for converting from
13 ** integers and LogEst values and back again and for doing simple
14 ** arithmetic operations (multiple and add) on LogEst values.
20 ** See the showHelp() routine for a description of valid arguments.
23 ** To convert 123 from LogEst to integer:
27 ** To convert 123456 from integer to LogEst:
39 typedef short int LogEst
; /* 10 times log2() */
41 LogEst
logEstMultiply(LogEst a
, LogEst b
){ return a
+b
; }
42 LogEst
logEstAdd(LogEst a
, LogEst b
){
43 static const unsigned char x
[] = {
48 6, 6, 6, /* 9,10,11 */
50 4, 4, 4, 4, /* 15-18 */
51 3, 3, 3, 3, 3, 3, /* 19-24 */
52 2, 2, 2, 2, 2, 2, 2, /* 25-31 */
54 if( a
<b
){ LogEst t
= a
; a
= b
; b
= t
; }
55 if( a
>b
+49 ) return a
;
56 if( a
>b
+31 ) return a
+1;
59 LogEst
logEstFromInteger(sqlite3_uint64 x
){
60 static LogEst a
[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
64 while( x
<8 ){ y
-= 10; x
<<= 1; }
66 while( x
>255 ){ y
+= 40; x
>>= 4; }
67 while( x
>15 ){ y
+= 10; x
>>= 1; }
69 return a
[x
&7] + y
- 10;
71 static sqlite3_uint64
logEstToInt(LogEst x
){
77 else if( n
>=1 ) n
-= 1;
78 if( x
>60 ) return (((sqlite3_uint64
)0xffffffff)<<32)+(sqlite3_uint64
)0xffffffff;
79 if( x
>=3 ) return (n
+8)<<(x
-3);
82 static LogEst
logEstFromDouble(double x
){
85 assert( sizeof(x
)==8 && sizeof(a
)==8 );
86 if( x
<=0.0 ) return -32768;
87 if( x
<0.01 ) return -logEstFromDouble(1.0/x
);
88 if( x
<1.0 ) return logEstFromDouble(100.0*x
) - 66;
89 if( x
<1024.0 ) return logEstFromInteger((sqlite3_uint64
)(1024.0*x
)) - 100;
90 if( x
<=2000000000.0 ) return logEstFromInteger((sqlite3_uint64
)x
);
96 int isInteger(const char *z
){
97 while( z
[0]>='0' && z
[0]<='9' ) z
++;
101 int isFloat(const char *z
){
103 while( ((c
=z
[0])>='0' && c
<='9') || c
=='.' || c
=='E' || c
=='e'
104 || c
=='+' || c
=='-' ) z
++;
108 static void showHelp(const char *zArgv0
){
109 printf("Usage: %s ARGS...\n", zArgv0
);
110 printf("Arguments:\n"
111 " NUM Convert NUM from integer to LogEst and push onto the stack\n"
112 " ^NUM Interpret NUM as a LogEst and push onto stack\n"
113 " x Multiple the top two elements of the stack\n"
114 " + Add the top two elements of the stack\n"
115 " dup Dupliate the top element on the stack\n"
116 " inv Take the reciprocal of the top of stack. N = 1/N.\n"
117 " log Find the LogEst of the number on top of stack\n"
118 " nlogn Compute NlogN where N is the top of stack\n"
123 int main(int argc
, char **argv
){
127 for(i
=1; i
<argc
; i
++){
128 const char *z
= argv
[i
];
129 if( strcmp(z
,"+")==0 ){
131 a
[n
-2] = logEstAdd(a
[n
-2],a
[n
-1]);
134 }else if( strcmp(z
,"x")==0 ){
136 a
[n
-2] = logEstMultiply(a
[n
-2],a
[n
-1]);
139 }else if( strcmp(z
,"dup")==0 ){
144 }else if( strcmp(z
,"log")==0 ){
145 if( n
>0 ) a
[n
-1] = logEstFromInteger(a
[n
-1]) - 33;
146 }else if( strcmp(z
,"nlogn")==0 ){
147 if( n
>0 ) a
[n
-1] += logEstFromInteger(a
[n
-1]) - 33;
148 }else if( strcmp(z
,"inv")==0 ){
149 if( n
>0 ) a
[n
-1] = -a
[n
-1];
150 }else if( z
[0]=='^' ){
151 a
[n
++] = (LogEst
)atoi(z
+1);
152 }else if( isInteger(z
) ){
153 a
[n
++] = logEstFromInteger(atoll(z
));
154 }else if( isFloat(z
) && z
[0]!='-' ){
155 a
[n
++] = logEstFromDouble(atof(z
));
160 for(i
=n
-1; i
>=0; i
--){
162 printf("%5d (%f)\n", a
[i
], 1.0/(double)logEstToInt(-a
[i
]));
164 printf("%5d (%f)\n", a
[i
], logEstToInt(a
[i
]+100)/1024.0);
165 }else if( a
[i
]>100 ){
166 printf("%5d (%lld)\n", a
[i
], logEstToInt(a
[i
]));
168 sqlite3_uint64 x
= logEstToInt(a
[i
]+100)*100/1024;
169 printf("%5d (%lld.%02lld)\n", a
[i
], x
/100, x
%100);