/// <summary> /// Tried the newton method for logs, but the exponential function is too slow to do it. /// </summary> private void LogNewton() { if (mantissa.IsZero() || mantissa.Sign) { return; } //Compute ln2. if (ln2cache == null || mantissa.Precision.NumBits > ln2cache.mantissa.Precision.NumBits) { CalculateLog2(mantissa.Precision.NumBits); } int numBits = mantissa.Precision.NumBits; //Use inverse exp function with Newton's method. BigFloat xn = new BigFloat(this); BigFloat oldExponent = new BigFloat(xn.exponent, mantissa.Precision); xn.exponent = 0; this.exponent = 0; //Hack to subtract 1 xn.mantissa.ClearBit(numBits - 1); //x0 = (x - 1) * log2 - this is a straight line fit between log(1) = 0 and log(2) = ln2 xn.Mul(ln2cache); //x0 = (x - 1) * log2 + C - this corrects for minimum error over the range. xn.Add(logNewtonConstant); BigFloat term = new BigFloat(mantissa.Precision); BigFloat one = new BigFloat(1, mantissa.Precision); int precision = 32; int normalPrecision = mantissa.Precision.NumBits; int iterations = 0; while (true) { term.Assign(xn); term.mantissa.Sign = true; term.Exp(precision); term.Mul(this); term.Sub(one); iterations++; if (term.exponent < -((precision >> 1) - 4)) { if (precision == normalPrecision) { if (term.exponent < -(precision - 4)) break; } else { precision = precision << 1; if (precision > normalPrecision) precision = normalPrecision; } } xn.Add(term); } //log(2^n*s) = log(2^n) + log(s) = nlog(2) + log(s) term.Assign(ln2cache); term.Mul(oldExponent); this.Assign(xn); this.Add(term); }
/// <summary> /// The exponential function. Less accurate for high exponents, scales poorly with the number /// of bits. This is quite fast for low-precision arguments. /// </summary> public static BigFloat Exp(BigFloat n1) { BigFloat res = new BigFloat(n1); res.Exp(); return res; }