From: Stefan Behnel Date: Tue, 8 Dec 2009 00:05:01 +0000 (+0100) Subject: translate Python float calculations into C doubles X-Git-Tag: 0.12.1~60 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=b9fc5d9224201b695ef2a75a587f89c26f6b30f0;p=cython.git translate Python float calculations into C doubles --- diff --git a/Cython/Compiler/Builtin.py b/Cython/Compiler/Builtin.py index c39258dc..8d87af99 100644 --- a/Cython/Compiler/Builtin.py +++ b/Cython/Compiler/Builtin.py @@ -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() diff --git a/Cython/Compiler/ExprNodes.py b/Cython/Compiler/ExprNodes.py index ce9f383c..75bf4e62 100644 --- a/Cython/Compiler/ExprNodes.py +++ b/Cython/Compiler/ExprNodes.py @@ -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 diff --git a/Cython/Compiler/PyrexTypes.py b/Cython/Compiler/PyrexTypes.py index 35ac35f7..b319a4d8 100644 --- a/Cython/Compiler/PyrexTypes.py +++ b/Cython/Compiler/PyrexTypes.py @@ -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): diff --git a/Cython/Compiler/TypeInference.py b/Cython/Compiler/TypeInference.py index c1424536..d9b2ad91 100644 --- a/Cython/Compiler/TypeInference.py +++ b/Cython/Compiler/TypeInference.py @@ -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 diff --git a/tests/run/int_float_builtins_as_casts_T400.pyx b/tests/run/int_float_builtins_as_casts_T400.pyx index c0fc52ea..fd2a7408 100644 --- a/tests/run/int_float_builtins_as_casts_T400.pyx +++ b/tests/run/int_float_builtins_as_casts_T400.pyx @@ -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 diff --git a/tests/run/type_inference.pyx b/tests/run/type_inference.pyx index 0666014b..dd899fdf 100644 --- a/tests/run/type_inference.pyx +++ b/tests/run/type_inference.pyx @@ -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]',