def test_string_to_float_nan(): nan = float('nan') pinf = float('inf') for s in ['nan', '+nan', '-nan', 'NAN', '+nAn']: assert math.isnan(string_to_float(s)) for s in ['inf', '+inf', '-inf', '-infinity', ' -infiNITy ']: assert math.isinf(string_to_float(s))
def descr__new__(space, w_complextype, w_real, w_imag=None): # if w_real is already a complex number and there is no second # argument, return it. Note that we cannot return w_real if # it is an instance of a *subclass* of complex, or if w_complextype # is itself a subclass of complex. noarg2 = w_imag is None if (noarg2 and space.is_w(w_complextype, space.w_complex) and space.is_w(space.type(w_real), space.w_complex)): return w_real if space.isinstance_w(w_real, space.w_text): # a string argument if not noarg2: raise oefmt( space.w_TypeError, "complex() can't take second" " arg if first is a string") unistr = unicode_to_decimal_w(space, w_real) try: unistr = _remove_underscores(unistr) except ValueError: raise oefmt(space.w_ValueError, "complex() arg is a malformed string") try: realstr, imagstr = _split_complex(unistr) except ValueError: raise oefmt(space.w_ValueError, "complex() arg is a malformed string") try: realval = string_to_float(realstr) imagval = string_to_float(imagstr) except ParseStringError: raise oefmt(space.w_ValueError, "complex() arg is a malformed string") else: # non-string arguments realval, imagval = unpackcomplex(space, w_real) # now take w_imag into account if not noarg2: # complex(x, y) == x+y*j, even if 'y' is already a complex. realval2, imagval2 = unpackcomplex(space, w_imag, firstarg=False) # try to preserve the signs of zeroes of realval and realval2 if imagval2 != 0.0: realval -= imagval2 if imagval != 0.0: imagval += realval2 else: imagval = realval2 # done w_obj = space.allocate_instance(W_ComplexObject, w_complextype) W_ComplexObject.__init__(w_obj, realval, imagval) return w_obj
def descr__new__(space, w_complextype, w_real, w_imag=None): from pypy.objspace.std.complexobject import W_ComplexObject # if w_real is already a complex number and there is no second # argument, return it. Note that we cannot return w_real if # it is an instance of a *subclass* of complex, or if w_complextype # is itself a subclass of complex. noarg2 = w_imag is None if (noarg2 and space.is_w(w_complextype, space.w_complex) and space.is_w(space.type(w_real), space.w_complex)): return w_real if space.isinstance_w(w_real, space.w_str) or \ space.isinstance_w(w_real, space.w_unicode): # a string argument if not noarg2: raise OperationError( space.w_TypeError, space.wrap("complex() can't take second arg" " if first is a string")) try: realstr, imagstr = _split_complex(space.str_w(w_real)) except ValueError: raise OperationError(space.w_ValueError, space.wrap(ERR_MALFORMED)) try: realval = string_to_float(realstr) imagval = string_to_float(imagstr) except ParseStringError: raise OperationError(space.w_ValueError, space.wrap(ERR_MALFORMED)) else: # non-string arguments realval, imagval = unpackcomplex(space, w_real, strict_typing=False) # now take w_imag into account if not noarg2: # complex(x, y) == x+y*j, even if 'y' is already a complex. realval2, imagval2 = unpackcomplex(space, w_imag, strict_typing=False) # try to preserve the signs of zeroes of realval and realval2 if imagval2 != 0.0: realval -= imagval2 if imagval != 0.0: imagval += realval2 else: imagval = realval2 # done w_obj = space.allocate_instance(W_ComplexObject, w_complextype) W_ComplexObject.__init__(w_obj, realval, imagval) return w_obj
def descr__new__(space, w_complextype, w_real, w_imag=None): # if w_real is already a complex number and there is no second # argument, return it. Note that we cannot return w_real if # it is an instance of a *subclass* of complex, or if w_complextype # is itself a subclass of complex. noarg2 = w_imag is None if (noarg2 and space.is_w(w_complextype, space.w_complex) and space.is_w(space.type(w_real), space.w_complex)): return w_real if space.isinstance_w(w_real, space.w_str) or \ space.isinstance_w(w_real, space.w_unicode): # a string argument if not noarg2: raise oefmt(space.w_TypeError, "complex() can't take second" " arg if first is a string") try: realstr, imagstr = _split_complex(space.str_w(w_real)) except ValueError: raise oefmt(space.w_ValueError, "complex() arg is a malformed string") try: realval = string_to_float(realstr) imagval = string_to_float(imagstr) except ParseStringError: raise oefmt(space.w_ValueError, "complex() arg is a malformed string") else: # non-string arguments realval, imagval = unpackcomplex(space, w_real, strict_typing=False) # now take w_imag into account if not noarg2: # complex(x, y) == x+y*j, even if 'y' is already a complex. realval2, imagval2 = unpackcomplex(space, w_imag, strict_typing=False) # try to preserve the signs of zeroes of realval and realval2 if imagval2 != 0.0: realval -= imagval2 if imagval != 0.0: imagval += realval2 else: imagval = realval2 # done w_obj = space.allocate_instance(W_ComplexObject, w_complextype) W_ComplexObject.__init__(w_obj, realval, imagval) return w_obj
def _string_to_float(space, w_source, string): try: string = _remove_underscores(string) except ValueError: pass else: try: return rfloat.string_to_float(string) except ParseStringError as e: pass raise oefmt(space.w_ValueError, "could not convert string to float: %R", w_source)
def save_field(self, field_builder): field = field_builder.build() if self.numeric_field: from rpython.rlib.rstring import ParseStringError from rpython.rlib.rfloat import string_to_float self.numeric_field = False try: ff = string_to_float(field) except ParseStringError, e: raise OperationError(self.space.w_ValueError, self.space.wrap(e.msg)) w_obj = self.space.wrap(ff)
def str2num(w_s): from rpython.rlib import rarithmetic, rfloat, rbigint from rpython.rlib.rstring import ParseStringError, ParseStringOverflowError s = w_s.as_str_utf8() try: if "." in s: return values.W_Flonum(rfloat.string_to_float(s)) else: try: return values.W_Fixnum(rarithmetic.string_to_int(s, base=10)) except ParseStringOverflowError: return values.W_Bignum(rbigint.rbigint.fromstr(s)) except ParseStringError as e: return values.w_false
def str2num(w_s): from rpython.rlib import rarithmetic, rfloat, rbigint from rpython.rlib.rstring import ParseStringError, ParseStringOverflowError try: s = w_s.as_str_utf8() if "." in s: return values.W_Flonum(rfloat.string_to_float(s)) else: try: return values.W_Fixnum(rarithmetic.string_to_int(s, base=0)) except ParseStringOverflowError: return values.W_Bignum(rbigint.rbigint.fromstr(s)) except ParseStringError as e: return values.w_false
def save_field(self, field_builder): space = self.space field = field_builder.build() if self.numeric_field: from rpython.rlib.rstring import ParseStringError from rpython.rlib.rfloat import string_to_float self.numeric_field = False try: ff = string_to_float(field) except ParseStringError as e: raise wrap_parsestringerror(space, e, space.wrap(field)) w_obj = space.wrap(ff) else: w_obj = space.wrap(field) self.fields_w.append(w_obj)
def descr__new__(space, w_floattype, w_x): from pypy.objspace.std.floatobject import W_FloatObject w_value = w_x # 'x' is the keyword argument name in CPython w_special = space.lookup(w_value, "__float__") if w_special is not None: w_obj = space.get_and_call_function(w_special, w_value) if not space.isinstance_w(w_obj, space.w_float): raise OperationError(space.w_TypeError, space.wrap("__float__ returned non-float")) if space.is_w(w_floattype, space.w_float): return w_obj value = space.float_w(w_obj) elif (space.isinstance_w(w_value, space.w_str) or space.isinstance_w(w_value, space.w_bytearray)): strvalue = space.bufferstr_w(w_value) try: value = rfloat.string_to_float(strvalue) except ParseStringError, e: raise OperationError(space.w_ValueError, space.wrap(e.msg))
def load_object(fp): fp.next_reference_obj -= 1 needs_ref = (fp.next_reference_obj == 0) # fp.error_pos = fp.pos try: i = fp.consume(2) except SerializerError: i = fp.consume(1) if fp.s[i] == '}': fp.space.ec.notice("unserialize(): " "Unexpected end of serialized data") raise s = fp.s tp = s[i] check_nonneg(i) check_nonneg(fp.pos) # if tp == 'i': if s[i + 1] != ':': raise SerializerError("':' expected") i = fp.read_int_until(';') w_result = fp.space.wrap(i) # elif tp == 's': if s[i + 1] != ':': raise SerializerError("':' expected") w_result = fp.space.newstr(load_str(fp, ';')) # elif tp == 'd': if s[i + 1] != ':': raise SerializerError("':' expected") data = fp.read_substring_until(';') try: result = string_to_float(data) except ParseStringError: raise SerializerError('bad double') w_result = fp.space.newfloat(result) # elif tp == 'b': if s[i + 1] != ':': raise SerializerError("':' expected") i = fp.consume(2) digit = s[i] if digit == '0': w_result = fp.space.w_False elif digit == '1': w_result = fp.space.w_True else: raise SerializerError('bad bool') if s[i + 1] != ';': raise SerializerError("';' expected") # elif tp == 'N': if s[i + 1] != ';': raise SerializerError("';' expected") w_result = fp.space.w_Null # elif tp == 'a': if s[i + 1] != ':': raise SerializerError("':' expected") length = fp.read_int_until(':', can_be_negative=False) if length < 0: raise SerializerError("integer overflow") i = fp.consume(1) if s[i] != '{': raise SerializerError("'{' expected") w_result = None if needs_ref: w_result = fp.space.empty_ref() fp.save_reference(w_result) # first try to load the array as a direct list lst_w = [] expected = ['i', ':', '0', ';'] for n in range(length): i = fp.pos if i + len(expected) >= len(s): break for j in range(len(expected)): if s[i] != expected[j]: break i += 1 else: # ok, we got exactly 'i:N;' where N is the expected index fp.pos = i lst_w.append(load_object(fp)) # increment the expected counter j = len(expected) - 2 while j >= 2: if expected[j] != '9': expected[j] = chr(ord(expected[j]) + 1) break expected[j] = '0' j -= 1 else: expected = ['i', ':', '1'] + expected[2:] continue break else: # we succeeded in loading the complete array as a list n = length _succeeded_as_a_list() # for tests # fill in the remaining entries, if any, the slow way w_array = fp.space.new_array_from_list(lst_w) for n in range(n, length): w_key = load_array_key(fp) w_value = load_object(fp) w_array = fp.space.setitem_maybe_inplace(w_array, w_key, w_value) fp.expect_closing_brace() if w_result is not None: # needs_ref w_result.store(w_array, unique=True) return w_result else: return w_array # elif tp == 'R': if s[i + 1] != ':': raise SerializerError("':' expected") return load_reference(fp) # elif tp == 'r': if s[i + 1] != ':': raise SerializerError("':' expected") return load_reference(fp).deref() # elif tp == 'O': if s[i + 1] != ':': raise SerializerError("':' expected") klass_name = load_str(fp, ':') space = fp.space interp = space.ec.interpreter klass = interp.lookup_class_or_intf(klass_name) if klass is None: klass = k_incomplete w_instance = klass.get_empty_instance(space) w_instance.setattr(interp, '__PHP_Incomplete_Class_Name', space.wrap(klass_name), None) else: w_instance = klass.get_empty_instance(space) w_result = w_instance if needs_ref: w_result = W_Reference(w_instance) fp.save_reference(w_result) count_attrs = fp.read_int_until(':') # negative value accepted :-( i = fp.consume(1) if s[i] != '{': raise SerializerError("'{' expected") attrs = {} for i in xrange(count_attrs): w_attr = load_array_key(fp) w_value = load_object(fp) attr_name = space.str_w(w_attr) attrs[attr_name] = w_value w_instance.setattr(interp, attr_name, w_value, None) fp.expect_closing_brace() w_instance.unserialize(space, attrs) if '__wakeup' in klass.methods: klass.methods['__wakeup'].method_func.call_args( space.ec.interpreter, [], w_this=w_instance, thisclass=klass) return w_result # else: if tp == '}': fp.space.ec.notice("unserialize(): " "Unexpected end of serialized data") raise SerializerError('malformed input') # this is for primitive types only; complex types 'return' above if needs_ref: w_result = W_Reference(w_result) fp.save_reference(w_result) return w_result
def _string_to_float(space, w_source, string): try: return rfloat.string_to_float(string) except ParseStringError as e: raise oefmt(space.w_ValueError, "could not convert string to float: %R", w_source)
if len(e_parts) > 2: raise ParseStringError("invalid floating point number : %s" % s) try: num = float(e_parts[0]) exp = int(e_parts[1]) p = math.pow(10, exp) except ValueError, e: return values.w_false return values.W_Flonum(num*p) if "." in s or re.match("[+-]?([\d]+)(\.[\d]+)?e[+-][\d]+$", s): if not radix == 10: # FIXME raise SchemeException("string->number : floats with base different than 10 are not supported yet : given number : %s - radix : %s" % (s, str(radix))) return values.W_Flonum(rfloat.string_to_float(s)) else: try: return values.W_Fixnum(rarithmetic.string_to_int(s, base=radix)) except ParseStringOverflowError: return values.W_Bignum(rbigint.rbigint.fromstr(s, base=radix)) except ParseStringError as e: return values.w_false @expose("number->string", [values.W_Number, default(values.W_Fixnum, values.W_Fixnum.make(10))]) def num2str(a, radix): from rpython.rlib.rbigint import BASE8, BASE16 if radix.value == 10: return W_String.fromascii(a.tostring()) else:
def test_string_to_float(): from rpython.rlib.rstring import ParseStringError import random assert string_to_float('0') == 0.0 assert string_to_float('1') == 1.0 assert string_to_float('-1.5') == -1.5 assert string_to_float('1.5E2') == 150.0 assert string_to_float('2.5E-1') == 0.25 assert string_to_float('1e1111111111111') == float('1e1111111111111') assert string_to_float('1e-1111111111111') == float('1e-1111111111111') assert string_to_float('-1e1111111111111') == float('-1e1111111111111') assert string_to_float('-1e-1111111111111') == float('-1e-1111111111111') assert string_to_float('1e111111111111111111111') == float('1e111111111111111111111') assert string_to_float('1e-111111111111111111111') == float('1e-111111111111111111111') assert string_to_float('-1e111111111111111111111') == float('-1e111111111111111111111') assert string_to_float('-1e-111111111111111111111') == float('-1e-111111111111111111111') valid_parts = [['', ' ', ' \f\n\r\t\v'], ['', '+', '-'], ['00', '90', '.5', '2.4', '3.', '0.07', '12.3489749871982471987198371293717398256187563298638726' '2187362820947193247129871083561249818451804287437824015' '013816418758104762348932657836583048761487632840726386'], ['', 'e0', 'E+1', 'E-01', 'E42'], ['', ' ', ' \f\n\r\t\v'], ] invalid_parts = [['#'], ['++', '+-', '-+', '--'], ['', '1.2.3', '.', '5..6'], ['E+', 'E-', 'e', 'e++', 'E++2'], ['#'], ] for part0 in valid_parts[0]: for part1 in valid_parts[1]: for part2 in valid_parts[2]: for part3 in valid_parts[3]: for part4 in valid_parts[4]: s = part0+part1+part2+part3+part4 assert (abs(string_to_float(s) - float(s)) <= 1E-13 * abs(float(s))) for j in range(len(invalid_parts)): for invalid in invalid_parts[j]: for i in range(20): parts = [random.choice(lst) for lst in valid_parts] parts[j] = invalid s = ''.join(parts) print repr(s) if s.strip(): # empty s raises OperationError directly py.test.raises(ParseStringError, string_to_float, s) py.test.raises(ParseStringError, string_to_float, "")
if len(e_parts) > 2: raise ParseStringError("invalid floating point number : %s" % s) try: num = float(e_parts[0]) exp = int(e_parts[1]) p = math.pow(10, exp) except ValueError, e: return values.w_false return values.W_Flonum(num*p) if "." in s or re.match("[+-]?([\d]+)(\.[\d]+)?e[+-][\d]+$", s): if not radix == 10: # FIXME raise SchemeException("string->number : floats with base different than 10 are not supported yet : given number : %s - radix : %s" % (w_s.tostring(), str(radix))) return values.W_Flonum(rfloat.string_to_float(s)) else: try: return values.W_Fixnum(rarithmetic.string_to_int(s, base=radix)) except ParseStringOverflowError: return values.W_Bignum(rbigint.rbigint.fromstr(s, base=radix)) except ParseStringError as e: return values.w_false @expose("number->string", [values.W_Number, default(values.W_Fixnum, values.W_Fixnum.make(10))]) def num2str(a, radix): from rpython.rlib.rbigint import BASE8, BASE16 if radix.value == 10: return W_String.fromascii(a.tostring()) else:
def _string_to_float(space, w_source, string): try: return rfloat.string_to_float(string) except ParseStringError as e: from pypy.objspace.std.intobject import wrap_parsestringerror raise wrap_parsestringerror(space, e, w_source)
def string_to_float(s): return model.w_float(rfloat.string_to_float(s))
def load_object(fp): fp.next_reference_obj -= 1 needs_ref = (fp.next_reference_obj == 0) # fp.error_pos = fp.pos try: i = fp.consume(2) except SerializerError: i = fp.consume(1) if fp.s[i] == '}': fp.space.ec.notice("unserialize(): " "Unexpected end of serialized data") raise s = fp.s tp = s[i] check_nonneg(i) check_nonneg(fp.pos) # if tp == 'i': if s[i + 1] != ':': raise SerializerError("':' expected") i = fp.read_int_until(';') w_result = fp.space.wrap(i) # elif tp == 's': if s[i + 1] != ':': raise SerializerError("':' expected") w_result = fp.space.newstr(load_str(fp, ';')) # elif tp == 'd': if s[i + 1] != ':': raise SerializerError("':' expected") data = fp.read_substring_until(';') try: result = string_to_float(data) except ParseStringError: raise SerializerError('bad double') w_result = fp.space.newfloat(result) # elif tp == 'b': if s[i + 1] != ':': raise SerializerError("':' expected") i = fp.consume(2) digit = s[i] if digit == '0': w_result = fp.space.w_False elif digit == '1': w_result = fp.space.w_True else: raise SerializerError('bad bool') if s[i + 1] != ';': raise SerializerError("';' expected") # elif tp == 'N': if s[i + 1] != ';': raise SerializerError("';' expected") w_result = fp.space.w_Null # elif tp == 'a': if s[i + 1] != ':': raise SerializerError("':' expected") length = fp.read_int_until(':', can_be_negative=False) if length < 0: raise SerializerError("integer overflow") i = fp.consume(1) if s[i] != '{': raise SerializerError("'{' expected") w_result = None if needs_ref: w_result = fp.space.empty_ref() fp.save_reference(w_result) # first try to load the array as a direct list lst_w = [] expected = ['i', ':', '0', ';'] for n in range(length): i = fp.pos if i + len(expected) >= len(s): break for j in range(len(expected)): if s[i] != expected[j]: break i += 1 else: # ok, we got exactly 'i:N;' where N is the expected index fp.pos = i lst_w.append(load_object(fp)) # increment the expected counter j = len(expected) - 2 while j >= 2: if expected[j] != '9': expected[j] = chr(ord(expected[j]) + 1) break expected[j] = '0' j -= 1 else: expected = ['i', ':', '1'] + expected[2:] continue break else: # we succeeded in loading the complete array as a list n = length _succeeded_as_a_list() # for tests # fill in the remaining entries, if any, the slow way w_array = fp.space.new_array_from_list(lst_w) for n in range(n, length): w_key = load_array_key(fp) w_value = load_object(fp) w_array = fp.space.setitem_maybe_inplace(w_array, w_key, w_value) fp.expect_closing_brace() if w_result is not None: # needs_ref w_result.store(w_array, unique=True) return w_result else: return w_array # elif tp == 'R': if s[i + 1] != ':': raise SerializerError("':' expected") return load_reference(fp) # elif tp == 'r': if s[i + 1] != ':': raise SerializerError("':' expected") return load_reference(fp).deref() # elif tp == 'O': if s[i + 1] != ':': raise SerializerError("':' expected") klass_name = load_str(fp, ':') space = fp.space interp = space.ec.interpreter klass = interp.lookup_class_or_intf(klass_name) if klass is None: klass = k_incomplete w_instance = klass.get_empty_instance(space) w_instance.setattr(interp, '__PHP_Incomplete_Class_Name', space.wrap(klass_name), None) else: w_instance = klass.get_empty_instance(space) w_result = w_instance if needs_ref: w_result = W_Reference(w_instance) fp.save_reference(w_result) count_attrs = fp.read_int_until(':') # negative value accepted :-( i = fp.consume(1) if s[i] != '{': raise SerializerError("'{' expected") attrs = {} for i in xrange(count_attrs): w_attr = load_array_key(fp) w_value = load_object(fp) attr_name = space.str_w(w_attr) attrs[attr_name] = w_value w_instance.setattr(interp, attr_name, w_value, None) fp.expect_closing_brace() w_instance.unserialize(space, attrs) if '__wakeup' in klass.methods: klass.methods['__wakeup'].method_func.call_args(space.ec.interpreter, [], w_this=w_instance, thisclass=klass) return w_result # else: if tp == '}': fp.space.ec.notice("unserialize(): " "Unexpected end of serialized data") raise SerializerError('malformed input') # this is for primitive types only; complex types 'return' above if needs_ref: w_result = W_Reference(w_result) fp.save_reference(w_result) return w_result
if space.is_w(w_floattype, space.w_float): return w_obj value = space.float_w(w_obj) elif (space.isinstance_w(w_value, space.w_str) or space.isinstance_w(w_value, space.w_bytearray)): strvalue = space.bufferstr_w(w_value) try: value = rfloat.string_to_float(strvalue) except ParseStringError, e: raise OperationError(space.w_ValueError, space.wrap(e.msg)) elif space.isinstance_w(w_value, space.w_unicode): from unicodeobject import unicode_to_decimal_w strvalue = unicode_to_decimal_w(space, w_value) try: value = rfloat.string_to_float(strvalue) except ParseStringError, e: raise OperationError(space.w_ValueError, space.wrap(e.msg)) else: value = space.float_w(w_x) w_obj = space.allocate_instance(W_FloatObject, w_floattype) W_FloatObject.__init__(w_obj, value) return w_obj def detect_floatformat(): from rpython.rtyper.lltypesystem import rffi, lltype buf = lltype.malloc(rffi.CCHARP.TO, 8, flavor='raw') rffi.cast(rffi.DOUBLEP, buf)[0] = 9006104071832581.0 packed = rffi.charpsize2str(buf, 8)
def _string_to_float(space, w_source, string): try: return rfloat.string_to_float(string) except ParseStringError as e: raise wrap_parsestringerror(space, e, w_source)
def str2num(w_s, radix, convert_mode, decimal_mode): from rpython.rlib import rarithmetic, rfloat, rbigint from rpython.rlib.rstring import ParseStringError, ParseStringOverflowError from rpython.rlib.rsre import rsre_re as re import math s = w_s.as_str_utf8() try: if re.match("[+-]?([\d]+)?.?\d+[tT]\d", s): # it's an extflonum return values.W_ExtFlonum(s) if re.match("[+-]?([\d]+)?.?\d+[sf]\d", s): if "f" in s: f_parts = s.split("f") elif "s" in s: f_parts = s.split("s") else: raise ParseStringError("invalid floating point number : %s" % s) if len(f_parts) > 2: raise ParseStringError("invalid floating point number : %s" % s) try: numb = float(f_parts[0]) prec = int(f_parts[1]) p = math.pow(10, prec) except ValueError: return values.w_false return values.W_Flonum.make(numb * p, True) if re.match("[+-]?([\d]+)?.?\d+e\d", s): e_parts = s.split("e") if len(e_parts) > 2: raise ParseStringError("invalid floating point number : %s" % s) try: num = float(e_parts[0]) exp = int(e_parts[1]) p = math.pow(10, exp) except ValueError: return values.w_false return values.W_Flonum(num * p) if "." in s or re.match("[+-]?([\d]+)(\.[\d]+)?e[+-][\d]+$", s): if not radix.equal(values.W_Fixnum(10)): # FIXME raise SchemeException( "string->number : floats with base different than 10 are not supported yet : given number : %s - radix : %s" % (w_s.tostring(), radix.tostring())) return values.W_Flonum(rfloat.string_to_float(s)) else: try: return values.W_Fixnum( rarithmetic.string_to_int(s, base=radix.toint())) except ParseStringOverflowError: return values.W_Bignum(rbigint.rbigint.fromstr(s)) except ParseStringError as e: return values.w_false
def test_string_to_float(): from rpython.rlib.rstring import ParseStringError import random assert string_to_float('0') == 0.0 assert string_to_float('1') == 1.0 assert string_to_float('-1.5') == -1.5 assert string_to_float('1.5E2') == 150.0 assert string_to_float('2.5E-1') == 0.25 assert string_to_float('1e1111111111111') == float('1e1111111111111') assert string_to_float('1e-1111111111111') == float('1e-1111111111111') assert string_to_float('-1e1111111111111') == float('-1e1111111111111') assert string_to_float('-1e-1111111111111') == float('-1e-1111111111111') assert string_to_float('1e111111111111111111111') == float( '1e111111111111111111111') assert string_to_float('1e-111111111111111111111') == float( '1e-111111111111111111111') assert string_to_float('-1e111111111111111111111') == float( '-1e111111111111111111111') assert string_to_float('-1e-111111111111111111111') == float( '-1e-111111111111111111111') valid_parts = [ ['', ' ', ' \f\n\r\t\v'], ['', '+', '-'], [ '00', '90', '.5', '2.4', '3.', '0.07', '12.3489749871982471987198371293717398256187563298638726' '2187362820947193247129871083561249818451804287437824015' '013816418758104762348932657836583048761487632840726386' ], ['', 'e0', 'E+1', 'E-01', 'E42'], ['', ' ', ' \f\n\r\t\v'], ] invalid_parts = [ ['#'], ['++', '+-', '-+', '--'], ['', '1.2.3', '.', '5..6'], ['E+', 'E-', 'e', 'e++', 'E++2'], ['#'], ] for part0 in valid_parts[0]: for part1 in valid_parts[1]: for part2 in valid_parts[2]: for part3 in valid_parts[3]: for part4 in valid_parts[4]: s = part0 + part1 + part2 + part3 + part4 assert (abs(string_to_float(s) - float(s)) <= 1E-13 * abs(float(s))) for j in range(len(invalid_parts)): for invalid in invalid_parts[j]: for i in range(20): parts = [random.choice(lst) for lst in valid_parts] parts[j] = invalid s = ''.join(parts) print repr(s) if s.strip(): # empty s raises OperationError directly py.test.raises(ParseStringError, string_to_float, s) py.test.raises(ParseStringError, string_to_float, "")