logest.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. /*
  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. **
  20. ** See the showHelp() routine for a description of valid arguments.
  21. ** 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. typedef short int LogEst; /* 10 times log2() */
  39. LogEst logEstMultiply(LogEst a, LogEst b){ return a+b; }
  40. LogEst logEstAdd(LogEst a, LogEst b){
  41. static const unsigned char x[] = {
  42. 10, 10, /* 0,1 */
  43. 9, 9, /* 2,3 */
  44. 8, 8, /* 4,5 */
  45. 7, 7, 7, /* 6,7,8 */
  46. 6, 6, 6, /* 9,10,11 */
  47. 5, 5, 5, /* 12-14 */
  48. 4, 4, 4, 4, /* 15-18 */
  49. 3, 3, 3, 3, 3, 3, /* 19-24 */
  50. 2, 2, 2, 2, 2, 2, 2, /* 25-31 */
  51. };
  52. if( a<b ){ LogEst t = a; a = b; b = t; }
  53. if( a>b+49 ) return a;
  54. if( a>b+31 ) return a+1;
  55. return a+x[a-b];
  56. }
  57. LogEst logEstFromInteger(sqlite3_uint64 x){
  58. static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
  59. LogEst y = 40;
  60. if( x<8 ){
  61. if( x<2 ) return 0;
  62. while( x<8 ){ y -= 10; x <<= 1; }
  63. }else{
  64. while( x>255 ){ y += 40; x >>= 4; }
  65. while( x>15 ){ y += 10; x >>= 1; }
  66. }
  67. return a[x&7] + y - 10;
  68. }
  69. static sqlite3_uint64 logEstToInt(LogEst x){
  70. sqlite3_uint64 n;
  71. if( x<10 ) return 1;
  72. n = x%10;
  73. x /= 10;
  74. if( n>=5 ) n -= 2;
  75. else if( n>=1 ) n -= 1;
  76. if( x>60 ) return (((sqlite3_uint64)0xffffffff)<<32)+(sqlite3_uint64)0xffffffff;
  77. if( x>=3 ) return (n+8)<<(x-3);
  78. return (n+8)>>(3-x);
  79. }
  80. static LogEst logEstFromDouble(double x){
  81. sqlite3_uint64 a;
  82. LogEst e;
  83. assert( sizeof(x)==8 && sizeof(a)==8 );
  84. if( x<=0.0 ) return -32768;
  85. if( x<0.01 ) return -logEstFromDouble(1.0/x);
  86. if( x<1.0 ) return logEstFromDouble(100.0*x) - 66;
  87. if( x<1024.0 ) return logEstFromInteger((sqlite3_uint64)(1024.0*x)) - 100;
  88. if( x<=2000000000.0 ) return logEstFromInteger((sqlite3_uint64)x);
  89. memcpy(&a, &x, 8);
  90. e = (a>>52) - 1022;
  91. return e*10;
  92. }
  93. int isInteger(const char *z){
  94. while( z[0]>='0' && z[0]<='9' ) z++;
  95. return z[0]==0;
  96. }
  97. int isFloat(const char *z){
  98. char c;
  99. while( ((c=z[0])>='0' && c<='9') || c=='.' || c=='E' || c=='e'
  100. || c=='+' || c=='-' ) z++;
  101. return z[0]==0;
  102. }
  103. static void showHelp(const char *zArgv0){
  104. printf("Usage: %s ARGS...\n", zArgv0);
  105. printf("Arguments:\n"
  106. " NUM Convert NUM from integer to LogEst and push onto the stack\n"
  107. " ^NUM Interpret NUM as a LogEst and push onto stack\n"
  108. " x Multiple the top two elements of the stack\n"
  109. " + Add the top two elements of the stack\n"
  110. " dup Dupliate the top element on the stack\n"
  111. " inv Take the reciprocal of the top of stack. N = 1/N.\n"
  112. " log Find the LogEst of the number on top of stack\n"
  113. " nlogn Compute NlogN where N is the top of stack\n"
  114. );
  115. exit(1);
  116. }
  117. int main(int argc, char **argv){
  118. int i;
  119. int n = 0;
  120. LogEst a[100];
  121. for(i=1; i<argc; i++){
  122. const char *z = argv[i];
  123. if( strcmp(z,"+")==0 ){
  124. if( n>=2 ){
  125. a[n-2] = logEstAdd(a[n-2],a[n-1]);
  126. n--;
  127. }
  128. }else if( strcmp(z,"x")==0 ){
  129. if( n>=2 ){
  130. a[n-2] = logEstMultiply(a[n-2],a[n-1]);
  131. n--;
  132. }
  133. }else if( strcmp(z,"dup")==0 ){
  134. if( n>0 ){
  135. a[n] = a[n-1];
  136. n++;
  137. }
  138. }else if( strcmp(z,"log")==0 ){
  139. if( n>0 ) a[n-1] = logEstFromInteger(a[n-1]) - 33;
  140. }else if( strcmp(z,"nlogn")==0 ){
  141. if( n>0 ) a[n-1] += logEstFromInteger(a[n-1]) - 33;
  142. }else if( strcmp(z,"inv")==0 ){
  143. if( n>0 ) a[n-1] = -a[n-1];
  144. }else if( z[0]=='^' ){
  145. a[n++] = (LogEst)atoi(z+1);
  146. }else if( isInteger(z) ){
  147. a[n++] = logEstFromInteger(atoll(z));
  148. }else if( isFloat(z) && z[0]!='-' ){
  149. a[n++] = logEstFromDouble(atof(z));
  150. }else{
  151. showHelp(argv[0]);
  152. }
  153. }
  154. for(i=n-1; i>=0; i--){
  155. if( a[i]<-40 ){
  156. printf("%5d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i]));
  157. }else if( a[i]<10 ){
  158. printf("%5d (%f)\n", a[i], logEstToInt(a[i]+100)/1024.0);
  159. }else if( a[i]>100 ){
  160. printf("%5d (%lld)\n", a[i], logEstToInt(a[i]));
  161. }else{
  162. sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024;
  163. printf("%5d (%lld.%02lld)\n", a[i], x/100, x%100);
  164. }
  165. }
  166. return 0;
  167. }