blob: d916b43d396747de0ebbbac1ff39732f823d9185 [file] [log] [blame]
drhbf539c42013-10-05 18:16:02 +00001/*
2** 2013-06-10
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** 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.
15**
16** Usage:
17**
18** ./LogEst ARGS
19**
drh382bdea2014-03-27 14:05:38 +000020** See the showHelp() routine for a description of valid arguments.
drhbf539c42013-10-05 18:16:02 +000021** Examples:
22**
23** To convert 123 from LogEst to integer:
24**
25** ./LogEst ^123
26**
27** To convert 123456 from integer to LogEst:
28**
29** ./LogEst 123456
30**
31*/
32#include <stdio.h>
33#include <stdlib.h>
34#include <ctype.h>
35#include <assert.h>
36#include <string.h>
37#include "sqlite3.h"
38
39typedef short int LogEst; /* 10 times log2() */
40
41LogEst logEstMultiply(LogEst a, LogEst b){ return a+b; }
42LogEst logEstAdd(LogEst a, LogEst b){
43 static const unsigned char x[] = {
44 10, 10, /* 0,1 */
45 9, 9, /* 2,3 */
46 8, 8, /* 4,5 */
47 7, 7, 7, /* 6,7,8 */
48 6, 6, 6, /* 9,10,11 */
49 5, 5, 5, /* 12-14 */
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 */
53 };
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;
57 return a+x[a-b];
58}
59LogEst logEstFromInteger(sqlite3_uint64 x){
60 static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
61 LogEst y = 40;
62 if( x<8 ){
63 if( x<2 ) return 0;
64 while( x<8 ){ y -= 10; x <<= 1; }
65 }else{
66 while( x>255 ){ y += 40; x >>= 4; }
67 while( x>15 ){ y += 10; x >>= 1; }
68 }
69 return a[x&7] + y - 10;
70}
drh0af62b02013-10-05 18:32:30 +000071static sqlite3_uint64 logEstToInt(LogEst x){
72 sqlite3_uint64 n;
drhbf539c42013-10-05 18:16:02 +000073 if( x<10 ) return 1;
74 n = x%10;
75 x /= 10;
76 if( n>=5 ) n -= 2;
77 else if( n>=1 ) n -= 1;
mistachkin2b5fbb22021-12-31 18:26:50 +000078 if( x>60 ) return (((sqlite3_uint64)0xffffffff)<<32)+(sqlite3_uint64)0xffffffff;
drhbf539c42013-10-05 18:16:02 +000079 if( x>=3 ) return (n+8)<<(x-3);
80 return (n+8)>>(3-x);
81}
82static LogEst logEstFromDouble(double x){
83 sqlite3_uint64 a;
84 LogEst e;
85 assert( sizeof(x)==8 && sizeof(a)==8 );
drh0af62b02013-10-05 18:32:30 +000086 if( x<=0.0 ) return -32768;
drh253666e2014-04-30 14:22:38 +000087 if( x<0.01 ) return -logEstFromDouble(1.0/x);
88 if( x<1.0 ) return logEstFromDouble(100.0*x) - 66;
drh0af62b02013-10-05 18:32:30 +000089 if( x<1024.0 ) return logEstFromInteger((sqlite3_uint64)(1024.0*x)) - 100;
90 if( x<=2000000000.0 ) return logEstFromInteger((sqlite3_uint64)x);
drhbf539c42013-10-05 18:16:02 +000091 memcpy(&a, &x, 8);
92 e = (a>>52) - 1022;
93 return e*10;
94}
95
drh382bdea2014-03-27 14:05:38 +000096int isInteger(const char *z){
97 while( z[0]>='0' && z[0]<='9' ) z++;
98 return z[0]==0;
99}
100
drhbf539c42013-10-05 18:16:02 +0000101int isFloat(const char *z){
drh382bdea2014-03-27 14:05:38 +0000102 char c;
103 while( ((c=z[0])>='0' && c<='9') || c=='.' || c=='E' || c=='e'
104 || c=='+' || c=='-' ) z++;
105 return z[0]==0;
106}
107
108static 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"
119 );
120 exit(1);
drhbf539c42013-10-05 18:16:02 +0000121}
122
123int main(int argc, char **argv){
124 int i;
125 int n = 0;
126 LogEst a[100];
127 for(i=1; i<argc; i++){
128 const char *z = argv[i];
drh382bdea2014-03-27 14:05:38 +0000129 if( strcmp(z,"+")==0 ){
drhbf539c42013-10-05 18:16:02 +0000130 if( n>=2 ){
131 a[n-2] = logEstAdd(a[n-2],a[n-1]);
132 n--;
133 }
drh382bdea2014-03-27 14:05:38 +0000134 }else if( strcmp(z,"x")==0 ){
drhbf539c42013-10-05 18:16:02 +0000135 if( n>=2 ){
136 a[n-2] = logEstMultiply(a[n-2],a[n-1]);
137 n--;
138 }
drh382bdea2014-03-27 14:05:38 +0000139 }else if( strcmp(z,"dup")==0 ){
140 if( n>0 ){
141 a[n] = a[n-1];
142 n++;
143 }
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];
drhbf539c42013-10-05 18:16:02 +0000150 }else if( z[0]=='^' ){
mistachkin77fac872016-04-12 20:05:06 +0000151 a[n++] = (LogEst)atoi(z+1);
drh382bdea2014-03-27 14:05:38 +0000152 }else if( isInteger(z) ){
drh7e910f62021-12-09 01:28:15 +0000153 a[n++] = logEstFromInteger(atoll(z));
drh382bdea2014-03-27 14:05:38 +0000154 }else if( isFloat(z) && z[0]!='-' ){
drhbf539c42013-10-05 18:16:02 +0000155 a[n++] = logEstFromDouble(atof(z));
156 }else{
drh382bdea2014-03-27 14:05:38 +0000157 showHelp(argv[0]);
drhbf539c42013-10-05 18:16:02 +0000158 }
159 }
160 for(i=n-1; i>=0; i--){
drh253666e2014-04-30 14:22:38 +0000161 if( a[i]<-40 ){
drh382bdea2014-03-27 14:05:38 +0000162 printf("%5d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i]));
drh253666e2014-04-30 14:22:38 +0000163 }else if( a[i]<10 ){
164 printf("%5d (%f)\n", a[i], logEstToInt(a[i]+100)/1024.0);
drh7e910f62021-12-09 01:28:15 +0000165 }else if( a[i]>100 ){
166 printf("%5d (%lld)\n", a[i], logEstToInt(a[i]));
drhbf539c42013-10-05 18:16:02 +0000167 }else{
drh0af62b02013-10-05 18:32:30 +0000168 sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024;
drh382bdea2014-03-27 14:05:38 +0000169 printf("%5d (%lld.%02lld)\n", a[i], x/100, x%100);
drhbf539c42013-10-05 18:16:02 +0000170 }
171 }
172 return 0;
173}