Commit b9fc5d92 authored by Stefan Behnel's avatar Stefan Behnel

translate Python float calculations into C doubles

parent c7dbcf9a
...@@ -414,7 +414,7 @@ def init_builtins(): ...@@ -414,7 +414,7 @@ def init_builtins():
init_builtin_types() init_builtin_types()
init_builtin_structs() init_builtin_structs()
global list_type, tuple_type, dict_type, set_type, type_type global list_type, tuple_type, dict_type, set_type, type_type
global bytes_type, str_type, unicode_type global bytes_type, str_type, unicode_type, float_type
type_type = builtin_scope.lookup('type').type type_type = builtin_scope.lookup('type').type
list_type = builtin_scope.lookup('list').type list_type = builtin_scope.lookup('list').type
tuple_type = builtin_scope.lookup('tuple').type tuple_type = builtin_scope.lookup('tuple').type
...@@ -423,5 +423,6 @@ def init_builtins(): ...@@ -423,5 +423,6 @@ def init_builtins():
bytes_type = builtin_scope.lookup('bytes').type bytes_type = builtin_scope.lookup('bytes').type
str_type = builtin_scope.lookup('str').type str_type = builtin_scope.lookup('str').type
unicode_type = builtin_scope.lookup('unicode').type unicode_type = builtin_scope.lookup('unicode').type
float_type = builtin_scope.lookup('float').type
init_builtins() init_builtins()
...@@ -2412,7 +2412,9 @@ class SimpleCallNode(CallNode): ...@@ -2412,7 +2412,9 @@ class SimpleCallNode(CallNode):
if result_type.is_extension_type: if result_type.is_extension_type:
return result_type return result_type
elif result_type.is_builtin_type: elif result_type.is_builtin_type:
if function.entry.name in Builtin.types_that_construct_their_instance: if function.entry.name == 'float':
return PyrexTypes.c_double_type
elif function.entry.name in Builtin.types_that_construct_their_instance:
return result_type return result_type
return py_object_type return py_object_type
...@@ -2447,7 +2449,17 @@ class SimpleCallNode(CallNode): ...@@ -2447,7 +2449,17 @@ class SimpleCallNode(CallNode):
self.arg_tuple = TupleNode(self.pos, args = self.args) self.arg_tuple = TupleNode(self.pos, args = self.args)
self.arg_tuple.analyse_types(env) self.arg_tuple.analyse_types(env)
self.args = None self.args = None
if function.is_name and function.type_entry: if func_type is Builtin.type_type and function.entry.is_builtin and \
function.entry.name in Builtin.types_that_construct_their_instance:
# calling a builtin type that returns a specific object type
if function.entry.name == 'float':
# the following will come true later on in a transform
self.type = PyrexTypes.c_double_type
self.result_ctype = PyrexTypes.c_double_type
else:
self.type = Builtin.builtin_types[function.entry.name]
self.result_ctype = py_object_type
elif function.is_name and function.type_entry:
# We are calling an extension type constructor. As # We are calling an extension type constructor. As
# long as we do not support __new__(), the result type # long as we do not support __new__(), the result type
# is clear # is clear
......
...@@ -2031,6 +2031,10 @@ def spanning_type(type1, type2): ...@@ -2031,6 +2031,10 @@ def spanning_type(type1, type2):
return type1 return type1
elif type1.is_numeric and type2.is_numeric: elif type1.is_numeric and type2.is_numeric:
return widest_numeric_type(type1, type2) return widest_numeric_type(type1, type2)
elif type1.is_builtin_type and type1.name == 'float' and type2.is_numeric:
return widest_numeric_type(c_double_type, type2)
elif type2.is_builtin_type and type2.name == 'float' and type1.is_numeric:
return widest_numeric_type(type1, c_double_type)
elif type1.is_pyobject ^ type2.is_pyobject: elif type1.is_pyobject ^ type2.is_pyobject:
return py_object_type return py_object_type
elif type1.assignable_from(type2): elif type1.assignable_from(type2):
......
...@@ -191,16 +191,20 @@ class SimpleAssignmentTypeInferer: ...@@ -191,16 +191,20 @@ class SimpleAssignmentTypeInferer:
entry.type = py_object_type entry.type = py_object_type
def find_safe_type(result_type, which_types_to_infer): def find_safe_type(result_type, which_types_to_infer):
if which_types_to_infer == 'none':
return py_object_type
if result_type in (PyrexTypes.c_double_type, PyrexTypes.c_float_type, Builtin.float_type):
# Python's float type is just a C double, so it's safe to
# use the C type instead
return PyrexTypes.c_double_type
if which_types_to_infer == 'all': if which_types_to_infer == 'all':
return result_type return result_type
elif which_types_to_infer == 'safe': elif which_types_to_infer == 'safe':
if result_type.is_pyobject: if result_type.is_pyobject:
# any specific Python type is always safe to infer # any specific Python type is always safe to infer
return result_type return result_type
elif result_type in (PyrexTypes.c_double_type, PyrexTypes.c_float_type):
# Python's float type is just a C double, so it's safe to
# use the C type instead
return PyrexTypes.c_double_type
elif result_type is PyrexTypes.c_bint_type: elif result_type is PyrexTypes.c_bint_type:
# 'bint' should behave exactly like Python's bool type ... # 'bint' should behave exactly like Python's bool type ...
return PyrexTypes.c_bint_type return PyrexTypes.c_bint_type
......
...@@ -37,17 +37,17 @@ def int_to_pyssizet_int(int x): ...@@ -37,17 +37,17 @@ def int_to_pyssizet_int(int x):
cdef Py_ssize_t r = int(x) cdef Py_ssize_t r = int(x)
return r return r
@cython.test_assert_path_exists("//SingleAssignmentNode/CastNode") ## @cython.test_assert_path_exists("//SingleAssignmentNode/CastNode")
@cython.test_fail_if_path_exists("//SimpleCallNode") ## @cython.test_fail_if_path_exists("//SimpleCallNode")
def double_to_pyssizet_float(double x): ## def double_to_pyssizet_float(double x):
""" ## """
>>> double_to_pyssizet_float(4.1) ## >>> double_to_pyssizet_float(4.1)
4 ## 4
>>> double_to_pyssizet_float(4) ## >>> double_to_pyssizet_float(4)
4 ## 4
""" ## """
cdef Py_ssize_t r = float(x) ## cdef Py_ssize_t r = float(x)
return r ## return r
@cython.test_assert_path_exists("//SingleAssignmentNode/CastNode") @cython.test_assert_path_exists("//SingleAssignmentNode/CastNode")
@cython.test_fail_if_path_exists("//SimpleCallNode") @cython.test_fail_if_path_exists("//SimpleCallNode")
...@@ -89,8 +89,7 @@ def short_to_double_int(short x): ...@@ -89,8 +89,7 @@ def short_to_double_int(short x):
cdef double r = int(x) cdef double r = int(x)
return r return r
@cython.test_fail_if_path_exists("//SimpleCallNode", @cython.test_fail_if_path_exists("//SimpleCallNode")
"//SingleAssignmentNode/CastNode")
def float_to_float_float(float x): def float_to_float_float(float x):
""" """
>>> 4.05 < float_to_float_float(4.1) < 4.15 >>> 4.05 < float_to_float_float(4.1) < 4.15
......
...@@ -149,6 +149,25 @@ def loop(): ...@@ -149,6 +149,25 @@ def loop():
assert typeof(a) == "long" assert typeof(a) == "long"
@infer_types('safe')
def double_inference():
"""
>>> values, types = double_inference()
>>> values == (1.0, 1.0*2, 1.0*2.0+2.0*2.0, 1.0*2.0)
True
>>> types
('double', 'double', 'double', 'Python object')
"""
d_a = 1.0
d_b = d_a * float(2)
d_c = d_a * float(some_float_value()) + d_b * float(some_float_value())
o_d = d_a * some_float_value()
return (d_a,d_b,d_c,o_d), (typeof(d_a), typeof(d_b), typeof(d_c), typeof(o_d))
cdef object some_float_value():
return 2.0
@cython.test_fail_if_path_exists('//NameNode[@type.is_pyobject = True]') @cython.test_fail_if_path_exists('//NameNode[@type.is_pyobject = True]')
@cython.test_assert_path_exists('//InPlaceAssignmentNode/NameNode', @cython.test_assert_path_exists('//InPlaceAssignmentNode/NameNode',
'//NameNode[@type.is_pyobject]', '//NameNode[@type.is_pyobject]',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment