#include "log.h" #define crumb printf #include "lntable.frag" #define tablen (sizeof(lntable)/sizeof(*lntable)) double antiln (double x) { double index, fract; int i, lower, upper; int antiinfloop, halfway; double retval; //crumb("Antilogarithm of %f\n", x); if (x < 0) return (antiln(x + 1.0) / ee); if (x > 1.0) return (antiln(x - 1.0) * ee); if (x == 0) return 1; if (x == 1.0) return ee; /* Find the two numbers x fits between. */ /* Get the indices. */ /* Lerp between the indices for a more precise value. */ /* Scale index value between 1 and e: */ /* antilog = (index * (ee - 1) / (lntable.len)) + 1 */ retval = 0; lower = 0; upper = tablen; antiinfloop = 0; while ((upper - lower > 1) && (antiinfloop < tablen)) { halfway = lower + ((upper - lower) >> 1); //crumb("Comparing x(%.18f) to [%d](%.18f), (%d, %d)\n", x, halfway, lntable[halfway], lower, upper); if (x < lntable[halfway]) { upper = halfway; } else { lower = halfway; } antiinfloop++; } /* Now it should be such that: lntable[lower] <= x < lntable[upper] */ if (antiinfloop >= tablen) /* ugh ugh. */ upper = lower + 1; //crumb("For x = %.18f:\n", x); //crumb(" lower = %d [%.18f]\n", lower, lntable[lower]); //crumb(" upper = %d [%.18f]\n", upper, lntable[upper]); /* Lerp. */ fract = (x - lntable[lower]) / (lntable[upper] - lntable[lower]); index = (float)lower + fract; // index *= 1.000978; /* Always a little too low. */ index *= 1.0009768; //crumb("Calculating on index %.18f\n", index); /* Scale to 1..e */ retval = (index * (ee - 1) / tablen) + 1; //crumb("Antilog %f = %f\n", x, retval); return retval; } /* Table-lookup + linear interpolation techinque. Natural logarithm. Given a value x, multiply or divide by e until within in range 1..e. Keep track of number of multiplys/divides (maintaining sign). equation then is ln (x * e^n) = L Where x is the given value, n is the number of multiply/divides, L is the desired result in 1..e inclusive. d = 1000 * ((x * e^n) - 1) / (e - 1); d give a value between 0..1000 inclusive. This is used for offset into lookup table. i = int(d); i is index into lookup table. a = lntable[i]; b = lntable[i+1]; The value we look for is lerped between this two values based on the fractional part of d. c = d - i; c is the fractional part of d. Lerp between a and b is: L = a + ((b - a) * c) minor subst: L = lntable[i] + ((lntable[i+1] - lntable[i]) * (d - i)); ln (x * e^n) = L ln(x) + ln(e^n) = L ln(x) + n = L ln(x) = L - n Our real result. */ double ln (double x) { double retval; double d, c; int n, i; if (x == 0) return 0; /* FIXME: error condition. */ n = 0; if (x > ee) { while (x > ee) { x /= ee; n--; } } else if (x < 1.0) { while (x < 1.0) { x *= ee; n++; } } d = ((sizeof(lntable)-1) / sizeof(*lntable)) * (x - 1.0) / (ee - 1.0); i = (int)d; c = (d - (float)i); retval = lntable[i] + ((lntable[i+1] - lntable[i]) * c); retval -= (float)n; return retval; } double exp (double x) { double retval; int i, n; // double shifting; int shifting = 0; /* This function aims to be based iteration, instead of using antiln's recursion. */ n = 0; if (x > 1.0) { while (x > 1.0) { shifting--; x -= 1.0; } } else if (x < 0) { while (x < 0) { shifting++; x += 1.0; } } //crumb("exp: of %f after shifting %d\n", x, shifting); retval = antiln(x); if (shifting > 0) { while (shifting > 0) { shifting--; retval /= ee; } } else if (shifting < 0) { while (shifting < 0) { shifting++; retval *= ee; } } /* Add or subtract 1 to/from x until 0 <= x < 1 */ /* Number of add/subtracts stored in `n'. */ /* Take antilogarithm of remaining x, store in x. */ /* Raise e to the power of n, store in shifting. */ /* Multiply the current x with shifting, store in retval. */ return retval; } double lg (double x) { double retval; retval = ln(x) / ln(10); return retval; } double pow (double base, double exponent) { /* Any exponention b^n can be rewritten as e^(n ln b). */ double retval; float z; //crumb("pow: %f to %f\n", base, exponent); z = ln(base); //crumb("pow: z = %f\n", z); z = exponent * z; //crumb("pow: z = %f\n", z); retval = exp(z); //crumb("pow: done %f\n", retval); // retval = exp(exponent * ln(base)); return retval; } #ifndef Q3_VM int main () { printf("test ln(0.015) = %.57f\n", ln(0.015)); printf("antilogarithm(0.224455) = %.57f\n", antiln(0.224455)); printf("antilogarithm(0.98) = %.57f\n", antiln(0.98)); printf("antilogarithm(1.1) = %.57f\n", antiln(1.1)); printf("antilogarithm(100) = %.57f\n", antiln(100)); printf("2^5 = %.57f\n", pow(2, 5)); printf("2^10 = %.57f\n", pow(2, 10)); printf("10^3 = %.57f\n", pow(10, 3)); } #endif