def log(x, b=None): """ log(x) -> the natural (base e) logarithm of x log(x, b) -> the base b logarithm of x """ # Basic input management if b is not None: Float._prec += 3 if b == 2: blog = log2_float() elif b == 10: blog = log10_float() else: blog = log(b) l = log(x) / blog Float._prec -= 3 return l if x == 0: raise ValueError, "logarithm of 0" if isinstance(x, (ComplexFloat, complex)): mag = abs(x) phase = atan2(x.imag, x.real) return ComplexFloat(log(mag), phase) if not isinstance(x, Float): x = Float(x) if x < 0: return log(ComplexFloat(x)) if x == 1: return Float((0, 0)) bc = bitcount(x.man) # Estimated precision needed for log(t) + n*log(2) prec = Float._prec + int(_clog(1 + abs(bc + x.exp), 2)) + 10 # Watch out for the case when x is very close to 1 if -1 < bc + x.exp < 2: near_one = abs(x - 1) if near_one == 0: return Float((0, 0)) prec += -(near_one.exp) - bitcount(near_one.man) # Separate mantissa and exponent, calculate fixed-point # approximation and put it all together t = _rshift(x.man, bc - prec) l = _log_newton(t, prec) a = (x.exp + bc) * log2_fixed(prec) return Float((l + a, -prec))
def exp(x): """ exp(x) -- compute the exponential function of the real or complex number x """ if isinstance(x, (ComplexFloat, complex)): mag = exp(x.real) re, im = cos_sin(x.imag) return ComplexFloat(mag * re, mag * im) else: if not isinstance(x, Float): x = Float(x) # extra precision needs to be similar in magnitude to log_2(|x|) prec = Float._prec + 4 + max(0, bitcount(x.man) + x.exp) t = make_fixed(x, prec) if abs(x) > 1: lg2 = log2_fixed(prec) n, t = divmod(t, lg2) else: n = 0 y = _exp_series(t, prec) return Float((y, -prec + n))