Skip to content

Commit 25f0109

Browse files
committed
floor_divide fixed for signed 0 output
1 parent 0506a49 commit 25f0109

File tree

2 files changed

+41
-69
lines changed

2 files changed

+41
-69
lines changed

dpctl/tensor/libtensor/include/kernels/elementwise_functions/floor_divide.hpp

Lines changed: 5 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <CL/sycl.hpp>
2828
#include <cstddef>
2929
#include <cstdint>
30+
#include <limits>
3031
#include <type_traits>
3132

3233
#include "utils/offset_utils.hpp"
@@ -55,8 +56,9 @@ struct FloorDivideFunctor
5556

5657
using supports_sg_loadstore = std::negation<
5758
std::disjunction<tu_ns::is_complex<argT1>, tu_ns::is_complex<argT2>>>;
58-
using supports_vec = std::negation<
59-
std::disjunction<tu_ns::is_complex<argT1>, tu_ns::is_complex<argT2>>>;
59+
// vec overload disabled due to incorrect output
60+
// for signed zero, infinities
61+
using supports_vec = typename std::false_type;
6062

6163
resT operator()(const argT1 &in1, const argT2 &in2)
6264
{
@@ -77,59 +79,7 @@ struct FloorDivideFunctor
7779
}
7880
}
7981
else {
80-
return sycl::floor(tmp);
81-
}
82-
}
83-
84-
template <int vec_sz>
85-
sycl::vec<resT, vec_sz> operator()(const sycl::vec<argT1, vec_sz> &in1,
86-
const sycl::vec<argT2, vec_sz> &in2)
87-
{
88-
auto tmp = in1 / in2;
89-
using tmpT = typename decltype(tmp)::element_type;
90-
if constexpr (std::is_integral_v<tmpT>) {
91-
if constexpr (std::is_signed_v<tmpT>) {
92-
auto rem_tmp = in1 % in2;
93-
#pragma unroll
94-
for (int i = 0; i < vec_sz; ++i) {
95-
if (in2[i] == argT2(0)) {
96-
tmp[i] = tmpT(0);
97-
}
98-
else {
99-
tmpT corr = (rem_tmp[i] != 0 &&
100-
((rem_tmp[i] < 0) != (in2[i] < 0)));
101-
tmp[i] -= corr;
102-
}
103-
}
104-
}
105-
else {
106-
#pragma unroll
107-
for (int i = 0; i < vec_sz; ++i) {
108-
if (in2[i] == argT2(0)) {
109-
tmp[i] = tmpT(0);
110-
}
111-
}
112-
}
113-
if constexpr (std::is_same_v<resT, tmpT>) {
114-
return tmp;
115-
}
116-
else {
117-
using dpctl::tensor::type_utils::vec_cast;
118-
return vec_cast<resT, tmpT, vec_sz>(tmp);
119-
}
120-
}
121-
else {
122-
sycl::vec<resT, vec_sz> res = sycl::floor(tmp);
123-
if constexpr (std::is_same_v<resT,
124-
typename decltype(res)::element_type>)
125-
{
126-
return res;
127-
}
128-
else {
129-
using dpctl::tensor::type_utils::vec_cast;
130-
return vec_cast<resT, typename decltype(res)::element_type,
131-
vec_sz>(res);
132-
}
82+
return (tmp == 0) ? resT(tmp) : resT(std::floor(tmp));
13383
}
13484
}
13585
};

dpctl/tests/elementwise/test_floor_divide.py

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -203,16 +203,6 @@ def test_floor_divide_gh_1247():
203203
dpt.asnumpy(res), np.full(res.shape, -1, dtype=res.dtype)
204204
)
205205

206-
# attempt to invoke sycl::vec overload using a larger array
207-
x = dpt.arange(-64, 65, 1, dtype="i4")
208-
np.testing.assert_array_equal(
209-
dpt.asnumpy(dpt.floor_divide(x, 3)), np.floor_divide(dpt.asnumpy(x), 3)
210-
)
211-
np.testing.assert_array_equal(
212-
dpt.asnumpy(dpt.floor_divide(x, -3)),
213-
np.floor_divide(dpt.asnumpy(x), -3),
214-
)
215-
216206

217207
@pytest.mark.parametrize("dtype", _no_complex_dtypes[1:9])
218208
def test_floor_divide_integer_zero(dtype):
@@ -226,10 +216,42 @@ def test_floor_divide_integer_zero(dtype):
226216
dpt.asnumpy(res), np.zeros(x.shape, dtype=res.dtype)
227217
)
228218

229-
# attempt to invoke sycl::vec overload using a larger array
230-
x = dpt.arange(129, dtype=dtype, sycl_queue=q)
231-
y = dpt.zeros_like(x, sycl_queue=q)
219+
220+
def test_floor_divide_special_cases():
221+
q = get_queue_or_skip()
222+
223+
x = dpt.empty(1, dtype="f4", sycl_queue=q)
224+
y = dpt.empty_like(x)
225+
x[0], y[0] = dpt.inf, dpt.inf
226+
res = dpt.floor_divide(x, y)
227+
with np.errstate(all="ignore"):
228+
res_np = np.floor_divide(dpt.asnumpy(x), dpt.asnumpy(y))
229+
np.testing.assert_array_equal(dpt.asnumpy(res), res_np)
230+
231+
x[0], y[0] = 0.0, -1.0
232+
res = dpt.floor_divide(x, y)
233+
x_np = dpt.asnumpy(x)
234+
y_np = dpt.asnumpy(y)
235+
res_np = np.floor_divide(x_np, y_np)
236+
np.testing.assert_array_equal(dpt.asnumpy(res), res_np)
237+
238+
res = dpt.floor_divide(y, x)
239+
with np.errstate(all="ignore"):
240+
res_np = np.floor_divide(y_np, x_np)
241+
np.testing.assert_array_equal(dpt.asnumpy(res), res_np)
242+
243+
x[0], y[0] = -1.0, dpt.inf
232244
res = dpt.floor_divide(x, y)
233245
np.testing.assert_array_equal(
234-
dpt.asnumpy(res), np.zeros(x.shape, dtype=res.dtype)
246+
dpt.asnumpy(res), np.asarray([-0.0], dtype="f4")
235247
)
248+
249+
res = dpt.floor_divide(y, x)
250+
np.testing.assert_array_equal(
251+
dpt.asnumpy(res), np.asarray([-dpt.inf], dtype="f4")
252+
)
253+
254+
x[0], y[0] = 1.0, dpt.nan
255+
res = dpt.floor_divide(x, y)
256+
res_np = np.floor_divide(dpt.asnumpy(x), dpt.asnumpy(y))
257+
np.testing.assert_array_equal(dpt.asnumpy(res), res_np)

0 commit comments

Comments
 (0)