1bf539c4dSdrh /*
2bf539c4dSdrh ** 2013-06-10
3bf539c4dSdrh **
4bf539c4dSdrh ** The author disclaims copyright to this source code. In place of
5bf539c4dSdrh ** a legal notice, here is a blessing:
6bf539c4dSdrh **
7bf539c4dSdrh ** May you do good and not evil.
8bf539c4dSdrh ** May you find forgiveness for yourself and forgive others.
9bf539c4dSdrh ** May you share freely, never taking more than you give.
10bf539c4dSdrh **
11bf539c4dSdrh *************************************************************************
12bf539c4dSdrh ** This file contains a simple command-line utility for converting from
13bf539c4dSdrh ** integers and LogEst values and back again and for doing simple
14bf539c4dSdrh ** arithmetic operations (multiple and add) on LogEst values.
15bf539c4dSdrh **
16bf539c4dSdrh ** Usage:
17bf539c4dSdrh **
18bf539c4dSdrh ** ./LogEst ARGS
19bf539c4dSdrh **
20382bdeabSdrh ** See the showHelp() routine for a description of valid arguments.
21bf539c4dSdrh ** Examples:
22bf539c4dSdrh **
23bf539c4dSdrh ** To convert 123 from LogEst to integer:
24bf539c4dSdrh **
25bf539c4dSdrh ** ./LogEst ^123
26bf539c4dSdrh **
27bf539c4dSdrh ** To convert 123456 from integer to LogEst:
28bf539c4dSdrh **
29bf539c4dSdrh ** ./LogEst 123456
30bf539c4dSdrh **
31bf539c4dSdrh */
32bf539c4dSdrh #include <stdio.h>
33bf539c4dSdrh #include <stdlib.h>
34bf539c4dSdrh #include <ctype.h>
35bf539c4dSdrh #include <assert.h>
36bf539c4dSdrh #include <string.h>
37bf539c4dSdrh #include "sqlite3.h"
38bf539c4dSdrh
39bf539c4dSdrh typedef short int LogEst; /* 10 times log2() */
40bf539c4dSdrh
logEstMultiply(LogEst a,LogEst b)41bf539c4dSdrh LogEst logEstMultiply(LogEst a, LogEst b){ return a+b; }
logEstAdd(LogEst a,LogEst b)42bf539c4dSdrh LogEst logEstAdd(LogEst a, LogEst b){
43bf539c4dSdrh static const unsigned char x[] = {
44bf539c4dSdrh 10, 10, /* 0,1 */
45bf539c4dSdrh 9, 9, /* 2,3 */
46bf539c4dSdrh 8, 8, /* 4,5 */
47bf539c4dSdrh 7, 7, 7, /* 6,7,8 */
48bf539c4dSdrh 6, 6, 6, /* 9,10,11 */
49bf539c4dSdrh 5, 5, 5, /* 12-14 */
50bf539c4dSdrh 4, 4, 4, 4, /* 15-18 */
51bf539c4dSdrh 3, 3, 3, 3, 3, 3, /* 19-24 */
52bf539c4dSdrh 2, 2, 2, 2, 2, 2, 2, /* 25-31 */
53bf539c4dSdrh };
54bf539c4dSdrh if( a<b ){ LogEst t = a; a = b; b = t; }
55bf539c4dSdrh if( a>b+49 ) return a;
56bf539c4dSdrh if( a>b+31 ) return a+1;
57bf539c4dSdrh return a+x[a-b];
58bf539c4dSdrh }
logEstFromInteger(sqlite3_uint64 x)59bf539c4dSdrh LogEst logEstFromInteger(sqlite3_uint64 x){
60bf539c4dSdrh static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
61bf539c4dSdrh LogEst y = 40;
62bf539c4dSdrh if( x<8 ){
63bf539c4dSdrh if( x<2 ) return 0;
64bf539c4dSdrh while( x<8 ){ y -= 10; x <<= 1; }
65bf539c4dSdrh }else{
66bf539c4dSdrh while( x>255 ){ y += 40; x >>= 4; }
67bf539c4dSdrh while( x>15 ){ y += 10; x >>= 1; }
68bf539c4dSdrh }
69bf539c4dSdrh return a[x&7] + y - 10;
70bf539c4dSdrh }
logEstToInt(LogEst x)710af62b01Sdrh static sqlite3_uint64 logEstToInt(LogEst x){
720af62b01Sdrh sqlite3_uint64 n;
73bf539c4dSdrh if( x<10 ) return 1;
74bf539c4dSdrh n = x%10;
75bf539c4dSdrh x /= 10;
76bf539c4dSdrh if( n>=5 ) n -= 2;
77bf539c4dSdrh else if( n>=1 ) n -= 1;
78*2b5fbb28Smistachkin if( x>60 ) return (((sqlite3_uint64)0xffffffff)<<32)+(sqlite3_uint64)0xffffffff;
79bf539c4dSdrh if( x>=3 ) return (n+8)<<(x-3);
80bf539c4dSdrh return (n+8)>>(3-x);
81bf539c4dSdrh }
logEstFromDouble(double x)82bf539c4dSdrh static LogEst logEstFromDouble(double x){
83bf539c4dSdrh sqlite3_uint64 a;
84bf539c4dSdrh LogEst e;
85bf539c4dSdrh assert( sizeof(x)==8 && sizeof(a)==8 );
860af62b01Sdrh if( x<=0.0 ) return -32768;
87253666e5Sdrh if( x<0.01 ) return -logEstFromDouble(1.0/x);
88253666e5Sdrh if( x<1.0 ) return logEstFromDouble(100.0*x) - 66;
890af62b01Sdrh if( x<1024.0 ) return logEstFromInteger((sqlite3_uint64)(1024.0*x)) - 100;
900af62b01Sdrh if( x<=2000000000.0 ) return logEstFromInteger((sqlite3_uint64)x);
91bf539c4dSdrh memcpy(&a, &x, 8);
92bf539c4dSdrh e = (a>>52) - 1022;
93bf539c4dSdrh return e*10;
94bf539c4dSdrh }
95bf539c4dSdrh
isInteger(const char * z)96382bdeabSdrh int isInteger(const char *z){
97382bdeabSdrh while( z[0]>='0' && z[0]<='9' ) z++;
98382bdeabSdrh return z[0]==0;
99bf539c4dSdrh }
100382bdeabSdrh
isFloat(const char * z)101382bdeabSdrh int isFloat(const char *z){
102382bdeabSdrh char c;
103382bdeabSdrh while( ((c=z[0])>='0' && c<='9') || c=='.' || c=='E' || c=='e'
104382bdeabSdrh || c=='+' || c=='-' ) z++;
105382bdeabSdrh return z[0]==0;
106382bdeabSdrh }
107382bdeabSdrh
showHelp(const char * zArgv0)108382bdeabSdrh static void showHelp(const char *zArgv0){
109382bdeabSdrh printf("Usage: %s ARGS...\n", zArgv0);
110382bdeabSdrh printf("Arguments:\n"
111382bdeabSdrh " NUM Convert NUM from integer to LogEst and push onto the stack\n"
112382bdeabSdrh " ^NUM Interpret NUM as a LogEst and push onto stack\n"
113382bdeabSdrh " x Multiple the top two elements of the stack\n"
114382bdeabSdrh " + Add the top two elements of the stack\n"
115382bdeabSdrh " dup Dupliate the top element on the stack\n"
116382bdeabSdrh " inv Take the reciprocal of the top of stack. N = 1/N.\n"
117382bdeabSdrh " log Find the LogEst of the number on top of stack\n"
118382bdeabSdrh " nlogn Compute NlogN where N is the top of stack\n"
119382bdeabSdrh );
120382bdeabSdrh exit(1);
121bf539c4dSdrh }
122bf539c4dSdrh
main(int argc,char ** argv)123bf539c4dSdrh int main(int argc, char **argv){
124bf539c4dSdrh int i;
125bf539c4dSdrh int n = 0;
126bf539c4dSdrh LogEst a[100];
127bf539c4dSdrh for(i=1; i<argc; i++){
128bf539c4dSdrh const char *z = argv[i];
129382bdeabSdrh if( strcmp(z,"+")==0 ){
130bf539c4dSdrh if( n>=2 ){
131bf539c4dSdrh a[n-2] = logEstAdd(a[n-2],a[n-1]);
132bf539c4dSdrh n--;
133bf539c4dSdrh }
134382bdeabSdrh }else if( strcmp(z,"x")==0 ){
135bf539c4dSdrh if( n>=2 ){
136bf539c4dSdrh a[n-2] = logEstMultiply(a[n-2],a[n-1]);
137bf539c4dSdrh n--;
138bf539c4dSdrh }
139382bdeabSdrh }else if( strcmp(z,"dup")==0 ){
140382bdeabSdrh if( n>0 ){
141382bdeabSdrh a[n] = a[n-1];
142382bdeabSdrh n++;
143382bdeabSdrh }
144382bdeabSdrh }else if( strcmp(z,"log")==0 ){
145382bdeabSdrh if( n>0 ) a[n-1] = logEstFromInteger(a[n-1]) - 33;
146382bdeabSdrh }else if( strcmp(z,"nlogn")==0 ){
147382bdeabSdrh if( n>0 ) a[n-1] += logEstFromInteger(a[n-1]) - 33;
148382bdeabSdrh }else if( strcmp(z,"inv")==0 ){
149382bdeabSdrh if( n>0 ) a[n-1] = -a[n-1];
150bf539c4dSdrh }else if( z[0]=='^' ){
15177fac879Smistachkin a[n++] = (LogEst)atoi(z+1);
152382bdeabSdrh }else if( isInteger(z) ){
1537e910f64Sdrh a[n++] = logEstFromInteger(atoll(z));
154382bdeabSdrh }else if( isFloat(z) && z[0]!='-' ){
155bf539c4dSdrh a[n++] = logEstFromDouble(atof(z));
156bf539c4dSdrh }else{
157382bdeabSdrh showHelp(argv[0]);
158bf539c4dSdrh }
159bf539c4dSdrh }
160bf539c4dSdrh for(i=n-1; i>=0; i--){
161253666e5Sdrh if( a[i]<-40 ){
162382bdeabSdrh printf("%5d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i]));
163253666e5Sdrh }else if( a[i]<10 ){
164253666e5Sdrh printf("%5d (%f)\n", a[i], logEstToInt(a[i]+100)/1024.0);
1657e910f64Sdrh }else if( a[i]>100 ){
1667e910f64Sdrh printf("%5d (%lld)\n", a[i], logEstToInt(a[i]));
167bf539c4dSdrh }else{
1680af62b01Sdrh sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024;
169382bdeabSdrh printf("%5d (%lld.%02lld)\n", a[i], x/100, x%100);
170bf539c4dSdrh }
171bf539c4dSdrh }
172bf539c4dSdrh return 0;
173bf539c4dSdrh }
174