Add decimal division functionality with scale preservation#22261
Add decimal division functionality with scale preservation#22261simoneves wants to merge 4 commits into
Conversation
Implements divide_decimal for fixed-point decimal columns that preserves the dividend's scale, similar to Java BigDecimal.divide() with rounding mode. - Add divide_decimal C++ implementation with HALF_UP and HALF_EVEN rounding - Add Python bindings via pylibcudf - Add divide_decimal method to DecimalBaseColumn - Add comprehensive tests for various scales and rounding modes - Fix critical bug in C++ implementation for different scales - Add Doxygen documentation for new functions Addresses issue rapidsai#17448 Co-authored-by: Akihiro Hirota <akihiro-hirota@gmobiz.com> (cherry picked from commit f8b1ff34ef9490b486ab76f2071b86c6d4d3423c)
aefd0bd to
e3bbe5b
Compare
| /* | ||
| * Copyright (c) 2025, NVIDIA CORPORATION. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ |
There was a problem hiding this comment.
| /* | |
| * Copyright (c) 2025, NVIDIA CORPORATION. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| /* | |
| * SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION. | |
| * SPDX-License-Identifier: Apache-2.0 | |
| */ |
| namespace CUDF_EXPORT cudf { | ||
|
|
||
| /** | ||
| * @addtogroup transformation_decimalops |
There was a problem hiding this comment.
I think this doxygen group does not already exist and we need to add it. Might need to rename it to match existing patterns if any
| * @param lhs The left operand column | ||
| * @param rhs The right operand column | ||
| * @param rounding_mode The rounding mode to use | ||
| * @param stream CUDA stream used for device memory operations and kernel launches | ||
| * @param mr Device memory resource used to allocate the returned column's device memory | ||
| * @return Output column containing the result of the decimal division | ||
| * @throw cudf::logic_error if @p lhs and @p rhs are different sizes | ||
| * @throw cudf::logic_error if @p lhs and @p rhs are not decimal types |
There was a problem hiding this comment.
clang-format likely needed here
| /** | ||
| * @brief Performs decimal division between two columns with scale preservation. | ||
| * | ||
| * The output contains the result of `divide_decimal(lhs[i], rhs[i])` for all `0 <= i < lhs.size()` |
There was a problem hiding this comment.
The output contains the result of
divide_decimal(lhs[i], rhs[i])for all0 <= i < lhs.size()
Result of divide_decimal(lhs[i], rhs[i]) isn't yet defined as this is the first instance of this API overload
| @@ -11,6 +11,7 @@ | |||
| import numpy as np | |||
There was a problem hiding this comment.
Please separate out python bindings and pytests into a separate follow up PR if possible to limit the scope of this PR
| * @tparam Rad1 The radix of the fixed-point numbers | ||
| * @param lhs The dividend (left-hand side of division) | ||
| * @param rhs The divisor (right-hand side of division) | ||
| * @param rounding_mode The rounding mode to use (default: HALF_UP) |
There was a problem hiding this comment.
No need to add default value here as clear from the param below. Also less future maintenance
| * @param rounding_mode The rounding mode to use (default: HALF_UP) | |
| * @param rounding_mode The rounding mode to use |
| // We need to compensate for the scale difference to preserve the dividend's scale | ||
| // Standard division would give us scale = lhs.scale() - rhs.scale() | ||
| // To preserve lhs.scale(), we need to scale up by 10^(-rhs.scale()) | ||
| auto const scale_factor = detail::ipow<Rep1, Rad1>(-static_cast<int>(rhs.scale())); |
There was a problem hiding this comment.
We should look into reusing utils from src/round/round.cu here if possible to avoid code duplication
| * @return A fixed-point number with the same scale as the dividend | ||
| */ | ||
| template <typename Rep1, Radix Rad1> | ||
| CUDF_HOST_DEVICE inline fixed_point<Rep1, Rad1> divide_decimal( |
There was a problem hiding this comment.
Is the CUDF_HOST_DEVICE needed or could this just be a device only util since i only see it being called from a device function below
| namespace detail { | ||
|
|
||
| template <typename DecimalType> | ||
| struct divide_decimal_functor { |
| } | ||
| }; | ||
|
|
||
| std::unique_ptr<column> divide_decimal_impl(column_view const& lhs, |
There was a problem hiding this comment.
Would recommend restructuring the code in this file as follows:
namespace CUDF_EXPORT cudf {
namespace detail {
// Provided two fixed point iterators here and computes decimal_divide from `fixed_point.hpp` using a transform on them.
template <LHS, RHS>
std::unique_ptr<column> divide_decimal(LHS lhs, RHS rhs, size_type size ...)
{}
// Detail APIs for decimal_divide(col, col), decimal_divide(col, scalar), decimal_divide(scalar, col) overloads that call the above one with combination of regular (columns) or `cuda::constant_iterator` (scalars)
} // namespace detail
// public APIs here that just do this
std::unique_ptr<column> divide_decimal(..)
{
CUDF_FUNC_RANGE();
return detail::divide_decimal(..)
}
} // namespace cudf| @@ -0,0 +1,103 @@ | |||
| /* | |||
There was a problem hiding this comment.
Nit: Reconsider renaming the file. Here decimal/decimal_ops.hpp the word decimal seems to be repeating, also adds a new folder. Perhaps we could move this to cudf/fixed_point/math_ops.hpp.
Open to suggestions
Resurrection of #19861, rebased on
mainfor testing with Velox====
Implements divide_decimal for fixed-point decimal columns that preserves the dividend's scale, similar to Java BigDecimal.divide() with rounding mode.
Addresses issue #17448
(cherry picked from commit f8b1ff34ef9490b486ab76f2071b86c6d4d3423c)
Description
Checklist