def test_nan_and_special_values(): from rpython.rlib.rfloat import isnan, isinf, isfinite, copysign inf = 1e300 * 1e300 assert isinf(inf) nan = inf/inf assert isnan(nan) for value, checker in [ (inf, lambda x: isinf(x) and x > 0.0), (-inf, lambda x: isinf(x) and x < 0.0), (nan, isnan), (42.0, isfinite), (0.0, lambda x: not x and copysign(1., x) == 1.), (-0.0, lambda x: not x and copysign(1., x) == -1.), ]: def f(): return value f1 = compile(f, []) res = f1() assert checker(res) l = [value] def g(x): return l[x] g2 = compile(g, [int]) res = g2(0) assert checker(res) l2 = [(-value, -value), (value, value)] def h(x): return l2[x][1] h3 = compile(h, [int]) res = h3(1) assert checker(res)
def test_math_sqrt(self): def f(x): try: return math.sqrt(x) except ValueError: return -INFINITY res = self.interp_operations(f, [0.0]) assert res == 0.0 self.check_operations_history(call_pure=1) # res = self.interp_operations(f, [25.0]) assert res == 5.0 self.check_operations_history(call_pure=1) # res = self.interp_operations(f, [-0.0]) assert str(res) == '-0.0' self.check_operations_history(call_pure=1) # res = self.interp_operations(f, [1000000.0]) assert res == 1000.0 self.check_operations_history(call_pure=1) # res = self.interp_operations(f, [-1.0]) assert res == -INFINITY self.check_operations_history(call_pure=0) # res = self.interp_operations(f, [INFINITY]) assert isinf(res) and not isnan(res) and res > 0.0 self.check_operations_history(call_pure=0) # res = self.interp_operations(f, [NAN]) assert isnan(res) and not isinf(res) self.check_operations_history(call_pure=0)
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 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 last_index_of(this, args): search_string = get_arg(args, 0) position = get_arg(args, 1) s = this.to_string() search_str = search_string.to_string() num_pos = position.ToNumber() from rpython.rlib.rfloat import INFINITY, isnan, isinf if isnan(num_pos): pos = INFINITY elif isinf(num_pos): pos = num_pos else: pos = int(num_pos) length = len(s) start = min(max(pos, 0), length) search_len = len(search_str) if isinf(start): idx = s.rfind(search_str) return idx end = int(start + search_len) assert end >= 0 idx = s.rfind(search_str, 0, end) return idx
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 number == 0 or isinf(number) or isnan(number): return space.wrap(number) # 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(number) elif ndigits < NDIGITS_MIN: # return 0.0, but with sign of x return space.wrap(0.0 * number) # 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.wrap(z)
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_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 division(ctx, nleft, nright): fleft = nleft.ToNumber() fright = nright.ToNumber() if isnan(fleft) or isnan(fright): return w_NAN if isinf(fleft) and isinf(fright): return w_NAN if isinf(fleft) and fright == 0: s = sign_of(fleft, fright) return w_signed_inf(s) if isinf(fright): return _w(0) if fleft == 0 and fright == 0: return w_NAN if fright == 0: s = sign_of(fleft, fright) return w_signed_inf(s) val = fleft / fright return W_FloatNumber(val)
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 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 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 push_primitive_constant(self, TYPE, value): ilasm = self.ilasm if TYPE is ootype.Void: pass elif TYPE is ootype.Bool: ilasm.opcode('ldc.i4', str(int(value))) elif TYPE is ootype.Char or TYPE is ootype.UniChar: ilasm.opcode('ldc.i4', ord(value)) elif TYPE is ootype.Float: if isinf(value): if value < 0.0: ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f0 ff)') else: ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f0 7f)') elif isnan(value): ilasm.opcode('ldc.r8', '(00 00 00 00 00 00 f8 ff)') else: ilasm.opcode('ldc.r8', repr(value)) elif isinstance(value, CDefinedIntSymbolic): ilasm.opcode('ldc.i4', DEFINED_INT_SYMBOLICS[value.expr]) elif TYPE in (ootype.Signed, ootype.Unsigned, rffi.SHORT): ilasm.opcode('ldc.i4', str(value)) elif TYPE in (ootype.SignedLongLong, ootype.UnsignedLongLong): ilasm.opcode('ldc.i8', str(value)) elif TYPE in (ootype.String, ootype.Unicode): if value._str is None: ilasm.opcode('ldnull') else: ilasm.opcode("ldstr", string_literal(value._str)) else: assert False, "Unexpected constant type"
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 var_dump(self, space, indent, recursion): if isinf(self.floatval): inf = "%s" % self.floatval return "%sfloat(%s)\n" % (indent, inf.upper()) if isnan(self.floatval): return "%sfloat(NAN)\n" % (indent,) return "%sfloat(%s)\n" % (indent, self.str(space))
def format_float(self, w_value, char): space = self.space x = space.float_w(maybe_float(space, w_value)) if isnan(x): if char in 'EFG': r = 'NAN' else: r = 'nan' elif isinf(x): if x < 0: if char in 'EFG': r = '-INF' else: r = '-inf' else: if char in 'EFG': r = 'INF' else: r = 'inf' else: prec = self.prec if prec < 0: prec = 6 if char in 'fF' and x/1e25 > 1e25: char = chr(ord(char) + 1) # 'f' => 'g' flags = 0 if self.f_alt: flags |= DTSF_ALT r = formatd(x, char, prec, flags) self.std_wp_number(r)
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 rfloat.isinf(x): mant = r_ulonglong(0) exp = MAX_EXP - MIN_EXP + 2 elif rfloat.isnan(x): # rfloat.isnan(x): asint = cast(ULONGLONG, float2longlong(x)) mant = asint & ((r_ulonglong(1) << 51) - 1) if mant == 0: mant = r_ulonglong(1) << (MANT_DIG - 1) - 1 sign = asint < 0 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") mant = mant << 1 # 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 exp = r_ulonglong(exp) sign = r_ulonglong(sign) return (mant, (sign << BITS - MANT_DIG - 1) | exp)
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 mod(ctx, w_left, w_right): left = w_left.ToNumber() right = w_right.ToNumber() if isnan(left) or isnan(right): return w_NAN if isinf(left) or right == 0: return w_NAN if isinf(right): return w_left if left == 0: return w_left return W_FloatNumber(math.fmod(left, right))
def is_finite(this, args): if len(args) < 1: return True n = args[0].ToNumber() if isinf(n) or isnan(n): return False else: return True
def arith_truncate(self): from rpython.rlib.rfloat import isinf if isinf(self.value): return self elif self.value < 0: return self.arith_ceiling() else: return self.arith_floor()
def isfinitejs(ctx, args, this): if len(args) < 1: return newbool(True) n = args[0].ToNumber(ctx) if isinf(n) or isnan(n): return newbool(False) else: return newbool(True)
def ToInteger(self): if isnan(self._floatval_): return 0 if self._floatval_ == 0 or isinf(self._floatval_): return int(self._floatval_) return intmask(int(self._floatval_))
def js_cos(this, args): arg0 = get_arg(args, 0) x = arg0.ToNumber() if isnan(x) or isinf(x): return NAN return math.cos(x)
def var_export(self, space, indent, recursion, suffix): if isinf(self.floatval): inf = "%s" % self.floatval return "%s" % inf.upper() if isnan(self.floatval): return "NAN" out = "%s%s%s" % (indent, self.str(space), suffix) return out
def test_complex_overflow(self): from numpy import array, absolute, isinf, complex128, floor_divide a = array(complex(1.5e308,1.5e308)) # Prints a RuntimeWarning, but does not raise b = absolute(a) assert isinf(b) c = array([1.e+110, 1.e-110], dtype=complex128) d = floor_divide(c**2, c) assert (d == [1.e+110, 0]).all()
def format_float(x, code, precision): # like float2string, except that the ".0" is not necessary if isinf(x): if x > 0.0: return "inf" else: return "-inf" elif isnan(x): return "nan" else: return formatd(x, code, precision)
def js_asin(this, args): arg0 = get_arg(args, 0) x = arg0.ToNumber() if isnan(x) or isinf(x): return NAN if x > 1 or x < -1: return NAN return math.asin(x)
def rAssertAlmostEqual(a, b, rel_err = 2e-15, abs_err = 5e-323, msg=''): """Fail if the two floating-point numbers are not almost equal. Determine whether floating-point values a and b are equal to within a (small) rounding error. The default values for rel_err and abs_err are chosen to be suitable for platforms where a float is represented by an IEEE 754 double. They allow an error of between 9 and 19 ulps. """ # special values testing if isnan(a): if isnan(b): return raise AssertionError(msg + '%r should be nan' % (b,)) if isinf(a): if a == b: return raise AssertionError(msg + 'finite result where infinity expected: ' 'expected %r, got %r' % (a, b)) # if both a and b are zero, check whether they have the same sign # (in theory there are examples where it would be legitimate for a # and b to have opposite signs; in practice these hardly ever # occur). if not a and not b: # only check it if we are running on top of CPython >= 2.6 if sys.version_info >= (2, 6) and copysign(1., a) != copysign(1., b): raise AssertionError(msg + 'zero has wrong sign: expected %r, ' 'got %r' % (a, b)) # if a-b overflows, or b is infinite, return False. Again, in # theory there are examples where a is within a few ulps of the # max representable float, and then b could legitimately be # infinite. In practice these examples are rare. try: absolute_error = abs(b-a) except OverflowError: pass else: # test passes if either the absolute error or the relative # error is sufficiently small. The defaults amount to an # error of between 9 ulps and 19 ulps on an IEEE-754 compliant # machine. if absolute_error <= max(abs_err, rel_err * abs(a)): return raise AssertionError(msg + '%r and %r are not sufficiently close' % (a, b))
def ll_math_ldexp(x, exp): if x == 0.0 or not isfinite(x): return x # NaNs, zeros and infinities are returned unchanged if exp > INT_MAX: # overflow (64-bit platforms only) r = math_copysign(INFINITY, x) errno = ERANGE elif exp < INT_MIN: # underflow to +-0 (64-bit platforms only) r = math_copysign(0.0, x) errno = 0 else: r = math_ldexp(x, exp) errno = rposix.get_saved_errno() if isinf(r): errno = ERANGE if errno: _likely_raise(errno, r) return r
def special_type(d): if isnan(d): return ST_NAN elif isinf(d): if d > 0.0: return ST_PINF else: return ST_NINF else: if d != 0.0: if d > 0.0: return ST_POS else: return ST_NEG else: if copysign(1., d) == 1.: return ST_PZERO else: return ST_NZERO
def js_round(this, args): arg0 = get_arg(args, 0) x = arg0.ToNumber() if isnan(x): return x if x == 0: return x if x > 0 and x < 0.5: return 0 if x < 0 and x >= -0.5: return -0.0 if isinf(x): return x return math.floor(x + 0.5)
def _hash_float(f): """The algorithm behind compute_hash() for a float. This implementation is identical to the CPython implementation, except the fact that the integer case is not treated specially. In RPython, floats cannot be used with ints in dicts, anyway. """ from rpython.rlib.rarithmetic import intmask from rpython.rlib.rfloat import isfinite, isinf if not isfinite(f): if isinf(f): if f < 0.0: return -271828 else: return 314159 else: #isnan(f): return 0 v, expo = math.frexp(f) v *= TAKE_NEXT hipart = int(v) v = (v - float(hipart)) * TAKE_NEXT x = hipart + int(v) + (expo << 15) return intmask(x)
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 to_string(self): # XXX incomplete, this doesn't follow the 9.8.1 recommendation if isnan(self._floatval_): return u'NaN' if isinf(self._floatval_): if self._floatval_ > 0: return u'Infinity' else: return u'-Infinity' if self._floatval_ == 0: return u'0' res = u'' try: res = unicode(formatd(self._floatval_, 'g', 10)) except OverflowError: raise if len(res) > 3 and (res[-3] == '+' or res[-3] == '-') and res[-2] == '0': cut = len(res) - 2 assert cut >= 0 res = res[:cut] + res[-1] return res
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 test_primitive_log_n(): assert prim(primitives.FLOAT_LOG_N, [1.0]).value == 0.0 assert prim(primitives.FLOAT_LOG_N, [math.e]).value == 1.0 assert float_equals(prim(primitives.FLOAT_LOG_N, [10.0]), math.log(10)) assert isinf(prim(primitives.FLOAT_LOG_N, [0.0]).value) # works also for negative infinity assert isnan(prim(primitives.FLOAT_LOG_N, [-1.0]).value)
class CConfig: _compilation_info_ = ExternalCompilationInfo(includes=['float.h']) DBL_MAX = rffi_platform.DefinedConstantDouble('DBL_MAX') DBL_MIN = rffi_platform.DefinedConstantDouble('DBL_MIN') DBL_MANT_DIG = rffi_platform.ConstantInteger('DBL_MANT_DIG') for k, v in rffi_platform.configure(CConfig).items(): assert v is not None, "no value found for %r" % k globals()[k] = v assert 0.0 < DBL_MAX < (1e200 * 1e200) assert isinf(DBL_MAX * 1.0001) assert DBL_MIN > 0.0 assert DBL_MIN * (2**-53) == 0.0 # Constants. M_LN2 = 0.6931471805599453094 # natural log of 2 M_LN10 = 2.302585092994045684 # natural log of 10 # CM_LARGE_DOUBLE is used to avoid spurious overflow in the sqrt, log, # inverse trig and inverse hyperbolic trig functions. Its log is used in the # evaluation of exp, cos, cosh, sin, sinh, tan, and tanh to avoid unecessary # overflow. CM_LARGE_DOUBLE = DBL_MAX / 4. CM_SQRT_LARGE_DOUBLE = math.sqrt(CM_LARGE_DOUBLE) CM_LOG_LARGE_DOUBLE = math.log(CM_LARGE_DOUBLE) CM_SQRT_DBL_MIN = math.sqrt(DBL_MIN)
def fn(x, y): n1 = x * x n2 = y * y * y return rfloat.isinf(n1 / n2)
def arith_ceiling(self): from rpython.rlib.rfloat import isinf if isinf(self.value): return self return values.W_Flonum(float(math.ceil(self.value)))
def test_abs_overflow(self): from numpy import array, absolute, isinf a = array(complex(1.5e308, 1.5e308)) # Prints a RuntimeWarning, but does not raise b = absolute(a) assert isinf(b)
def _pow(space, x, y): # Sort out special cases here instead of relying on pow() if y == 2.0: # special case for performance: return x * x # x * x is always correct if y == 0.0: # x**0 is 1, even 0**0 return 1.0 if isnan(x): # nan**y = nan, unless y == 0 return x if isnan(y): # x**nan = nan, unless x == 1; x**nan = x if x == 1.0: return 1.0 else: return y if isinf(y): # x**inf is: 0.0 if abs(x) < 1; 1.0 if abs(x) == 1; inf if # abs(x) > 1 (including case where x infinite) # # x**-inf is: inf if abs(x) < 1; 1.0 if abs(x) == 1; 0.0 if # abs(x) > 1 (including case where v infinite) x = abs(x) if x == 1.0: return 1.0 elif (y > 0.0) == (x > 1.0): return INFINITY else: return 0.0 if isinf(x): # (+-inf)**w is: inf for w positive, 0 for w negative; in oth # cases, we need to add the appropriate sign if w is an odd # integer. y_is_odd = math.fmod(abs(y), 2.0) == 1.0 if y > 0.0: if y_is_odd: return x else: return abs(x) else: if y_is_odd: return copysign(0.0, x) else: return 0.0 if x == 0.0: if y < 0.0: raise oefmt(space.w_ZeroDivisionError, "0.0 cannot be raised to a negative power") negate_result = False # special case: "(-1.0) ** bignum" should not raise PowDomainError, # unlike "math.pow(-1.0, bignum)". See http://mail.python.org/ # - pipermail/python-bugs-list/2003-March/016795.html if x < 0.0: if isnan(y): return NAN if math.floor(y) != y: raise PowDomainError # y is an exact integer, albeit perhaps a very large one. # Replace x by its absolute value and remember to negate the # pow result if y is odd. x = -x negate_result = math.fmod(abs(y), 2.0) == 1.0 if x == 1.0: # (-1) ** large_integer also ends up here if negate_result: return -1.0 else: return 1.0 try: # We delegate to our implementation of math.pow() the error detection. z = math.pow(x, y) except OverflowError: raise oefmt(space.w_OverflowError, "float power") except ValueError: raise oefmt(space.w_ValueError, "float power") if negate_result: z = -z return z
def isinf(space, w_x): """Return True if x is infinity.""" return space.wrap(rfloat.isinf(_get_double(space, w_x)))
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 as 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 oefmt(space.w_OverflowError, "intermediate overflow") if rfloat.isinf(original): inf_sum += original special_sum += original del partials[:] else: partials.append(v) if special_sum != 0.0: if rfloat.isnan(inf_sum): raise oefmt(space.w_ValueError, "-inf + inf") return space.newfloat(special_sum) hi = 0.0 if partials: hi = partials[-1] j = 0 lo = 0 for j in range(len(partials) - 2, -1, -1): v = hi y = partials[j] assert abs(y) < abs(v) hi = v + y yr = hi - v lo = y - yr if lo != 0.0: break if j > 0 and (lo < 0.0 and partials[j - 1] < 0.0 or lo > 0.0 and partials[j - 1] > 0.0): y = lo * 2.0 v = hi + y yr = v - hi if y == yr: hi = v return space.newfloat(hi)
def ll_math_cos(x): if isinf(x): raise ValueError("math domain error") return math_cos(x)
def c_isinf(r, i): return isinf(r) or isinf(i)
def float_pack(x, size): """Convert a Python float x into a 64-bit unsigned integer with the same byte representation.""" if size == 8: MIN_EXP = -1021 # = sys.float_info.min_exp MAX_EXP = 1024 # = sys.float_info.max_exp MANT_DIG = 53 # = sys.float_info.mant_dig BITS = 64 elif size == 4: MIN_EXP = -125 # C's FLT_MIN_EXP MAX_EXP = 128 # FLT_MAX_EXP MANT_DIG = 24 # FLT_MANT_DIG BITS = 32 elif size == 2: MIN_EXP = -13 MAX_EXP = 16 MANT_DIG = 11 BITS = 16 else: raise ValueError("invalid size value") sign = rfloat.copysign(1.0, x) < 0.0 if rfloat.isinf(x): mant = r_ulonglong(0) exp = MAX_EXP - MIN_EXP + 2 elif rfloat.isnan(x): asint = cast(ULONGLONG, float2longlong(x)) sign = asint >> 63 # shift off lower bits, perhaps losing data mant = asint & ((r_ulonglong(1) << 52) - 1) if MANT_DIG < 53: mant = mant >> (53 - MANT_DIG) if mant == 0: mant = r_ulonglong(1) << (MANT_DIG - 1) - 1 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. mant = round_to_nearest(m * (r_ulonglong(1) << MANT_DIG)) mant -= 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 not objectmodel.we_are_translated(): assert 0 <= mant <= 1 << MANT_DIG - 1 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 exp = r_ulonglong(exp) sign = r_ulonglong(sign) return ((sign << BITS - 1) | (exp << MANT_DIG - 1)) | mant