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)
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 (isinf(value) or isnan(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 (isinf(value) or isnan(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 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 pack_float(result, number, size, bigendian): """Append to 'result' the 'size' characters of the 32-bit or 64-bit IEEE representation of the number. """ if size == 4: bias = 127 exp = 8 prec = 23 else: bias = 1023 exp = 11 prec = 52 if isnan(number): sign = 0x80 man, e = 1.5, bias + 1 else: if number < 0: sign = 0x80 number *= -1 elif number == 0.0: for i in range(size): result.append('\x00') return else: sign = 0x00 if isinf(number): man, e = 1.0, bias + 1 else: man, e = math.frexp(number) if 0.5 <= man and man < 1.0: man *= 2 e -= 1 man -= 1 e += bias power_of_two = r_longlong(1) << prec mantissa = r_longlong(power_of_two * man + 0.5) if mantissa >> prec: mantissa = 0 e += 1 for i in range(size - 2): result.append(chr(mantissa & 0xff)) mantissa >>= 8 x = (mantissa & ((1 << (15 - exp)) - 1)) | ((e & ((1 << (exp - 7)) - 1)) << (15 - exp)) result.append(chr(x)) x = sign | e >> (exp - 7) result.append(chr(x)) if bigendian: first = len(result) - size last = len(result) - 1 for i in range(size // 2): (result[first + i], result[last - i]) = (result[last - i], result[first + i])
def eq__Float_Long(space, w_float1, w_long2): # XXX naive implementation x = w_float1.floatval if isinf(x) or math.floor(x) != x: return space.w_False try: w_long1 = W_LongObject.fromfloat(x) except OverflowError: return space.w_False return space.eq(w_long1, w_long2)
def name_float(value, db): if isinf(value): if value > 0: return '(Py_HUGE_VAL)' else: return '(-Py_HUGE_VAL)' elif isnan(value): return '(Py_HUGE_VAL/Py_HUGE_VAL)' else: return repr(value)
def pack_float(result, number, size, bigendian): """Append to 'result' the 'size' characters of the 32-bit or 64-bit IEEE representation of the number. """ if size == 4: bias = 127 exp = 8 prec = 23 else: bias = 1023 exp = 11 prec = 52 if isnan(number): sign = 0x80 man, e = 1.5, bias + 1 else: if number < 0: sign = 0x80 number *= -1 elif number == 0.0: for i in range(size): result.append('\x00') return else: sign = 0x00 if isinf(number): man, e = 1.0, bias + 1 else: man, e = math.frexp(number) if 0.5 <= man and man < 1.0: man *= 2 e -= 1 man -= 1 e += bias power_of_two = r_longlong(1) << prec mantissa = r_longlong(power_of_two * man + 0.5) if mantissa >> prec : mantissa = 0 e += 1 for i in range(size-2): result.append(chr(mantissa & 0xff)) mantissa >>= 8 x = (mantissa & ((1<<(15-exp))-1)) | ((e & ((1<<(exp-7))-1))<<(15-exp)) result.append(chr(x)) x = sign | e >> (exp - 7) result.append(chr(x)) if bigendian: first = len(result) - size last = len(result) - 1 for i in range(size // 2): (result[first + i], result[last - i]) = ( result[last - i], result[first + i])
def lt__Float_Long(space, w_float1, w_long2): # XXX naive implementation x = w_float1.floatval if isinf(x): return space.newbool(x < 0.0) x_floor = math.floor(x) try: w_long1 = W_LongObject.fromfloat(x_floor) except OverflowError: return space.newbool(x < 0.0) return space.lt(w_long1, w_long2)
def name_singlefloat(value, db): value = float(value) if isinf(value): if value > 0: return '((float)Py_HUGE_VAL)' else: return '((float)-Py_HUGE_VAL)' elif isnan(value): # XXX are these expressions ok? return '((float)(Py_HUGE_VAL/Py_HUGE_VAL))' else: return repr(value) + 'f'
def _push_double_constant(self, value): if isnan(value): jvm.DOUBLENAN.load(self) elif isinf(value): if value > 0: jvm.DOUBLEPOSINF.load(self) else: jvm.DOUBLENEGINF.load(self) elif value == 0.0: self.emit(jvm.DCONST_0) elif value == 1.0: self.emit(jvm.DCONST_1) else: # Big hack to avoid exponential notation: self.emit(jvm.LDC2, "%22.22f" % value)
def test_correct_tests(): import struct for number, size, bigendian, expected in testcases: if sys.version < (2, 5) and (isinf(number) or isnan(number)): continue # 'inf' and 'nan' unsupported in CPython 2.4's struct if bigendian: fmt = ">" else: fmt = "<" if size == 4: fmt += "f" else: fmt += "d" assert struct.pack(fmt, number) == expected res, = struct.unpack(fmt, expected) assert (isnan(res) and isnan(number)) or res == number or abs(res - number) < 1e-6
def test_correct_tests(): import struct for number, size, bigendian, expected in testcases: if sys.version < (2, 5) and (isinf(number) or isnan(number)): continue # 'inf' and 'nan' unsupported in CPython 2.4's struct if bigendian: fmt = '>' else: fmt = '<' if size == 4: fmt += 'f' else: fmt += 'd' assert struct.pack(fmt, number) == expected res, = struct.unpack(fmt, expected) assert (isnan(res) and isnan(number)) or \ res == number or abs(res - number) < 1E-6
def repr_float(self, type_, value): from pypy.rlib.rarithmetic import isinf, isnan if isinf(value) or isnan(value): # Need hex repr import struct packed = struct.pack("d", value) if sys.byteorder == 'little': packed = packed[::-1] repr = "0x" + "".join([("%02x" % ord(ii)) for ii in packed]) else: repr = "%f" % value # llvm requires a . when using e notation if "e" in repr and "." not in repr: repr = repr.replace("e", ".0e") return repr
def format_float(self, w_value, char): space = self.space x = space.float_w(maybe_float(space, w_value)) if isnan(x): r = 'nan' elif isinf(x): 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' try: r = formatd_overflow(self.f_alt, prec, char, x) except OverflowError: raise OperationError(space.w_OverflowError, space.wrap( "formatted float is too long (precision too large?)")) self.std_wp_number(r)
def repr_singlefloat(self, type_, value): from pypy.rlib.rarithmetic import isinf, isnan f = float(value) if isinf(f) or isnan(f): import struct packed = value._bytes if sys.byteorder == 'little': packed = packed[::-1] assert len(packed) == 4 repr = "0x" + "".join([("%02x" % ord(ii)) for ii in packed]) else: #repr = "%f" % f # XXX work around llvm2.1 bug, seems it doesnt like constants for floats repr = "fptrunc(double %f to float)" % f # llvm requires a . when using e notation if "e" in repr and "." not in repr: repr = repr.replace("e", ".0e") return repr
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, isinf, isnan if isinf(f): if f < 0.0: return -271828 else: return 314159 elif 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)