http://d.puremagic.com/issues/show_bug.cgi?id=3749
--- Comment #4 from Witold Baryluk <[email protected]> 2010-01-28 15:55:35 PST --- So I release this as public domain. I written this code as workaround to lack of log and exp. They looks to be accurate to 16 digital digits on whole real line. Results can be slightly different than values returned by std.math.{log,exp} unfortunetly. Anybody want to review this code or know better methods? /** Calculate natural logarithm of x. * * * Performs reduction of large values to (0..3) inverval, using log(x 3^n) = log(x) + n*log(3) * * Then uses truncated Taylor series in variable y=(x-1)/(x+1) for x > 0. * * For values x < 1, calculate -log(1/x) * */ double ctfe_log(double x_) { if (x_ == 0.0) { return -double.infinity; } if (x_ < 0.0) { return double.nan; } if (x_ == double.infinity) { return double.infinity; } if (x_ == 1.0) { return 0.0; } if (!(x_ == x_)) { // nan return double.nan; } real x = x_; if (x > 1.0) { uint m = 0; // reduce to (1 .. 3) interval while (x > 3.0) { x = x / 3.0; m = m + 1; } real y = (x-1.0)/(x+1.0); real y2 = y*y; /* Evaluate Horner's scheme on polynomial * log(x) = log((1+y) / (1-y)) = 2 y (1 + y^2/3 + y^4/5 + y^6/7 + ... y^70/71) */ real temp = 0.0; for (int i = 71; i >= 3; i -= 2) { temp += 1.0/cast(real)i; temp *= y2; } temp += 1.0; y = 2.0*y*temp; if (m) { return y + m*ctfe_log(3.0); } else { return y; } } else { return -ctfe_log(1.0/x); } } /** Compute exponential function of x. * * Uses truncated Taylor series expeansion of exp function. * * Performs reduction for |x| > 2, of the form exp(x 2^m) = exp(x)^(2^m) */ double ctfe_exp(double x_) { if (x_ == 0.0) { return 1.0; } if (x_ >= 710.0) { // includes +infinity return double.infinity; } if (x_ <= -746.0) { // includes -infinity return 0.0; } if (!(x_ == x_)) { // nan return double.nan; } real x = x_; int m = 0; // reduce to (-2 .. 2) interval if (x > 0.0) { while (x > 2.0) { x = x / 2.0; m = m + 1; } } else { while (x < -2.0) { x = x / 2.0; m = m - 1; } } real temp = 1.0; real term = 1.0; for (int i = 1; i <= 25; i++) { term *= x/cast(real)i; temp += term; } if (m) { real exp2 = ctfe_exp(2.0); if (m > 0) { for (int i = 0; i < m; i++) { temp = temp*temp; } } else { for (int i = 0; i < -m; i++) { temp = temp*temp; } } return temp; } else { return temp; } } int tests(double[] xs, int min, int max) { assert(min <= max); int r = 0; double c = 1.0; if (min < 0) { for (int i = 0; i < -min; i++) { c = c / 2.0; } } if (min > 0) { for (int i = 0; i < -min; i++) { c = c * 2.0; } } for (int i = min; i <= max; i++) { foreach (x0; xs) { auto x = c * x0; if ( (ctfe_exp(ctfe_log(x)) - x) / x < 1.0e-16 ) { // ok } else { r = r + 1; } } } return r; } enum c = tests( [0.1, 0.1001, 0.11, 0.2, 0.24, 0.3, 0.341, 0.387123, 0.4, 0.5, 0.55, 0.6, 0.7, 0.732, 0.8, 0.88, 0.9, 0.98, 0.9991, 0.999992], -300, 300); static assert(c == 0); static assert(ctfe_exp(0.0) == 1.0); static assert(ctfe_exp(-1000.0) == 0.0); static assert(ctfe_exp(1000.0) == double.infinity); static assert(ctfe_log(0.0) == -double.infinity); -- Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email ------- You are receiving this mail because: -------
