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 float_hex__Float(space, w_float): value = w_float.floatval if not isfinite(value): return str__Float(space, w_float) 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) == Ptr(PyObject) and value: # cannot just write 'gxxx' as a constant in a structure :-( node = db.getcontainernode(value._obj) expr = 'NULL /*%s*/' % node.name node.where_to_copy_me.append('&%s' % access_expr) elif typeOf(value) == Float and not isfinite(value): db.late_initializations.append(('%s' % access_expr, db.get(value))) expr = '0.0 /* patched later by %sinfinity */' % ('-+'[value > 0]) 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 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) == Ptr(PyObject) and value: # cannot just write 'gxxx' as a constant in a structure :-( node = db.getcontainernode(value._obj) expr = "NULL /*%s*/" % node.name node.where_to_copy_me.append("&%s" % access_expr) elif typeOf(value) == Float and not isfinite(value): db.late_initializations.append(("%s" % access_expr, db.get(value))) expr = "0.0 /* patched later by %sinfinity */" % ("-+"[value > 0]) 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 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 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 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): _error_reset() r = c_func(x) # Error checking fun. Copied from CPython 2.6 errno = rposix.get_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 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 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 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 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) _error_reset() r = math_hypot(x, y) errno = rposix.get_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_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 _error_reset() r = math_fmod(x, y) errno = rposix.get_errno() if isnan(r): if isnan(x) or isnan(y): errno = 0 else: errno = EDOM if errno: _likely_raise(errno, r) return r
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: _error_reset() r = math_ldexp(x, exp) errno = rposix.get_errno() if isinf(r): errno = ERANGE if errno: _likely_raise(errno, r) return r
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 pypy.rlib.rarithmetic import intmask from pypy.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 float_is_integer__Float(space, w_float): v = w_float.floatval if not rfloat.isfinite(v): return space.w_False return space.wrap(math.floor(v) == v)
def fn(x, y): n1 = x * x n2 = y * y * y return rfloat.isfinite(n1 / n2)
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 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) # 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. 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
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 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) # 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. 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