xref: /sqlite-3.40.0/tool/logest.c (revision 2b5fbb28)
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