def f(x): if x == 0: s = '1.0' else: s = '1e-100' sign, beforept, afterpt, expt = break_up_float(s) return parts_to_float(sign, beforept, afterpt, expt)
def string_to_float(s): """ Conversion of string to float. This version tries to only raise on invalid literals. Overflows should be converted to infinity whenever possible. """ s = strip_spaces(s) if not s: raise ParseStringError("empty string for float()") # 1) parse the string into pieces. try: sign, before_point, after_point, exponent = break_up_float(s) except ValueError: raise ParseStringError("invalid literal for float()") if not before_point and not after_point: raise ParseStringError("invalid literal for float()") try: return parts_to_float(sign, before_point, after_point, exponent) except ValueError: raise ParseStringError("invalid literal for float()")
def ll_float(ll_str): from pypy.rpython.annlowlevel import hlstr from pypy.rlib.rarithmetic import break_up_float, parts_to_float s = hlstr(ll_str) assert s is not None n = len(s) beg = 0 while beg < n: if s[beg] == ' ': beg += 1 else: break if beg == n: raise ValueError end = n-1 while end >= 0: if s[end] == ' ': end -= 1 else: break assert end >= 0 sign, before_point, after_point, exponent = break_up_float(s[beg:end+1]) if not before_point and not after_point: raise ValueError return parts_to_float(sign, before_point, after_point, exponent)
def ll_float(ll_str): from pypy.rpython.annlowlevel import hlstr from pypy.rlib.rarithmetic import break_up_float, parts_to_float s = hlstr(ll_str) assert s is not None n = len(s) beg = 0 while beg < n: if s[beg] == ' ': beg += 1 else: break if beg == n: raise ValueError end = n - 1 while end >= 0: if s[end] == ' ': end -= 1 else: break assert end >= 0 sign, before_point, after_point, exponent = break_up_float(s[beg:end + 1]) if not before_point and not after_point: raise ValueError return parts_to_float(sign, before_point, after_point, exponent)
def test_break_up_float(): assert break_up_float('1') == ('', '1', '', '') assert break_up_float('+1') == ('+', '1', '', '') assert break_up_float('-1') == ('-', '1', '', '') assert break_up_float('.5') == ('', '', '5', '') assert break_up_float('1.2e3') == ('', '1', '2', '3') assert break_up_float('1.2e+3') == ('', '1', '2', '+3') assert break_up_float('1.2e-3') == ('', '1', '2', '-3') # some that will get thrown out on return: assert break_up_float('.') == ('', '', '', '') assert break_up_float('+') == ('+', '', '', '') assert break_up_float('-') == ('-', '', '', '') assert break_up_float('e1') == ('', '', '', '1') py.test.raises(ValueError, break_up_float, 'e')
def interp_string_to_float(space, s): """ Conversion of string to float. This version tries to only raise on invalid literals. Overflows should be converted to infinity whenever possible. Expects an unwrapped string and return an unwrapped float. """ s = strip_spaces(s) if not s: raise OperationError(space.w_ValueError, space.wrap( "empty string for float()")) # 1) parse the string into pieces. try: sign, before_point, after_point, exponent = break_up_float(s) except ValueError: raise ParseStringError("invalid literal for float()") digits = before_point + after_point if not digits: raise ParseStringError("invalid literal for float()") # 2) pre-calculate digit exponent dexp. dexp = len(before_point) # 3) truncate and adjust dexp. p = 0 plim = dexp + len(after_point) while p < plim and digits[p] == '0': p += 1 dexp -= 1 digits = digits[p : p + MANTISSA_DIGITS] p = len(digits) - 1 while p >= 0 and digits[p] == '0': p -= 1 dexp -= p + 1 p += 1 assert p >= 0 digits = digits[:p] if len(digits) == 0: digits = '0' # a few abbreviations from pypy.objspace.std import longobject mklong = longobject.W_LongObject.fromint d2long = longobject.W_LongObject.fromdecimalstr adlong = longobject.add__Long_Long longup = longobject.pow__Long_Long_None multip = longobject.mul__Long_Long divide = longobject.div__Long_Long lshift = longobject.lshift__Long_Long rshift = longobject.rshift__Long_Long # 4) compute the exponent and truncate to +-400 if not exponent: exponent = '0' w_le = d2long(exponent) w_le = adlong(space, w_le, mklong(space, dexp)) try: e = w_le.toint() except OverflowError: # XXX poking at internals e = w_le.num.sign * 400 if e >= 400: e = 400 elif e <= -400: e = -400 # 5) compute the value using long math and proper rounding. w_lr = d2long(digits) w_10 = mklong(space, 10) w_1 = mklong(space, 1) if e >= 0: bits = 0 w_pten = longup(space, w_10, mklong(space, e), space.w_None) w_m = multip(space, w_lr, w_pten) else: # compute a sufficiently large scale prec = MANTISSA_DIGITS * 2 + 22 # 128, maybe bits = - (int(math.ceil(-e / math.log10(2.0) - 1e-10)) + prec) w_scale = lshift(space, w_1, mklong(space, -bits)) w_pten = longup(space, w_10, mklong(space, -e), None) w_tmp = multip(space, w_lr, w_scale) w_m = divide(space, w_tmp, w_pten) # we now have a fairly large mantissa. # Shift it and round the last bit. # first estimate the bits and do a big shift mbits = w_m._count_bits() needed = MANTISSA_BITS if mbits > needed: if mbits > needed+1: shifted = mbits - (needed+1) w_m = rshift(space, w_m, mklong(space, shifted)) bits += shifted # do the rounding bits += 1 round = w_m.is_odd() w_m = rshift(space, w_m, w_1) w_m = adlong(space, w_m, mklong(space, round)) try: r = math.ldexp(w_m.tofloat(), bits) # XXX I guess we do not check for overflow in ldexp as we agreed to! if r == 2*r and r != 0.0: raise OverflowError except OverflowError: r = 1e200 * 1e200 # produce inf, hopefully if sign == '-': r = -r return r
def applevel_string_to_float(s): """ Conversion of string to float. This version tries to only raise on invalid literals. Overflows should be converted to infinity whenever possible. """ # this version was triggered by Python 2.4 which adds # a test that breaks on overflow. # XXX The test still breaks for a different reason: # float must implement rich comparisons, where comparison # between infinity and a too large long does not overflow! # The problem: # there can be extreme notations of floats which are not # infinity. # For instance, this works in CPython: # float('1' + '0'*1000 + 'e-1000') # should evaluate to 1.0. # note: float('1' + '0'*10000 + 'e-10000') # does not work in CPython, but PyPy can do it, now. # The idea: # in order to compensate between very long digit strings # and extreme exponent numbers, we try to avoid overflows # by adjusting the exponent by the number of mantissa # digits. For simplicity, all computations are done in # long math. # The plan: # 1) parse the string into pieces. # 2) pre-calculate digit exponent dexp. # 3) truncate and adjust dexp. # 4) compute the exponent and truncate to +-400. # 5) compute the value using long math and proper rounding. # Positive results: # The algorithm appears appears to produce correct round-trip # values for the perfect input of _float_formatting. # Note: # XXX: the builtin rounding of long->float does not work, correctly. # Ask Tim Peters for the reasons why no correct rounding is done. # XXX: limitations: # - It is possibly not too efficient. # - Really optimum results need a more sophisticated algorithm # like Bellerophon from William D. Clinger, cf. # http://citeseer.csail.mit.edu/clinger90how.html s = strip_spaces(s) if not s: raise ParseStringError("empty string for float()") # 1) parse the string into pieces. try: sign, before_point, after_point, exponent = break_up_float(s) except ValueError: raise ParseStringError("invalid literal for float()") digits = before_point + after_point if digits: raise ParseStringError("invalid literal for float()") # 2) pre-calculate digit exponent dexp. dexp = len(before_point) # 3) truncate and adjust dexp. p = 0 plim = dexp + len(after_point) while p < plim and digits[p] == '0': p += 1 dexp -= 1 digits = digits[p : p + MANTISSA_DIGITS] p = len(digits) - 1 while p >= 0 and digits[p] == '0': p -= 1 dexp -= p + 1 digits = digits[:p+1] if len(digits) == 0: digits = '0' # 4) compute the exponent and truncate to +-400 if not exponent: exponent = '0' e = long(exponent) + dexp if e >= 400: e = 400 elif e <= -400: e = -400 # 5) compute the value using long math and proper rounding. lr = long(digits) if e >= 0: bits = 0 m = lr * 10L ** e else: # compute a sufficiently large scale prec = MANTISSA_DIGITS * 2 + 22 # 128, maybe bits = - (int(math.ceil(-e / math.log10(2.0) - 1e-10)) + prec) scale = 2L ** -bits pten = 10L ** -e m = (lr * scale) // pten # we now have a fairly large mantissa. # Shift it and round the last bit. # first estimate the bits and do a big shift if m: mbits = int(math.ceil(math.log(m, 2) - 1e-10)) needed = MANTISSA_BITS if mbits > needed: if mbits > needed+1: shifted = mbits - (needed+1) m >>= shifted bits += shifted # do the rounding bits += 1 m = (m >> 1) + (m & 1) try: r = math.ldexp(m, bits) except OverflowError: r = 1e200 * 1e200 # produce inf, hopefully if sign == '-': r = -r return r
def load_float(loader): if readchr(loader) != TYPE_FLOAT: raise ValueError("expected a float") length = ord(readchr(loader)) s = readstr(loader, length) return parts_to_float(*break_up_float(s))
def interp_string_to_float(space, s): """ Conversion of string to float. This version tries to only raise on invalid literals. Overflows should be converted to infinity whenever possible. Expects an unwrapped string and return an unwrapped float. """ s = strip_spaces(s) if not s: raise OperationError(space.w_ValueError, space.wrap("empty string for float()")) # 1) parse the string into pieces. try: sign, before_point, after_point, exponent = break_up_float(s) except ValueError: raise ParseStringError("invalid literal for float()") digits = before_point + after_point if not digits: raise ParseStringError("invalid literal for float()") # 2) pre-calculate digit exponent dexp. dexp = len(before_point) # 3) truncate and adjust dexp. p = 0 plim = dexp + len(after_point) while p < plim and digits[p] == '0': p += 1 dexp -= 1 digits = digits[p:p + MANTISSA_DIGITS] p = len(digits) - 1 while p >= 0 and digits[p] == '0': p -= 1 dexp -= p + 1 p += 1 assert p >= 0 digits = digits[:p] if len(digits) == 0: digits = '0' # a few abbreviations from pypy.objspace.std import longobject mklong = longobject.W_LongObject.fromint d2long = longobject.W_LongObject.fromdecimalstr adlong = longobject.add__Long_Long longup = longobject.pow__Long_Long_None multip = longobject.mul__Long_Long divide = longobject.div__Long_Long lshift = longobject.lshift__Long_Long rshift = longobject.rshift__Long_Long # 4) compute the exponent and truncate to +-400 if not exponent: exponent = '0' w_le = d2long(exponent) w_le = adlong(space, w_le, mklong(space, dexp)) try: e = w_le.toint() except OverflowError: # XXX poking at internals e = w_le.num.sign * 400 if e >= 400: e = 400 elif e <= -400: e = -400 # 5) compute the value using long math and proper rounding. w_lr = d2long(digits) w_10 = mklong(space, 10) w_1 = mklong(space, 1) if e >= 0: bits = 0 w_pten = longup(space, w_10, mklong(space, e), space.w_None) w_m = multip(space, w_lr, w_pten) else: # compute a sufficiently large scale prec = MANTISSA_DIGITS * 2 + 22 # 128, maybe bits = -(int(math.ceil(-e / math.log10(2.0) - 1e-10)) + prec) w_scale = lshift(space, w_1, mklong(space, -bits)) w_pten = longup(space, w_10, mklong(space, -e), None) w_tmp = multip(space, w_lr, w_scale) w_m = divide(space, w_tmp, w_pten) # we now have a fairly large mantissa. # Shift it and round the last bit. # first estimate the bits and do a big shift mbits = w_m._count_bits() needed = MANTISSA_BITS if mbits > needed: if mbits > needed + 1: shifted = mbits - (needed + 1) w_m = rshift(space, w_m, mklong(space, shifted)) bits += shifted # do the rounding bits += 1 round = w_m.is_odd() w_m = rshift(space, w_m, w_1) w_m = adlong(space, w_m, mklong(space, round)) try: r = math.ldexp(w_m.tofloat(), bits) # XXX I guess we do not check for overflow in ldexp as we agreed to! if r == 2 * r and r != 0.0: raise OverflowError except OverflowError: r = 1e200 * 1e200 # produce inf, hopefully if sign == '-': r = -r return r
def applevel_string_to_float(s): """ Conversion of string to float. This version tries to only raise on invalid literals. Overflows should be converted to infinity whenever possible. """ # this version was triggered by Python 2.4 which adds # a test that breaks on overflow. # XXX The test still breaks for a different reason: # float must implement rich comparisons, where comparison # between infinity and a too large long does not overflow! # The problem: # there can be extreme notations of floats which are not # infinity. # For instance, this works in CPython: # float('1' + '0'*1000 + 'e-1000') # should evaluate to 1.0. # note: float('1' + '0'*10000 + 'e-10000') # does not work in CPython, but PyPy can do it, now. # The idea: # in order to compensate between very long digit strings # and extreme exponent numbers, we try to avoid overflows # by adjusting the exponent by the number of mantissa # digits. For simplicity, all computations are done in # long math. # The plan: # 1) parse the string into pieces. # 2) pre-calculate digit exponent dexp. # 3) truncate and adjust dexp. # 4) compute the exponent and truncate to +-400. # 5) compute the value using long math and proper rounding. # Positive results: # The algorithm appears appears to produce correct round-trip # values for the perfect input of _float_formatting. # Note: # XXX: the builtin rounding of long->float does not work, correctly. # Ask Tim Peters for the reasons why no correct rounding is done. # XXX: limitations: # - It is possibly not too efficient. # - Really optimum results need a more sophisticated algorithm # like Bellerophon from William D. Clinger, cf. # http://citeseer.csail.mit.edu/clinger90how.html s = strip_spaces(s) if not s: raise ParseStringError("empty string for float()") # 1) parse the string into pieces. try: sign, before_point, after_point, exponent = break_up_float(s) except ValueError: raise ParseStringError("invalid literal for float()") digits = before_point + after_point if digits: raise ParseStringError("invalid literal for float()") # 2) pre-calculate digit exponent dexp. dexp = len(before_point) # 3) truncate and adjust dexp. p = 0 plim = dexp + len(after_point) while p < plim and digits[p] == '0': p += 1 dexp -= 1 digits = digits[p:p + MANTISSA_DIGITS] p = len(digits) - 1 while p >= 0 and digits[p] == '0': p -= 1 dexp -= p + 1 digits = digits[:p + 1] if len(digits) == 0: digits = '0' # 4) compute the exponent and truncate to +-400 if not exponent: exponent = '0' e = long(exponent) + dexp if e >= 400: e = 400 elif e <= -400: e = -400 # 5) compute the value using long math and proper rounding. lr = long(digits) if e >= 0: bits = 0 m = lr * 10L**e else: # compute a sufficiently large scale prec = MANTISSA_DIGITS * 2 + 22 # 128, maybe bits = -(int(math.ceil(-e / math.log10(2.0) - 1e-10)) + prec) scale = 2L**-bits pten = 10L**-e m = (lr * scale) // pten # we now have a fairly large mantissa. # Shift it and round the last bit. # first estimate the bits and do a big shift if m: mbits = int(math.ceil(math.log(m, 2) - 1e-10)) needed = MANTISSA_BITS if mbits > needed: if mbits > needed + 1: shifted = mbits - (needed + 1) m >>= shifted bits += shifted # do the rounding bits += 1 m = (m >> 1) + (m & 1) try: r = math.ldexp(m, bits) except OverflowError: r = 1e200 * 1e200 # produce inf, hopefully if sign == '-': r = -r return r