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():
init_builtin_types()
init_builtin_structs()
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
list_type = builtin_scope.lookup('list').type
tuple_type = builtin_scope.lookup('tuple').type
......@@ -423,5 +423,6 @@ def init_builtins():
bytes_type = builtin_scope.lookup('bytes').type
str_type = builtin_scope.lookup('str').type
unicode_type = builtin_scope.lookup('unicode').type
float_type = builtin_scope.lookup('float').type
init_builtins()
......@@ -2412,7 +2412,9 @@ class SimpleCallNode(CallNode):
if result_type.is_extension_type:
return result_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 py_object_type
......@@ -2447,7 +2449,17 @@ class SimpleCallNode(CallNode):
self.arg_tuple = TupleNode(self.pos, args = self.args)
self.arg_tuple.analyse_types(env)
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
# long as we do not support __new__(), the result type
# is clear
......
......@@ -2031,6 +2031,10 @@ def spanning_type(type1, type2):
return type1
elif type1.is_numeric and type2.is_numeric:
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:
return py_object_type
elif type1.assignable_from(type2):
......
......@@ -191,16 +191,20 @@ class SimpleAssignmentTypeInferer:
entry.type = py_object_type
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':
return result_type
elif which_types_to_infer == 'safe':
if result_type.is_pyobject:
# any specific Python type is always safe to infer
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:
# 'bint' should behave exactly like Python's bool type ...
return PyrexTypes.c_bint_type
......
......@@ -37,17 +37,17 @@ def int_to_pyssizet_int(int x):
cdef Py_ssize_t r = int(x)
return r
@cython.test_assert_path_exists("//SingleAssignmentNode/CastNode")
@cython.test_fail_if_path_exists("//SimpleCallNode")
def double_to_pyssizet_float(double x):
"""
>>> double_to_pyssizet_float(4.1)
4
>>> double_to_pyssizet_float(4)
4
"""
cdef Py_ssize_t r = float(x)
return r
## @cython.test_assert_path_exists("//SingleAssignmentNode/CastNode")
## @cython.test_fail_if_path_exists("//SimpleCallNode")
## def double_to_pyssizet_float(double x):
## """
## >>> double_to_pyssizet_float(4.1)
## 4
## >>> double_to_pyssizet_float(4)
## 4
## """
## cdef Py_ssize_t r = float(x)
## return r
@cython.test_assert_path_exists("//SingleAssignmentNode/CastNode")
@cython.test_fail_if_path_exists("//SimpleCallNode")
......@@ -89,8 +89,7 @@ def short_to_double_int(short x):
cdef double r = int(x)
return r
@cython.test_fail_if_path_exists("//SimpleCallNode",
"//SingleAssignmentNode/CastNode")
@cython.test_fail_if_path_exists("//SimpleCallNode")
def float_to_float_float(float x):
"""
>>> 4.05 < float_to_float_float(4.1) < 4.15
......
......@@ -149,6 +149,25 @@ def loop():
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_assert_path_exists('//InPlaceAssignmentNode/NameNode',
'//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