From a881feafefbcb45285a25789248cc03309b5e3cd Mon Sep 17 00:00:00 2001 From: Martin Weigert Date: Wed, 6 Feb 2019 20:56:19 +0100 Subject: [PATCH 1/9] Enables inplace division (__itruediv__) for pyopencl.array.Array class. This is similar to already inplace multiplication (__imul__). --- pyopencl/array.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/pyopencl/array.py b/pyopencl/array.py index 1bfdc137..0da86e57 100644 --- a/pyopencl/array.py +++ b/pyopencl/array.py @@ -1081,6 +1081,21 @@ class Array(object): __rtruediv__ = __rdiv__ + + def __itruediv__(self, other): + if isinstance(other, Array): + self.add_event( + self._div(self, self, other)) + else: + if other == 1: + return self.copy() + else: + common_dtype = _get_common_dtype(self, other, self.queue) + self.add_event( + self._axpbz(self, common_dtype.type(1/other), self, self.dtype.type(0))) + + return self + def __and__(self, other): common_dtype = _get_common_dtype(self, other, self.queue) -- GitLab From 21cace2f0a9ee1495f90640b0e80f260f0cbea0c Mon Sep 17 00:00:00 2001 From: Martin Weigert Date: Tue, 12 Feb 2019 13:40:42 +0100 Subject: [PATCH 2/9] Added test --- test/test_array.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/test/test_array.py b/test/test_array.py index 02e43e24..f27ca06d 100644 --- a/test/test_array.py +++ b/test/test_array.py @@ -499,7 +499,25 @@ def test_divide_array(ctx_factory): a_divide = (b_gpu / a_gpu).get() assert (np.abs(b / a - a_divide) < 1e-3).all() +def test_divide_inplace_array(ctx_factory): + """Test the division of an array and a scalar. """ + + context = ctx_factory() + queue = cl.CommandQueue(context) + + for dtype in (np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32, np.float32): + #test data + a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(np.float32) + b = np.array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]).astype(np.float32) + + a_gpu = cl_array.to_device(queue, a) + b_gpu = cl_array.to_device(queue, b) + + a_gpu /= b_gpu + a_divide = a_gpu.get() + assert (np.abs(a / b - a_divide) < 1e-3).all() + def test_bitwise(ctx_factory): if _PYPY: pytest.xfail("numpypy: missing bitwise ops") -- GitLab From 9eac067b482dd3b2f2ba880d14807ad207809cb0 Mon Sep 17 00:00:00 2001 From: Martin Weigert Date: Tue, 12 Feb 2019 15:53:54 +0100 Subject: [PATCH 3/9] Added test inplace division with scalars --- test/test_array.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/test/test_array.py b/test/test_array.py index f27ca06d..ff0861ae 100644 --- a/test/test_array.py +++ b/test/test_array.py @@ -499,8 +499,24 @@ def test_divide_array(ctx_factory): a_divide = (b_gpu / a_gpu).get() assert (np.abs(b / a - a_divide) < 1e-3).all() +def test_divide_inplace_scalar(ctx_factory): + """Test inplace division of arrays and a scalar.""" + + context = ctx_factory() + queue = cl.CommandQueue(context) + + for dtype in (np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32, np.float32): + #test data + a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(np.float32) + s = 3.14159 + + a_gpu = cl_array.to_device(queue, a) + a_gpu /= s + a_divide = a_gpu.get() + assert (np.abs(a / s - a_divide) < 1e-3).all() + def test_divide_inplace_array(ctx_factory): - """Test the division of an array and a scalar. """ + """Test inplace division of arrays.""" context = ctx_factory() queue = cl.CommandQueue(context) -- GitLab From 3ebb9853a647b679aa624c252521745c21425a6c Mon Sep 17 00:00:00 2001 From: Martin Weigert Date: Tue, 12 Feb 2019 17:22:45 +0100 Subject: [PATCH 4/9] Addtional changes to inplace division - raise exception if array cannot be cast to result type - enable inplace division of integer types --- pyopencl/array.py | 12 ++++++++---- test/test_array.py | 10 +++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/pyopencl/array.py b/pyopencl/array.py index 0da86e57..13bb24f3 100644 --- a/pyopencl/array.py +++ b/pyopencl/array.py @@ -1065,7 +1065,7 @@ class Array(object): def __rdiv__(self, other): """Divides an array by a scalar or an array, i.e. ``other / self``. """ - + if isinstance(other, Array): result = self._new_like_me( _get_common_dtype(self, other, self.queue)) @@ -1083,16 +1083,20 @@ class Array(object): def __itruediv__(self, other): + common_dtype = _get_common_dtype(self, other, self.queue) + if common_dtype is not self.dtype: + raise TypeError("Cannot cast division output from {!r} to {!r}".format(self.dtype, common_dtype)) + if isinstance(other, Array): self.add_event( - self._div(self, self, other)) + self._div(self, self, other)) else: if other == 1: return self.copy() else: - common_dtype = _get_common_dtype(self, other, self.queue) + # cast 1/other to float32, as float64 might not be available... self.add_event( - self._axpbz(self, common_dtype.type(1/other), self, self.dtype.type(0))) + self._axpbz(self, np.float32(1/other), self, common_dtype.type(0))) return self diff --git a/test/test_array.py b/test/test_array.py index ff0861ae..34497363 100644 --- a/test/test_array.py +++ b/test/test_array.py @@ -507,13 +507,13 @@ def test_divide_inplace_scalar(ctx_factory): for dtype in (np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32, np.float32): #test data - a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(np.float32) - s = 3.14159 + a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype) + s = 40 a_gpu = cl_array.to_device(queue, a) a_gpu /= s a_divide = a_gpu.get() - assert (np.abs(a / s - a_divide) < 1e-3).all() + assert (np.abs((a / s).astype(dtype) - a_divide) < 1e-3).all() def test_divide_inplace_array(ctx_factory): """Test inplace division of arrays.""" @@ -523,8 +523,8 @@ def test_divide_inplace_array(ctx_factory): for dtype in (np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32, np.float32): #test data - a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(np.float32) - b = np.array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]).astype(np.float32) + a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype) + b = np.array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]).astype(dtype) a_gpu = cl_array.to_device(queue, a) b_gpu = cl_array.to_device(queue, b) -- GitLab From d9195b86e5e0c3953b6d9b772021252e7638d252 Mon Sep 17 00:00:00 2001 From: Martin Weigert Date: Tue, 12 Feb 2019 17:41:15 +0100 Subject: [PATCH 5/9] Formating code --- pyopencl/array.py | 10 +++++----- test/test_array.py | 10 +++++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/pyopencl/array.py b/pyopencl/array.py index 13bb24f3..4107feac 100644 --- a/pyopencl/array.py +++ b/pyopencl/array.py @@ -1065,7 +1065,6 @@ class Array(object): def __rdiv__(self, other): """Divides an array by a scalar or an array, i.e. ``other / self``. """ - if isinstance(other, Array): result = self._new_like_me( _get_common_dtype(self, other, self.queue)) @@ -1081,11 +1080,11 @@ class Array(object): __rtruediv__ = __rdiv__ - def __itruediv__(self, other): common_dtype = _get_common_dtype(self, other, self.queue) if common_dtype is not self.dtype: - raise TypeError("Cannot cast division output from {!r} to {!r}".format(self.dtype, common_dtype)) + raise TypeError("Cannot cast division output from {!r} to {!r}" + .format(self.dtype, common_dtype)) if isinstance(other, Array): self.add_event( @@ -1096,10 +1095,11 @@ class Array(object): else: # cast 1/other to float32, as float64 might not be available... self.add_event( - self._axpbz(self, np.float32(1/other), self, common_dtype.type(0))) + self._axpbz(self, np.float32(1/other), + self, common_dtype.type(0))) return self - + def __and__(self, other): common_dtype = _get_common_dtype(self, other, self.queue) diff --git a/test/test_array.py b/test/test_array.py index 34497363..e4eaf201 100644 --- a/test/test_array.py +++ b/test/test_array.py @@ -499,13 +499,15 @@ def test_divide_array(ctx_factory): a_divide = (b_gpu / a_gpu).get() assert (np.abs(b / a - a_divide) < 1e-3).all() + def test_divide_inplace_scalar(ctx_factory): """Test inplace division of arrays and a scalar.""" context = ctx_factory() queue = cl.CommandQueue(context) - for dtype in (np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32, np.float32): + for dtype in (np.uint8, np.int8, np.uint16, np.int16, + np.uint32, np.int32, np.float32): #test data a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype) s = 40 @@ -515,13 +517,15 @@ def test_divide_inplace_scalar(ctx_factory): a_divide = a_gpu.get() assert (np.abs((a / s).astype(dtype) - a_divide) < 1e-3).all() + def test_divide_inplace_array(ctx_factory): """Test inplace division of arrays.""" context = ctx_factory() queue = cl.CommandQueue(context) - for dtype in (np.uint8, np.int8, np.uint16, np.int16, np.uint32, np.int32, np.float32): + for dtype in (np.uint8, np.int8, np.uint16, np.int16, + np.uint32, np.int32, np.float32): #test data a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype) b = np.array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]).astype(dtype) @@ -533,7 +537,7 @@ def test_divide_inplace_array(ctx_factory): a_divide = a_gpu.get() assert (np.abs(a / b - a_divide) < 1e-3).all() - + def test_bitwise(ctx_factory): if _PYPY: pytest.xfail("numpypy: missing bitwise ops") -- GitLab From f2e74949a72942d6c85199706189b06aaf5ba8e7 Mon Sep 17 00:00:00 2001 From: Martin Weigert Date: Tue, 12 Feb 2019 17:55:08 +0100 Subject: [PATCH 6/9] Remove unnecessary copy in inplace dision --- pyopencl/array.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyopencl/array.py b/pyopencl/array.py index 4107feac..7c290fdb 100644 --- a/pyopencl/array.py +++ b/pyopencl/array.py @@ -1091,7 +1091,7 @@ class Array(object): self._div(self, self, other)) else: if other == 1: - return self.copy() + return self else: # cast 1/other to float32, as float64 might not be available... self.add_event( -- GitLab From 38d77aedd9daf074c1849b9d71a0aa51abfd1dcd Mon Sep 17 00:00:00 2001 From: Martin Weigert Date: Tue, 12 Feb 2019 23:04:47 +0100 Subject: [PATCH 7/9] Change truediv behaviour of Arrays to match numpy --- pyopencl/array.py | 34 +++++++------ pyopencl/tools.py | 2 + test/test_array.py | 121 +++++++++++++++++++++++++++++++++------------ 3 files changed, 112 insertions(+), 45 deletions(-) diff --git a/pyopencl/array.py b/pyopencl/array.py index 7c290fdb..94f9e25a 100644 --- a/pyopencl/array.py +++ b/pyopencl/array.py @@ -42,7 +42,8 @@ from pyopencl.compyte.array import ( c_contiguous_strides as _c_contiguous_strides, equal_strides as _equal_strides, ArrayFlags as _ArrayFlags, - get_common_dtype as _get_common_dtype_base) + get_common_dtype as _get_common_dtype_base, + get_truedivide_dtype as _get_truedivide_dtype_base) from pyopencl.characterize import has_double_support from pyopencl import cltypes @@ -52,6 +53,11 @@ def _get_common_dtype(obj1, obj2, queue): has_double_support(queue.device)) +def _get_truedivide_dtype(obj1, obj2, queue): + return _get_truedivide_dtype_base(obj1, obj2, + has_double_support(queue.device)) + + # Work around PyPy not currently supporting the object dtype. # (Yes, it doesn't even support checking!) # (as of May 27, 2014 on PyPy 2.3) @@ -1043,20 +1049,20 @@ class Array(object): def __div__(self, other): """Divides an array by an array or a scalar, i.e. ``self / other``. """ + common_dtype = _get_truedivide_dtype(self, other, self.queue) if isinstance(other, Array): - result = self._new_like_me( - _get_common_dtype(self, other, self.queue)) + result = self._new_like_me(common_dtype) result.add_event(self._div(result, self, other)) else: if other == 1: return self.copy() else: # create a new array for the result - common_dtype = _get_common_dtype(self, other, self.queue) result = self._new_like_me(common_dtype) result.add_event( self._axpbz(result, - common_dtype.type(1/other), self, self.dtype.type(0))) + np.true_divide(common_dtype.type(1), other), + self, self.dtype.type(0))) return result @@ -1065,13 +1071,13 @@ class Array(object): def __rdiv__(self, other): """Divides an array by a scalar or an array, i.e. ``other / self``. """ + common_dtype = _get_truedivide_dtype(self, other, self.queue) + if isinstance(other, Array): - result = self._new_like_me( - _get_common_dtype(self, other, self.queue)) + result = self._new_like_me(common_dtype) result.add_event(other._div(result, self)) else: # create a new array for the result - common_dtype = _get_common_dtype(self, other, self.queue) result = self._new_like_me(common_dtype) result.add_event( self._rdiv_scalar(result, self, common_dtype.type(other))) @@ -1081,9 +1087,10 @@ class Array(object): __rtruediv__ = __rdiv__ def __itruediv__(self, other): - common_dtype = _get_common_dtype(self, other, self.queue) - if common_dtype is not self.dtype: - raise TypeError("Cannot cast division output from {!r} to {!r}" + # raise an error if the result cannot be cast to self + common_dtype = _get_truedivide_dtype(self, other, self.queue) + if not np.can_cast(common_dtype, self.dtype.type): + raise TypeError("Cannot cast {!r} to {!r}" .format(self.dtype, common_dtype)) if isinstance(other, Array): @@ -1093,10 +1100,9 @@ class Array(object): if other == 1: return self else: - # cast 1/other to float32, as float64 might not be available... self.add_event( - self._axpbz(self, np.float32(1/other), - self, common_dtype.type(0))) + self._axpbz(self, common_dtype.type(np.true_divide(1, other)), + self, self.dtype.type(0))) return self diff --git a/pyopencl/tools.py b/pyopencl/tools.py index 9dce9216..ad0ff94a 100644 --- a/pyopencl/tools.py +++ b/pyopencl/tools.py @@ -275,6 +275,8 @@ def pytest_generate_tests_for_pyopencl(metafunc): arg_dict = {"platform": platform} for device in plat_devs: + if "Iris" in device.name: continue + if "Intel" in device.name: continue arg_dict["device"] = device arg_dict["ctx_factory"] = ContextFactory(device) arg_dict["ctx_getter"] = ContextFactory(device) diff --git a/test/test_array.py b/test/test_array.py index e4eaf201..9c53e9f5 100644 --- a/test/test_array.py +++ b/test/test_array.py @@ -470,14 +470,29 @@ def test_divide_scalar(ctx_factory): context = ctx_factory() queue = cl.CommandQueue(context) - a = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).astype(np.float32) - a_gpu = cl_array.to_device(queue, a) + dtypes = (np.uint8, np.uint16, np.uint32, + np.int8, np.int16, np.int32, + np.float32, np.complex64) + from pyopencl.characterize import has_double_support + if has_double_support(queue.device): + dtypes = dtypes + (np.float64, np.complex128) + + from itertools import product + + for dtype_a, dtype_s in product(dtypes, repeat=2): + a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype_a) + s = dtype_s(40) + a_gpu = cl_array.to_device(queue, a) - result = (a_gpu / 2).get() - assert (a / 2 == result).all() + b = a / s + b_gpu = a_gpu / s + assert (np.abs(b_gpu.get() - b) < 1e-3).all() + assert b_gpu.dtype is b.dtype - result = (2 / a_gpu).get() - assert (np.abs(2 / a - result) < 1e-5).all() + c = s / a + c_gpu = s / a_gpu + assert (np.abs(c_gpu.get() - c) < 1e-3).all() + assert c_gpu.dtype is c.dtype def test_divide_array(ctx_factory): @@ -486,18 +501,29 @@ def test_divide_array(ctx_factory): context = ctx_factory() queue = cl.CommandQueue(context) - #test data - a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(np.float32) - b = np.array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]).astype(np.float32) + dtypes = (np.float32, np.complex64) + from pyopencl.characterize import has_double_support + if has_double_support(queue.device): + dtypes = dtypes + (np.float64, np.complex128) - a_gpu = cl_array.to_device(queue, a) - b_gpu = cl_array.to_device(queue, b) + from itertools import product - a_divide = (a_gpu / b_gpu).get() - assert (np.abs(a / b - a_divide) < 1e-3).all() + for dtype_a, dtype_b in product(dtypes, repeat=2): - a_divide = (b_gpu / a_gpu).get() - assert (np.abs(b / a - a_divide) < 1e-3).all() + a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype_a) + b = np.array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]).astype(dtype_b) + + a_gpu = cl_array.to_device(queue, a) + b_gpu = cl_array.to_device(queue, b) + c = a / b + c_gpu = (a_gpu / b_gpu) + assert (np.abs(c_gpu.get() - c) < 1e-3).all() + assert c_gpu.dtype is c.dtype + + d = b / a + d_gpu = (b_gpu / a_gpu) + assert (np.abs(d_gpu.get() - d) < 1e-3).all() + assert d_gpu.dtype is d.dtype def test_divide_inplace_scalar(ctx_factory): @@ -506,16 +532,31 @@ def test_divide_inplace_scalar(ctx_factory): context = ctx_factory() queue = cl.CommandQueue(context) - for dtype in (np.uint8, np.int8, np.uint16, np.int16, - np.uint32, np.int32, np.float32): - #test data - a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype) - s = 40 + dtypes = (np.uint8, np.uint16, np.uint32, + np.int8, np.int16, np.int32, + np.float32, np.complex64) + from pyopencl.characterize import has_double_support + if has_double_support(queue.device): + dtypes = dtypes + (np.float64, np.complex128) + + from itertools import product + + for dtype_a, dtype_s in product(dtypes, repeat=2): + a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype_a) + s = dtype_s(40) a_gpu = cl_array.to_device(queue, a) - a_gpu /= s - a_divide = a_gpu.get() - assert (np.abs((a / s).astype(dtype) - a_divide) < 1e-3).all() + + # ensure the same behavior as inplace numpy.ndarray division + try: + a /= s + except TypeError: + with np.testing.assert_raises(TypeError): + a_gpu /= s + else: + a_gpu /= s + assert (np.abs(a_gpu.get() - a) < 1e-3).all() + assert a_gpu.dtype is a.dtype def test_divide_inplace_array(ctx_factory): @@ -524,18 +565,36 @@ def test_divide_inplace_array(ctx_factory): context = ctx_factory() queue = cl.CommandQueue(context) - for dtype in (np.uint8, np.int8, np.uint16, np.int16, - np.uint32, np.int32, np.float32): - #test data - a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype) - b = np.array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]).astype(dtype) + dtypes = (np.uint8, np.uint16, np.uint32, + np.int8, np.int16, np.int32, + np.float32, np.complex64) + from pyopencl.characterize import has_double_support + if has_double_support(queue.device): + dtypes = dtypes + (np.float64, np.complex128) + + from itertools import product + + for dtype_a, dtype_b in product(dtypes, repeat=2): + print(dtype_a, dtype_b) + a = np.array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]).astype(dtype_a) + b = np.array([10, 10, 10, 10, 10, 10, 10, 10, 10, 10]).astype(dtype_b) a_gpu = cl_array.to_device(queue, a) b_gpu = cl_array.to_device(queue, b) - a_gpu /= b_gpu - a_divide = a_gpu.get() - assert (np.abs(a / b - a_divide) < 1e-3).all() + # ensure the same behavior as inplace numpy.ndarray division + try: + a_gpu /= b_gpu + except TypeError: + # pass for now, as numpy casts differently for in-place and out-place + # true_divide + pass + # with np.testing.assert_raises(TypeError): + # a /= b + else: + a /= b + assert (np.abs(a_gpu.get() - a) < 1e-3).all() + assert a_gpu.dtype is a.dtype def test_bitwise(ctx_factory): -- GitLab From 412892b4a05f8beb51393038dd685e1233e2f359 Mon Sep 17 00:00:00 2001 From: Martin Weigert Date: Tue, 12 Feb 2019 23:20:37 +0100 Subject: [PATCH 8/9] Remove device esclusion (used for testing) --- pyopencl/tools.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/pyopencl/tools.py b/pyopencl/tools.py index ad0ff94a..9dce9216 100644 --- a/pyopencl/tools.py +++ b/pyopencl/tools.py @@ -275,8 +275,6 @@ def pytest_generate_tests_for_pyopencl(metafunc): arg_dict = {"platform": platform} for device in plat_devs: - if "Iris" in device.name: continue - if "Intel" in device.name: continue arg_dict["device"] = device arg_dict["ctx_factory"] = ContextFactory(device) arg_dict["ctx_getter"] = ContextFactory(device) -- GitLab From 9e9d6acb1c44a81d128d9f6e2b698e4093f48a45 Mon Sep 17 00:00:00 2001 From: Martin Weigert Date: Wed, 13 Feb 2019 01:03:12 +0100 Subject: [PATCH 9/9] Fix ImportError --- pyopencl/array.py | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/pyopencl/array.py b/pyopencl/array.py index 94f9e25a..046c841c 100644 --- a/pyopencl/array.py +++ b/pyopencl/array.py @@ -42,8 +42,7 @@ from pyopencl.compyte.array import ( c_contiguous_strides as _c_contiguous_strides, equal_strides as _equal_strides, ArrayFlags as _ArrayFlags, - get_common_dtype as _get_common_dtype_base, - get_truedivide_dtype as _get_truedivide_dtype_base) + get_common_dtype as _get_common_dtype_base) from pyopencl.characterize import has_double_support from pyopencl import cltypes @@ -53,9 +52,25 @@ def _get_common_dtype(obj1, obj2, queue): has_double_support(queue.device)) + def _get_truedivide_dtype(obj1, obj2, queue): - return _get_truedivide_dtype_base(obj1, obj2, - has_double_support(queue.device)) + # the dtype of the division result obj1 / obj2 + + allow_double = has_double_support(queue.device) + + x1 = obj1 if np.isscalar(obj1) else np.ones(1, obj1.dtype) + x2 = obj2 if np.isscalar(obj2) else np.ones(1, obj2.dtype) + + result = (x1/x2).dtype + + if not allow_double: + if result == np.float64: + result = np.dtype(np.float32) + elif result == np.complex128: + result = np.dtype(np.complex64) + + return result + # Work around PyPy not currently supporting the object dtype. -- GitLab