def c_sinh(x, y): # special treatment for sinh(+/-inf + iy) if y is finite and nonzero if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) else: real = -copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) r = (real, imag) else: r = sinh_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/- infinity and x is not # a NaN if isinf(y) and not isnan(x): raise ValueError("math domain error") return r if fabs(x) > CM_LOG_LARGE_DOUBLE: x_minus_one = x - copysign(1., x) real = math.cos(y) * math.sinh(x_minus_one) * math.e imag = math.sin(y) * math.cosh(x_minus_one) * math.e else: real = math.cos(y) * math.sinh(x) imag = math.sin(y) * math.cosh(x) if isinf(real) or isinf(imag): raise OverflowError("math range error") return real, imag
def c_exp(x, y): if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) else: real = copysign(0., math.cos(y)) imag = copysign(0., math.sin(y)) r = (real, imag) else: r = exp_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/- infinity and x is not # a NaN and not -infinity if isinf(y) and (isfinite(x) or (isinf(x) and x > 0)): raise ValueError("math domain error") return r if x > CM_LOG_LARGE_DOUBLE: l = math.exp(x-1.) real = l * math.cos(y) * math.e imag = l * math.sin(y) * math.e else: l = math.exp(x) real = l * math.cos(y) imag = l * math.sin(y) if isinf(real) or isinf(imag): raise OverflowError("math range error") return real, imag
def c_cosh(x, y): if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) else: real = copysign(INF, math.cos(y)) imag = -copysign(INF, math.sin(y)) r = (real, imag) else: r = cosh_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/- infinity and x is not # a NaN if isinf(y) and not isnan(x): raise ValueError("math domain error") return r if fabs(x) > CM_LOG_LARGE_DOUBLE: # deal correctly with cases where cosh(x) overflows but # cosh(z) does not. x_minus_one = x - copysign(1., x) real = math.cos(y) * math.cosh(x_minus_one) * math.e imag = math.sin(y) * math.sinh(x_minus_one) * math.e else: real = math.cos(y) * math.cosh(x) imag = math.sin(y) * math.sinh(x) if isinf(real) or isinf(imag): raise OverflowError("math range error") 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_rect(r, phi): if not isfinite(r) or not isfinite(phi): # if r is +/-infinity and phi is finite but nonzero then # result is (+-INF +-INF i), but we need to compute cos(phi) # and sin(phi) to figure out the signs. if isinf(r) and isfinite(phi) and phi != 0.: if r > 0: real = copysign(INF, math.cos(phi)) imag = copysign(INF, math.sin(phi)) else: real = -copysign(INF, math.cos(phi)) imag = -copysign(INF, math.sin(phi)) z = (real, imag) else: z = rect_special_values[special_type(r)][special_type(phi)] # need to raise ValueError if r is a nonzero number and phi # is infinite if r != 0. and not isnan(r) and isinf(phi): raise ValueError("math domain error") return z real = r * math.cos(phi) imag = r * math.sin(phi) 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_exp(x, y): if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = copysign(INF, math.cos(y)) imag = copysign(INF, math.sin(y)) else: real = copysign(0., math.cos(y)) imag = copysign(0., math.sin(y)) r = (real, imag) else: r = exp_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/- infinity and x is not # a NaN and not -infinity if isinf(y) and (isfinite(x) or (isinf(x) and x > 0)): raise ValueError("math domain error") return r if x > CM_LOG_LARGE_DOUBLE: l = math.exp(x - 1.) real = l * math.cos(y) * math.e imag = l * math.sin(y) * math.e else: l = math.exp(x) real = l * math.cos(y) imag = l * math.sin(y) if isinf(real) or isinf(imag): raise OverflowError("math range error") 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 ll_math_pow(x, y): # deal directly with IEEE specials, to cope with problems on various # platforms whose semantics don't exactly match C99 if isnan(y): if x == 1.0: return 1.0 # 1**Nan = 1 return y if not isfinite(x): if isnan(x): if y == 0.0: return 1.0 # NaN**0 = 1 return x else: # isinf(x) odd_y = not isinf(y) and math_fmod(math_fabs(y), 2.0) == 1.0 if y > 0.0: if odd_y: return x return math_fabs(x) elif y == 0.0: return 1.0 else: # y < 0.0 if odd_y: return math_copysign(0.0, x) return 0.0 if isinf(y): if math_fabs(x) == 1.0: return 1.0 elif y > 0.0 and math_fabs(x) > 1.0: return y elif y < 0.0 and math_fabs(x) < 1.0: if x == 0.0: raise ValueError("0**-inf: divide by zero") return -y # result is +inf else: return 0.0 _error_reset() r = math_pow(x, y) errno = rposix.get_errno() if not isfinite(r): if isnan(r): # a NaN result should arise only from (-ve)**(finite non-integer) errno = EDOM else: # isinf(r) # an infinite result here arises either from: # (A) (+/-0.)**negative (-> divide-by-zero) # (B) overflow of x**y with x and y finite if x == 0.0: errno = EDOM else: errno = ERANGE if errno: _likely_raise(errno, r) return r
def ll_math_pow(x, y): # deal directly with IEEE specials, to cope with problems on various # platforms whose semantics don't exactly match C99 if math.isnan(y): if x == 1.0: return 1.0 # 1**Nan = 1 return y if not isfinite(x): if math.isnan(x): if y == 0.0: return 1.0 # NaN**0 = 1 return x else: # isinf(x) odd_y = not math.isinf(y) and math_fmod(math_fabs(y), 2.0) == 1.0 if y > 0.0: if odd_y: return x return math_fabs(x) elif y == 0.0: return 1.0 else: # y < 0.0 if odd_y: return math_copysign(0.0, x) return 0.0 if math.isinf(y): if math_fabs(x) == 1.0: return 1.0 elif y > 0.0 and math_fabs(x) > 1.0: return y elif y < 0.0 and math_fabs(x) < 1.0: if x == 0.0: raise ValueError("0**-inf: divide by zero") return -y # result is +inf else: return 0.0 r = math_pow(x, y) errno = rposix.get_saved_errno() if not isfinite(r): if math.isnan(r): # a NaN result should arise only from (-ve)**(finite non-integer) errno = EDOM else: # isinf(r) # an infinite result here arises either from: # (A) (+/-0.)**negative (-> divide-by-zero) # (B) overflow of x**y with x and y finite if x == 0.0: errno = EDOM else: errno = ERANGE if errno: _likely_raise(errno, r) return r
def c_sqrt(x, y): ''' Method: use symmetries to reduce to the case when x = z.real and y = z.imag are nonnegative. Then the real part of the result is given by s = sqrt((x + hypot(x, y))/2) and the imaginary part is d = (y/2)/s If either x or y is very large then there's a risk of overflow in computation of the expression x + hypot(x, y). We can avoid this by rewriting the formula for s as: s = 2*sqrt(x/8 + hypot(x/8, y/8)) This costs us two extra multiplications/divisions, but avoids the overhead of checking for x and y large. If both x and y are subnormal then hypot(x, y) may also be subnormal, so will lack full precision. We solve this by rescaling x and y by a sufficiently large power of 2 to ensure that x and y are normal. ''' if not isfinite(x) or not isfinite(y): return sqrt_special_values[special_type(x)][special_type(y)] if x == 0. and y == 0.: return (0., y) ax = fabs(x) ay = fabs(y) if ax < DBL_MIN and ay < DBL_MIN and (ax > 0. or ay > 0.): # here we catch cases where hypot(ax, ay) is subnormal ax = math.ldexp(ax, CM_SCALE_UP) ay1= math.ldexp(ay, CM_SCALE_UP) s = math.ldexp(math.sqrt(ax + math.hypot(ax, ay1)), CM_SCALE_DOWN) else: ax /= 8. s = 2.*math.sqrt(ax + math.hypot(ax, ay/8.)) d = ay/(2.*s) if x >= 0.: return (s, copysign(d, y)) else: return (d, copysign(s, y))
def c_sqrt(x, y): ''' Method: use symmetries to reduce to the case when x = z.real and y = z.imag are nonnegative. Then the real part of the result is given by s = sqrt((x + hypot(x, y))/2) and the imaginary part is d = (y/2)/s If either x or y is very large then there's a risk of overflow in computation of the expression x + hypot(x, y). We can avoid this by rewriting the formula for s as: s = 2*sqrt(x/8 + hypot(x/8, y/8)) This costs us two extra multiplications/divisions, but avoids the overhead of checking for x and y large. If both x and y are subnormal then hypot(x, y) may also be subnormal, so will lack full precision. We solve this by rescaling x and y by a sufficiently large power of 2 to ensure that x and y are normal. ''' if not isfinite(x) or not isfinite(y): return sqrt_special_values[special_type(x)][special_type(y)] if x == 0. and y == 0.: return (0., y) ax = fabs(x) ay = fabs(y) if ax < DBL_MIN and ay < DBL_MIN and (ax > 0. or ay > 0.): # here we catch cases where hypot(ax, ay) is subnormal ax = math.ldexp(ax, CM_SCALE_UP) ay1 = math.ldexp(ay, CM_SCALE_UP) s = math.ldexp(math.sqrt(ax + math.hypot(ax, ay1)), CM_SCALE_DOWN) else: ax /= 8. s = 2. * math.sqrt(ax + math.hypot(ax, ay / 8.)) d = ay / (2. * s) if x >= 0.: return (s, copysign(d, y)) else: return (d, copysign(s, y))
def ll_math_atan2(y, x): """wrapper for atan2 that deals directly with special cases before delegating to the platform libm for the remaining cases. This is necessary to get consistent behaviour across platforms. Windows, FreeBSD and alpha Tru64 are amongst platforms that don't always follow C99. """ if math.isnan(x): return NAN if not isfinite(y): if math.isnan(y): return NAN if math.isinf(x): if math_copysign(1.0, x) == 1.0: # atan2(+-inf, +inf) == +-pi/4 return math_copysign(0.25 * math.pi, y) else: # atan2(+-inf, -inf) == +-pi*3/4 return math_copysign(0.75 * math.pi, y) # atan2(+-inf, x) == +-pi/2 for finite x return math_copysign(0.5 * math.pi, y) if math.isinf(x) or y == 0.0: if math_copysign(1.0, x) == 1.0: # atan2(+-y, +inf) = atan2(+-0, +x) = +-0. return math_copysign(0.0, y) else: # atan2(+-y, -inf) = atan2(+-0., -x) = +-pi. return math_copysign(math.pi, y) return math_atan2(y, x)
def ll_math_atan2(y, x): """wrapper for atan2 that deals directly with special cases before delegating to the platform libm for the remaining cases. This is necessary to get consistent behaviour across platforms. Windows, FreeBSD and alpha Tru64 are amongst platforms that don't always follow C99. """ if isnan(x): return NAN if not isfinite(y): if isnan(y): return NAN if isinf(x): if math_copysign(1.0, x) == 1.0: # atan2(+-inf, +inf) == +-pi/4 return math_copysign(0.25 * math.pi, y) else: # atan2(+-inf, -inf) == +-pi*3/4 return math_copysign(0.75 * math.pi, y) # atan2(+-inf, x) == +-pi/2 for finite x return math_copysign(0.5 * math.pi, y) if isinf(x) or y == 0.0: if math_copysign(1.0, x) == 1.0: # atan2(+-y, +inf) = atan2(+-0, +x) = +-0. return math_copysign(0.0, y) else: # atan2(+-y, -inf) = atan2(+-0., -x) = +-pi. return math_copysign(math.pi, y) return math_atan2(y, x)
def generic_initializationexpr(db, value, access_expr, decoration): if isinstance(typeOf(value), ContainerType): node = db.getcontainernode(value) lines = list(node.initializationexpr(decoration+'.')) lines[-1] += ',' return lines else: comma = ',' if typeOf(value) == Float and not isfinite(value): db.late_initializations.append(('%s' % access_expr, db.get(value))) if math.isinf(value): name = '-+'[value > 0] + 'inf' else: name = 'NaN' expr = '0.0 /* patched later with %s */' % (name,) else: expr = db.get(value) if typeOf(value) is Void: comma = '' expr += comma i = expr.find('\n') if i < 0: i = len(expr) expr = '%s\t/* %s */%s' % (expr[:i], decoration, expr[i:]) return expr.split('\n')
def _round_float(space, w_float, w_ndigits=None): # Algorithm copied directly from CPython x = w_float.floatval if w_ndigits is None: # single-argument round: round to nearest integer rounded = rfloat.round_away(x) if math.fabs(x - rounded) == 0.5: # halfway case: round to even rounded = 2.0 * rfloat.round_away(x / 2.0) return newlong_from_float(space, rounded) # interpret 2nd argument as a Py_ssize_t; clip on overflow ndigits = space.getindex_w(w_ndigits, None) # nans and infinities round to themselves if not rfloat.isfinite(x): return space.newfloat(x) # Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x # always rounds to itself. For ndigits < NDIGITS_MIN, x always # rounds to +-0.0 if ndigits > NDIGITS_MAX: return space.newfloat(x) elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x return space.newfloat(0.0 * x) # finite x, and ndigits is not unreasonably large z = rfloat.round_double(x, ndigits, half_even=True) if math.isinf(z): raise oefmt(space.w_OverflowError, "overflow occurred during round") return space.newfloat(z)
def _hash_float(space, v): if not isfinite(v): if math.isinf(v): return HASH_INF if v > 0 else -HASH_INF return HASH_NAN m, e = math.frexp(v) sign = 1 if m < 0: sign = -1 m = -m # process 28 bits at a time; this should work well both for binary # and hexadecimal floating point. x = r_uint(0) while m: x = ((x << 28) & HASH_MODULUS) | x >> (HASH_BITS - 28) m *= 268435456.0 # 2**28 e -= 28 y = r_uint(m) # pull out integer part m -= y x += y if x >= HASH_MODULUS: x -= HASH_MODULUS # adjust for the exponent; first reduce it modulo HASH_BITS e = e % HASH_BITS if e >= 0 else HASH_BITS - 1 - ((-1 - e) % HASH_BITS) x = ((x << e) & HASH_MODULUS) | x >> (HASH_BITS - e) x = intmask(intmask(x) * sign) return -2 if x == -1 else x
def generic_initializationexpr(db, value, access_expr, decoration): if isinstance(typeOf(value), ContainerType): node = db.getcontainernode(value) lines = list(node.initializationexpr(decoration + ".")) lines[-1] += "," return lines else: comma = "," if typeOf(value) == Float and not isfinite(value): db.late_initializations.append(("%s" % access_expr, db.get(value))) if isinf(value): name = "-+"[value > 0] + "inf" else: name = "NaN" expr = "0.0 /* patched later with %s */" % (name,) else: expr = db.get(value) if typeOf(value) is Void: comma = "" expr += comma i = expr.find("\n") if i < 0: i = len(expr) expr = "%s\t/* %s */%s" % (expr[:i], decoration, expr[i:]) return expr.split("\n")
def _round_float(space, w_float, w_ndigits=None): # Algorithm copied directly from CPython x = w_float.floatval if w_ndigits is None: # single-argument round: round to nearest integer rounded = rfloat.round_away(x) if math.fabs(x - rounded) == 0.5: # halfway case: round to even rounded = 2.0 * rfloat.round_away(x / 2.0) return newlong_from_float(space, rounded) # interpret 2nd argument as a Py_ssize_t; clip on overflow ndigits = space.getindex_w(w_ndigits, None) # nans and infinities round to themselves if not rfloat.isfinite(x): return space.wrap(x) # Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x # always rounds to itself. For ndigits < NDIGITS_MIN, x always # rounds to +-0.0 if ndigits > NDIGITS_MAX: return space.wrap(x) elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x return space.wrap(0.0 * x) # finite x, and ndigits is not unreasonably large z = rfloat.round_double(x, ndigits, half_even=True) if rfloat.isinf(z): raise oefmt(space.w_OverflowError, "overflow occurred during round") return space.wrap(z)
def _hash_float(space, v): if not isfinite(v): if isinf(v): return HASH_INF if v > 0 else -HASH_INF return HASH_NAN m, e = math.frexp(v) sign = 1 if m < 0: sign = -1 m = -m # process 28 bits at a time; this should work well both for binary # and hexadecimal floating point. x = r_uint(0) while m: x = ((x << 28) & HASH_MODULUS) | x >> (HASH_BITS - 28) m *= 268435456.0 # 2**28 e -= 28 y = r_uint(m) # pull out integer part m -= y x += y if x >= HASH_MODULUS: x -= HASH_MODULUS # adjust for the exponent; first reduce it modulo HASH_BITS e = e % HASH_BITS if e >= 0 else HASH_BITS - 1 - ((-1 - e) % HASH_BITS) x = ((x << e) & HASH_MODULUS) | x >> (HASH_BITS - e) x = intmask(intmask(x) * sign) return -2 if x == -1 else x
def round(space, number, w_ndigits): """round(number[, ndigits]) -> floating point number Round a number to a given precision in decimal digits (default 0 digits). This always returns a floating point number. Precision may be negative.""" # Algorithm copied directly from CPython # interpret 2nd argument as a Py_ssize_t; clip on overflow ndigits = space.getindex_w(w_ndigits, None) # nans, infinities and zeros round to themselves if not isfinite(number): z = number elif ndigits == 0: # common case z = round_away(number) # no need to check for an infinite 'z' here else: # Deal with extreme values for ndigits. For ndigits > NDIGITS_MAX, x # always rounds to itself. For ndigits < NDIGITS_MIN, x always # rounds to +-0.0. if ndigits > NDIGITS_MAX: z = number elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x z = 0.0 * number else: # finite x, and ndigits is not unreasonably large z = round_double(number, ndigits) if isinf(z): raise oefmt(space.w_OverflowError, "rounded value too large to represent") return space.newfloat(z)
def descr_hex(self, space): TOHEX_NBITS = rfloat.DBL_MANT_DIG + 3 - (rfloat.DBL_MANT_DIG + 2) % 4 value = self.floatval if not isfinite(value): return self.descr_str(space) if value == 0.0: if copysign(1., value) == -1.: return space.wrap("-0x0.0p+0") else: return space.wrap("0x0.0p+0") mant, exp = math.frexp(value) shift = 1 - max(rfloat.DBL_MIN_EXP - exp, 0) mant = math.ldexp(mant, shift) mant = abs(mant) exp -= shift result = ['\0'] * ((TOHEX_NBITS - 1) // 4 + 2) result[0] = _char_from_hex(int(mant)) mant -= int(mant) result[1] = "." for i in range((TOHEX_NBITS - 1) // 4): mant *= 16.0 result[i + 2] = _char_from_hex(int(mant)) mant -= int(mant) if exp < 0: sign = "-" else: sign = "+" exp = abs(exp) s = ''.join(result) if value < 0.0: return space.wrap("-0x%sp%s%d" % (s, sign, exp)) else: return space.wrap("0x%sp%s%d" % (s, sign, exp))
def generic_initializationexpr(db, value, access_expr, decoration): if isinstance(typeOf(value), ContainerType): node = db.getcontainernode(value) lines = list(node.initializationexpr(decoration+'.')) lines[-1] += ',' return lines else: comma = ',' if typeOf(value) == Float and not isfinite(value): db.late_initializations.append(('%s' % access_expr, db.get(value))) if isinf(value): name = '-+'[value > 0] + 'inf' else: name = 'NaN' expr = '0.0 /* patched later with %s */' % (name,) else: expr = db.get(value) if typeOf(value) is Void: comma = '' expr += comma i = expr.find('\n') if i < 0: i = len(expr) expr = '%s\t/* %s */%s' % (expr[:i], decoration, expr[i:]) return expr.split('\n')
def c_acosh(x, y): # 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 acosh_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: # avoid unnecessary overflow for large arguments real = math.log(math.hypot(x / 2., y / 2.)) + M_LN2 * 2. imag = math.atan2(y, x) else: s1x, s1y = c_sqrt(x - 1., y) s2x, s2y = c_sqrt(x + 1., y) real = asinh(s1x * s2x + s1y * s2y) imag = 2. * math.atan2(s1y, s2x) return (real, imag)
def c_acosh(x, y): # 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 acosh_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: # avoid unnecessary overflow for large arguments real = math.log(math.hypot(x/2., y/2.)) + M_LN2*2. imag = math.atan2(y, x) else: s1x, s1y = c_sqrt(x - 1., y) s2x, s2y = c_sqrt(x + 1., y) real = asinh(s1x*s2x + s1y*s2y) imag = 2.*math.atan2(s1y, s2x) return (real, imag)
def ll_math_sqrt(x): if x < 0.0: raise ValueError("math domain error") if isfinite(x): return sqrt_nonneg(x) return x # +inf or nan
def c_abs(r, i): if not isfinite(r) or not isfinite(i): # C99 rules: if either the real or the imaginary part is an # infinity, return infinity, even if the other part is a NaN. if isinf(r): return INF if isinf(i): return INF # either the real or imaginary part is a NaN, # and neither is infinite. Result should be NaN. return NAN result = math.hypot(r, i) if not isfinite(result): raise OverflowError("math range error") return result
def float_pack80(x, size): """Convert a Python float or longfloat x into two 64-bit unsigned integers with 80 bit extended representation.""" x = float(x) # longfloat not really supported if size == 10 or size == 12 or size == 16: MIN_EXP = -16381 MAX_EXP = 16384 MANT_DIG = 64 BITS = 80 else: raise ValueError("invalid size value") sign = rfloat.copysign(1.0, x) < 0.0 if not rfloat.isfinite(x): if rfloat.isinf(x): mant = r_ulonglong(0) exp = MAX_EXP - MIN_EXP + 2 else: # rfloat.isnan(x): mant = (r_ulonglong(1) << (MANT_DIG - 2)) - 1 # other values possible exp = MAX_EXP - MIN_EXP + 2 elif x == 0.0: mant = r_ulonglong(0) exp = 0 else: m, e = math.frexp(abs(x)) # abs(x) == m * 2**e exp = e - (MIN_EXP - 1) if exp > 0: # Normal case. Avoid uint64 overflow by using MANT_DIG-1 mant = round_to_nearest(m * (r_ulonglong(1) << MANT_DIG - 1)) else: # Subnormal case. if exp + MANT_DIG - 1 >= 0: mant = round_to_nearest(m * (r_ulonglong(1) << exp + MANT_DIG - 1)) else: mant = r_ulonglong(0) exp = 0 # Special case: rounding produced a MANT_DIG-bit mantissa. if mant == r_ulonglong(1) << MANT_DIG - 1: mant = r_ulonglong(0) exp += 1 # Raise on overflow (in some circumstances, may want to return # infinity instead). if exp >= MAX_EXP - MIN_EXP + 2: raise OverflowError("float too large to pack in this format") # check constraints if not objectmodel.we_are_translated(): assert 0 <= mant < 1 << MANT_DIG - 1 assert 0 <= exp <= MAX_EXP - MIN_EXP + 2 assert 0 <= sign <= 1 mant = mant << 1 exp = r_ulonglong(exp) sign = r_ulonglong(sign) return (mant, (sign << BITS - MANT_DIG - 1) | exp)
def c_asinh(x, y): if not isfinite(x) or not isfinite(y): return asinh_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: if y >= 0.: real = copysign(math.log(math.hypot(x/2., y/2.)) + M_LN2*2., x) else: real = -copysign(math.log(math.hypot(x/2., y/2.)) + M_LN2*2., -x) imag = math.atan2(y, fabs(x)) else: s1x, s1y = c_sqrt(1.+y, -x) s2x, s2y = c_sqrt(1.-y, x) real = asinh(s1x*s2y - s2x*s1y) imag = math.atan2(y, s1x*s2x - s1y*s2y) return (real, imag)
def c_asinh(x, y): if not isfinite(x) or not isfinite(y): return asinh_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: if y >= 0.: real = copysign( math.log(math.hypot(x / 2., y / 2.)) + M_LN2 * 2., x) else: real = -copysign( math.log(math.hypot(x / 2., y / 2.)) + M_LN2 * 2., -x) imag = math.atan2(y, fabs(x)) else: s1x, s1y = c_sqrt(1. + y, -x) s2x, s2y = c_sqrt(1. - y, x) real = asinh(s1x * s2y - s2x * s1y) imag = math.atan2(y, s1x * s2x - s1y * s2y) return (real, imag)
def do_compare_bigint(f1, b2): """f1 is a float. b2 is a bigint.""" if not isfinite(f1) or math.floor(f1) != f1: return opname == 'ne' b1 = rbigint.fromfloat(f1) res = b1.eq(b2) if opname == 'ne': res = not res return res
def ll_math(x): r = c_func(x) # Error checking fun. Copied from CPython 2.6 errno = rposix.get_saved_errno() if not isfinite(r): if isnan(r): if isnan(x): errno = 0 else: errno = EDOM else: # isinf(r) if not isfinite(x): errno = 0 elif can_overflow: errno = ERANGE else: errno = EDOM if errno: _likely_raise(errno, r) return r
def float_to_string(x, code='g', precision=DTSF_STR_PRECISION): if isfinite(x): s = formatd(x, code, precision, DTSF_ADD_DOT_0) elif isinf(x): if x > 0.0: s = "inf" else: s = "-inf" else: # isnan(x): s = "nan" return s.decode('utf-8')
def ll_math(x): r = c_func(x) # Error checking fun. Copied from CPython 2.6 errno = rposix.get_saved_errno() if not isfinite(r): if math.isnan(r): if math.isnan(x): errno = 0 else: errno = EDOM else: # isinf(r) if not isfinite(x): errno = 0 elif can_overflow: errno = ERANGE else: errno = EDOM if errno: _likely_raise(errno, r) return r
def float2string(x, code, precision): # we special-case explicitly inf and nan here if isfinite(x): s = formatd(x, code, precision, DTSF_ADD_DOT_0) elif isinf(x): if x > 0.0: s = "inf" else: s = "-inf" else: # isnan(x): s = "nan" return s
def c_acos(x, y): if not isfinite(x) or not isfinite(y): return acos_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: # avoid unnecessary overflow for large arguments real = math.atan2(fabs(y), x) # split into cases to make sure that the branch cut has the # correct continuity on systems with unsigned zeros if x < 0.: imag = -copysign(math.log(math.hypot(x/2., y/2.)) + M_LN2*2., y) else: imag = copysign(math.log(math.hypot(x/2., y/2.)) + M_LN2*2., -y) else: s1x, s1y = c_sqrt(1.-x, -y) s2x, s2y = c_sqrt(1.+x, y) real = 2.*math.atan2(s1x, s2x) imag = asinh(s2x*s1y - s2y*s1x) return (real, imag)
def c_acos(x, y): if not isfinite(x) or not isfinite(y): return acos_special_values[special_type(x)][special_type(y)] if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE: # avoid unnecessary overflow for large arguments real = math.atan2(fabs(y), x) # split into cases to make sure that the branch cut has the # correct continuity on systems with unsigned zeros if x < 0.: imag = -copysign( math.log(math.hypot(x / 2., y / 2.)) + M_LN2 * 2., y) else: imag = copysign( math.log(math.hypot(x / 2., y / 2.)) + M_LN2 * 2., -y) else: s1x, s1y = c_sqrt(1. - x, -y) s2x, s2y = c_sqrt(1. + x, y) real = 2. * math.atan2(s1x, s2x) imag = asinh(s2x * s1y - s2y * s1x) return (real, imag)
def c_tanh(x, y): # Formula: # # tanh(x+iy) = (tanh(x)(1+tan(y)^2) + i tan(y)(1-tanh(x))^2) / # (1+tan(y)^2 tanh(x)^2) # # To avoid excessive roundoff error, 1-tanh(x)^2 is better computed # as 1/cosh(x)^2. When abs(x) is large, we approximate 1-tanh(x)^2 # by 4 exp(-2*x) instead, to avoid possible overflow in the # computation of cosh(x). if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = 1.0 # vv XXX why is the 2. there? imag = copysign(0., 2. * math.sin(y) * math.cos(y)) else: real = -1.0 imag = copysign(0., 2. * math.sin(y) * math.cos(y)) r = (real, imag) else: r = tanh_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/-infinity and x is finite if isinf(y) and isfinite(x): raise ValueError("math domain error") return r if fabs(x) > CM_LOG_LARGE_DOUBLE: real = copysign(1., x) imag = 4. * math.sin(y) * math.cos(y) * math.exp(-2.*fabs(x)) else: tx = math.tanh(x) ty = math.tan(y) cx = 1. / math.cosh(x) txty = tx * ty denom = 1. + txty * txty real = tx * (1. + ty*ty) / denom imag = ((ty / denom) * cx) * cx return real, imag
def c_tanh(x, y): # Formula: # # tanh(x+iy) = (tanh(x)(1+tan(y)^2) + i tan(y)(1-tanh(x))^2) / # (1+tan(y)^2 tanh(x)^2) # # To avoid excessive roundoff error, 1-tanh(x)^2 is better computed # as 1/cosh(x)^2. When abs(x) is large, we approximate 1-tanh(x)^2 # by 4 exp(-2*x) instead, to avoid possible overflow in the # computation of cosh(x). if not isfinite(x) or not isfinite(y): if isinf(x) and isfinite(y) and y != 0.: if x > 0: real = 1.0 # vv XXX why is the 2. there? imag = copysign(0., 2. * math.sin(y) * math.cos(y)) else: real = -1.0 imag = copysign(0., 2. * math.sin(y) * math.cos(y)) r = (real, imag) else: r = tanh_special_values[special_type(x)][special_type(y)] # need to raise ValueError if y is +/-infinity and x is finite if isinf(y) and isfinite(x): raise ValueError("math domain error") return r if fabs(x) > CM_LOG_LARGE_DOUBLE: real = copysign(1., x) imag = 4. * math.sin(y) * math.cos(y) * math.exp(-2. * fabs(x)) else: tx = math.tanh(x) ty = math.tan(y) cx = 1. / math.cosh(x) txty = tx * ty denom = 1. + txty * txty real = tx * (1. + ty * ty) / denom imag = ((ty / denom) * cx) * cx return real, imag
def ll_math_frexp(x): # deal with special cases directly, to sidestep platform differences if not isfinite(x) or not x: mantissa = x exponent = 0 else: exp_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw') try: mantissa = math_frexp(x, exp_p) exponent = rffi.cast(lltype.Signed, exp_p[0]) finally: lltype.free(exp_p, flavor='raw') return (mantissa, exponent)
def ll_math_hypot(x, y): # hypot(x, +/-Inf) returns Inf, even if x is a NaN. if isinf(x): return math_fabs(x) if isinf(y): return math_fabs(y) r = math_hypot(x, y) errno = rposix.get_saved_errno() if not isfinite(r): if isnan(r): if isnan(x) or isnan(y): errno = 0 else: errno = EDOM else: # isinf(r) if isfinite(x) and isfinite(y): errno = ERANGE else: errno = 0 if errno: _likely_raise(errno, r) return r
def ll_math_hypot(x, y): # hypot(x, +/-Inf) returns Inf, even if x is a NaN. if math.isinf(x): return math_fabs(x) if math.isinf(y): return math_fabs(y) r = math_hypot(x, y) errno = rposix.get_saved_errno() if not isfinite(r): if math.isnan(r): if math.isnan(x) or math.isnan(y): errno = 0 else: errno = EDOM else: # isinf(r) if isfinite(x) and isfinite(y): errno = ERANGE else: errno = 0 if errno: _likely_raise(errno, r) return r
def do_compare_bigint(f1, b2): """f1 is a float. b2 is a bigint.""" if not isfinite(f1): return op(f1, 0.0) if opname == 'gt' or opname == 'le': # 'float > long' <==> 'ceil(float) > long' # 'float <= long' <==> 'ceil(float) <= long' f1 = math.ceil(f1) else: # 'float < long' <==> 'floor(float) < long' # 'float >= long' <==> 'floor(float) >= long' f1 = math.floor(f1) b1 = rbigint.fromfloat(f1) return getattr(b1, opname)(b2)
def fsum(space, w_iterable): """Sum an iterable of floats, trying to keep precision.""" w_iter = space.iter(w_iterable) inf_sum = special_sum = 0.0 partials = [] while True: try: w_value = space.next(w_iter) except OperationError, e: if not e.match(space, space.w_StopIteration): raise break v = _get_double(space, w_value) original = v added = 0 for y in partials: if abs(v) < abs(y): v, y = y, v hi = v + y yr = hi - v lo = y - yr if lo != 0.0: partials[added] = lo added += 1 v = hi del partials[added:] if v != 0.0: if not rfloat.isfinite(v): if rfloat.isfinite(original): raise OperationError(space.w_OverflowError, space.wrap("intermediate overflow")) if rfloat.isinf(original): inf_sum += original special_sum += original del partials[:] else: partials.append(v)
def ll_math_fmod(x, y): # fmod(x, +/-Inf) returns x for finite x. if math.isinf(y) and isfinite(x): return x r = math_fmod(x, y) errno = rposix.get_saved_errno() if math.isnan(r): if math.isnan(x) or math.isnan(y): errno = 0 else: errno = EDOM if errno: _likely_raise(errno, r) return r
def ll_math_modf(x): # some platforms don't do the right thing for NaNs and # infinities, so we take care of special cases directly. if not isfinite(x): if isnan(x): return (x, x) else: # isinf(x) return (math_copysign(0.0, x), x) intpart_p = lltype.malloc(rffi.DOUBLEP.TO, 1, flavor='raw') try: fracpart = math_modf(x, intpart_p) intpart = intpart_p[0] finally: lltype.free(intpart_p, flavor='raw') return (fracpart, intpart)
def ll_math_fmod(x, y): # fmod(x, +/-Inf) returns x for finite x. if isinf(y) and isfinite(x): return x r = math_fmod(x, y) errno = rposix.get_saved_errno() if isnan(r): if isnan(x) or isnan(y): errno = 0 else: errno = EDOM if errno: _likely_raise(errno, r) return r