def logaddexp(self, v1, v2): tmp = v1 - v2 if tmp > 0: return v1 + rfloat.log1p(math.exp(-tmp)) elif tmp <= 0: return v2 + rfloat.log1p(math.exp(tmp)) else: return v1 + v2
def log1p(self, v): try: return rfloat.log1p(v) except OverflowError: return -rfloat.INFINITY except ValueError: return rfloat.NAN
def c_atanh(x, y): if not isfinite(x) or not isfinite(y): return atanh_special_values[special_type(x)][special_type(y)] # Reduce to case where x >= 0., using atanh(z) = -atanh(-z). if x < 0.: return c_neg(*c_atanh(*c_neg(x, y))) ay = fabs(y) if x > CM_SQRT_LARGE_DOUBLE or ay > CM_SQRT_LARGE_DOUBLE: # if abs(z) is large then we use the approximation # atanh(z) ~ 1/z +/- i*pi/2 (+/- depending on the sign # of y h = math.hypot(x/2., y/2.) # safe from overflow real = x/4./h/h # the two negations in the next line cancel each other out # except when working with unsigned zeros: they're there to # ensure that the branch cut has the correct continuity on # systems that don't support signed zeros imag = -copysign(math.pi/2., -y) elif x == 1. and ay < CM_SQRT_DBL_MIN: # C99 standard says: atanh(1+/-0.) should be inf +/- 0i if ay == 0.: raise ValueError("math domain error") #real = INF #imag = y else: real = -math.log(math.sqrt(ay)/math.sqrt(math.hypot(ay, 2.))) imag = copysign(math.atan2(2., -ay) / 2, y) else: real = log1p(4.*x/((1-x)*(1-x) + ay*ay))/4. imag = -math.atan2(-2.*y, (1-x)*(1+x) - ay*ay) / 2. return (real, imag)
def c_atanh(x, y): if not isfinite(x) or not isfinite(y): return atanh_special_values[special_type(x)][special_type(y)] # Reduce to case where x >= 0., using atanh(z) = -atanh(-z). if x < 0.: return c_neg(*c_atanh(*c_neg(x, y))) ay = fabs(y) if x > CM_SQRT_LARGE_DOUBLE or ay > CM_SQRT_LARGE_DOUBLE: # if abs(z) is large then we use the approximation # atanh(z) ~ 1/z +/- i*pi/2 (+/- depending on the sign # of y h = math.hypot(x / 2., y / 2.) # safe from overflow real = x / 4. / h / h # the two negations in the next line cancel each other out # except when working with unsigned zeros: they're there to # ensure that the branch cut has the correct continuity on # systems that don't support signed zeros imag = -copysign(math.pi / 2., -y) elif x == 1. and ay < CM_SQRT_DBL_MIN: # C99 standard says: atanh(1+/-0.) should be inf +/- 0i if ay == 0.: raise ValueError("math domain error") #real = INF #imag = y else: real = -math.log(math.sqrt(ay) / math.sqrt(math.hypot(ay, 2.))) imag = copysign(math.atan2(2., -ay) / 2, y) else: real = log1p(4. * x / ((1 - x) * (1 - x) + ay * ay)) / 4. imag = -math.atan2(-2. * y, (1 - x) * (1 + x) - ay * ay) / 2. return (real, imag)
def c_log(x, y): # The usual formula for the real part is log(hypot(z.real, z.imag)). # There are four situations where this formula is potentially # problematic: # # (1) the absolute value of z is subnormal. Then hypot is subnormal, # so has fewer than the usual number of bits of accuracy, hence may # have large relative error. This then gives a large absolute error # in the log. This can be solved by rescaling z by a suitable power # of 2. # # (2) the absolute value of z is greater than DBL_MAX (e.g. when both # z.real and z.imag are within a factor of 1/sqrt(2) of DBL_MAX) # Again, rescaling solves this. # # (3) the absolute value of z is close to 1. In this case it's # difficult to achieve good accuracy, at least in part because a # change of 1ulp in the real or imaginary part of z can result in a # change of billions of ulps in the correctly rounded answer. # # (4) z = 0. The simplest thing to do here is to call the # floating-point log with an argument of 0, and let its behaviour # (returning -infinity, signaling a floating-point exception, setting # errno, or whatever) determine that of c_log. So the usual formula # is fine here. # XXX the following two lines seem unnecessary at least on Linux; # the tests pass fine without them if not isfinite(x) or not isfinite(y): return log_special_values[special_type(x)][special_type(y)] ax = fabs(x) ay = fabs(y) if ax > CM_LARGE_DOUBLE or ay > CM_LARGE_DOUBLE: real = math.log(math.hypot(ax / 2., ay / 2.)) + M_LN2 elif ax < DBL_MIN and ay < DBL_MIN: if ax > 0. or ay > 0.: # catch cases where hypot(ax, ay) is subnormal real = math.log( math.hypot(math.ldexp(ax, DBL_MANT_DIG), math.ldexp(ay, DBL_MANT_DIG))) real -= DBL_MANT_DIG * M_LN2 else: # log(+/-0. +/- 0i) raise ValueError("math domain error") #real = -INF #imag = atan2(y, x) else: h = math.hypot(ax, ay) if 0.71 <= h and h <= 1.73: am = max(ax, ay) an = min(ax, ay) real = log1p((am - 1) * (am + 1) + an * an) / 2. else: real = math.log(h) imag = math.atan2(y, x) return (real, imag)
def c_log(x, y): # The usual formula for the real part is log(hypot(z.real, z.imag)). # There are four situations where this formula is potentially # problematic: # # (1) the absolute value of z is subnormal. Then hypot is subnormal, # so has fewer than the usual number of bits of accuracy, hence may # have large relative error. This then gives a large absolute error # in the log. This can be solved by rescaling z by a suitable power # of 2. # # (2) the absolute value of z is greater than DBL_MAX (e.g. when both # z.real and z.imag are within a factor of 1/sqrt(2) of DBL_MAX) # Again, rescaling solves this. # # (3) the absolute value of z is close to 1. In this case it's # difficult to achieve good accuracy, at least in part because a # change of 1ulp in the real or imaginary part of z can result in a # change of billions of ulps in the correctly rounded answer. # # (4) z = 0. The simplest thing to do here is to call the # floating-point log with an argument of 0, and let its behaviour # (returning -infinity, signaling a floating-point exception, setting # errno, or whatever) determine that of c_log. So the usual formula # is fine here. # XXX the following two lines seem unnecessary at least on Linux; # the tests pass fine without them if not isfinite(x) or not isfinite(y): return log_special_values[special_type(x)][special_type(y)] ax = fabs(x) ay = fabs(y) if ax > CM_LARGE_DOUBLE or ay > CM_LARGE_DOUBLE: real = math.log(math.hypot(ax/2., ay/2.)) + M_LN2 elif ax < DBL_MIN and ay < DBL_MIN: if ax > 0. or ay > 0.: # catch cases where hypot(ax, ay) is subnormal real = math.log(math.hypot(math.ldexp(ax, DBL_MANT_DIG), math.ldexp(ay, DBL_MANT_DIG))) real -= DBL_MANT_DIG*M_LN2 else: # log(+/-0. +/- 0i) raise ValueError("math domain error") #real = -INF #imag = atan2(y, x) else: h = math.hypot(ax, ay) if 0.71 <= h and h <= 1.73: am = max(ax, ay) an = min(ax, ay) real = log1p((am-1)*(am+1) + an*an) / 2. else: real = math.log(h) imag = math.atan2(y, x) return (real, imag)
def npy_log2_1p(self, v): return log2e * rfloat.log1p(v)