DPNP C++ backend kernel library 0.20.0dev1
Data Parallel Extension for NumPy*
Loading...
Searching...
No Matches
divmod.hpp
1//*****************************************************************************
2// Copyright (c) 2025, Intel Corporation
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are met:
7// - Redistributions of source code must retain the above copyright notice,
8// this list of conditions and the following disclaimer.
9// - Redistributions in binary form must reproduce the above copyright notice,
10// this list of conditions and the following disclaimer in the documentation
11// and/or other materials provided with the distribution.
12// - Neither the name of the copyright holder nor the names of its contributors
13// may be used to endorse or promote products derived from this software
14// without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26// THE POSSIBILITY OF SUCH DAMAGE.
27//*****************************************************************************
28
29#pragma once
30
31#include <limits>
32#include <type_traits>
33
34#include <sycl/sycl.hpp>
35
36namespace dpnp::kernels::divmod
37{
38template <typename argT1, typename argT2, typename divT, typename modT>
40{
41 using argT = argT1;
42
43 static_assert(std::is_same_v<argT, argT2>,
44 "Input types are expected to be the same");
45 static_assert(std::is_integral_v<argT> || std::is_floating_point_v<argT> ||
46 std::is_same_v<argT, sycl::half>,
47 "Input types are expected to be integral or floating");
48
49 using supports_vec = typename std::false_type;
50 using supports_sg_loadstore = typename std::true_type;
51
52 divT operator()(const argT &in1, const argT &in2, modT &mod) const
53 {
54 if constexpr (std::is_integral_v<argT>) {
55 if (in2 == argT(0)) {
56 mod = modT(0);
57 return divT(0);
58 }
59
60 if constexpr (std::is_signed_v<argT>) {
61 if ((in1 == std::numeric_limits<argT>::min()) &&
62 (in2 == argT(-1))) {
63 mod = modT(0);
64 return std::numeric_limits<argT>::min();
65 }
66 }
67
68 divT div = in1 / in2;
69 mod = in1 % in2;
70
71 if constexpr (std::is_signed_v<argT>) {
72 if (l_xor(in1 > 0, in2 > 0) && (mod != 0)) {
73 div -= divT(1);
74 mod += in2;
75 }
76 }
77 return div;
78 }
79 else {
80 mod = sycl::fmod(in1, in2);
81 if (!in2) {
82 // in2 == 0 (not NaN): return result of fmod (for IEEE is nan)
83 return in1 / in2;
84 }
85
86 // (in1 - mod) should be very nearly an integer multiple of in2
87 auto div = (in1 - mod) / in2;
88
89 // adjust fmod result to conform to Python convention of remainder
90 if (mod) {
91 if (l_xor(in2 < 0, mod < 0)) {
92 mod += in2;
93 div -= divT(1.0);
94 }
95 }
96 else {
97 // if mod is zero ensure correct sign
98 mod = sycl::copysign(modT(0), in2);
99 }
100
101 // snap quotient to nearest integral value
102 if (div) {
103 auto floordiv = sycl::floor(div);
104 if (div - floordiv > divT(0.5)) {
105 floordiv += divT(1.0);
106 }
107 div = floordiv;
108 }
109 else {
110 // if div is zero ensure correct sign
111 div = sycl::copysign(divT(0), in1 / in2);
112 }
113 return div;
114 }
115 }
116
117private:
118 bool l_xor(bool b1, bool b2) const
119 {
120 return (b1 != b2);
121 }
122};
123} // namespace dpnp::kernels::divmod