logest.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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. ** Arguments:
  21. **
  22. ** 'x' Multiple the top two elements of the stack
  23. ** '+' Add the top two elements of the stack
  24. ** NUM Convert NUM from integer to LogEst and push onto the stack
  25. ** ^NUM Interpret NUM as a LogEst and push onto stack.
  26. **
  27. ** Examples:
  28. **
  29. ** To convert 123 from LogEst to integer:
  30. **
  31. ** ./LogEst ^123
  32. **
  33. ** To convert 123456 from integer to LogEst:
  34. **
  35. ** ./LogEst 123456
  36. **
  37. */
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <ctype.h>
  41. #include <assert.h>
  42. #include <string.h>
  43. #include "sqlite3.h"
  44. typedef short int LogEst; /* 10 times log2() */
  45. LogEst logEstMultiply(LogEst a, LogEst b){ return a+b; }
  46. LogEst logEstAdd(LogEst a, LogEst b){
  47. static const unsigned char x[] = {
  48. 10, 10, /* 0,1 */
  49. 9, 9, /* 2,3 */
  50. 8, 8, /* 4,5 */
  51. 7, 7, 7, /* 6,7,8 */
  52. 6, 6, 6, /* 9,10,11 */
  53. 5, 5, 5, /* 12-14 */
  54. 4, 4, 4, 4, /* 15-18 */
  55. 3, 3, 3, 3, 3, 3, /* 19-24 */
  56. 2, 2, 2, 2, 2, 2, 2, /* 25-31 */
  57. };
  58. if( a<b ){ LogEst t = a; a = b; b = t; }
  59. if( a>b+49 ) return a;
  60. if( a>b+31 ) return a+1;
  61. return a+x[a-b];
  62. }
  63. LogEst logEstFromInteger(sqlite3_uint64 x){
  64. static LogEst a[] = { 0, 2, 3, 5, 6, 7, 8, 9 };
  65. LogEst y = 40;
  66. if( x<8 ){
  67. if( x<2 ) return 0;
  68. while( x<8 ){ y -= 10; x <<= 1; }
  69. }else{
  70. while( x>255 ){ y += 40; x >>= 4; }
  71. while( x>15 ){ y += 10; x >>= 1; }
  72. }
  73. return a[x&7] + y - 10;
  74. }
  75. static sqlite3_uint64 logEstToInt(LogEst x){
  76. sqlite3_uint64 n;
  77. if( x<10 ) return 1;
  78. n = x%10;
  79. x /= 10;
  80. if( n>=5 ) n -= 2;
  81. else if( n>=1 ) n -= 1;
  82. if( x>=3 ) return (n+8)<<(x-3);
  83. return (n+8)>>(3-x);
  84. }
  85. static LogEst logEstFromDouble(double x){
  86. sqlite3_uint64 a;
  87. LogEst e;
  88. assert( sizeof(x)==8 && sizeof(a)==8 );
  89. if( x<=0.0 ) return -32768;
  90. if( x<1.0 ) return -logEstFromDouble(1/x);
  91. if( x<1024.0 ) return logEstFromInteger((sqlite3_uint64)(1024.0*x)) - 100;
  92. if( x<=2000000000.0 ) return logEstFromInteger((sqlite3_uint64)x);
  93. memcpy(&a, &x, 8);
  94. e = (a>>52) - 1022;
  95. return e*10;
  96. }
  97. int isFloat(const char *z){
  98. while( z[0] ){
  99. if( z[0]=='.' || z[0]=='E' || z[0]=='e' ) return 1;
  100. z++;
  101. }
  102. return 0;
  103. }
  104. int main(int argc, char **argv){
  105. int i;
  106. int n = 0;
  107. LogEst a[100];
  108. for(i=1; i<argc; i++){
  109. const char *z = argv[i];
  110. if( z[0]=='+' ){
  111. if( n>=2 ){
  112. a[n-2] = logEstAdd(a[n-2],a[n-1]);
  113. n--;
  114. }
  115. }else if( z[0]=='x' ){
  116. if( n>=2 ){
  117. a[n-2] = logEstMultiply(a[n-2],a[n-1]);
  118. n--;
  119. }
  120. }else if( z[0]=='^' ){
  121. a[n++] = atoi(z+1);
  122. }else if( isFloat(z) ){
  123. a[n++] = logEstFromDouble(atof(z));
  124. }else{
  125. a[n++] = logEstFromInteger(atoi(z));
  126. }
  127. }
  128. for(i=n-1; i>=0; i--){
  129. if( a[i]<0 ){
  130. printf("%d (%f)\n", a[i], 1.0/(double)logEstToInt(-a[i]));
  131. }else{
  132. sqlite3_uint64 x = logEstToInt(a[i]+100)*100/1024;
  133. printf("%d (%lld.%02lld)\n", a[i], x/100, x%100);
  134. }
  135. }
  136. return 0;
  137. }