Skip to content

Add decimal division functionality with scale preservation#22261

Open
simoneves wants to merge 4 commits into
rapidsai:mainfrom
simoneves:simoneves/a-hirota/decimal-division-operations-rebased
Open

Add decimal division functionality with scale preservation#22261
simoneves wants to merge 4 commits into
rapidsai:mainfrom
simoneves:simoneves/a-hirota/decimal-division-operations-rebased

Conversation

@simoneves
Copy link
Copy Markdown

Resurrection of #19861, rebased on main for 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.

  • 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 #17448

(cherry picked from commit f8b1ff34ef9490b486ab76f2071b86c6d4d3423c)

Description

Checklist

  • I am familiar with the Contributing Guidelines.
  • New or existing tests cover these changes.
  • The documentation is up to date with these changes.

@simoneves simoneves requested review from a team as code owners April 22, 2026 23:48
@github-actions github-actions Bot added libcudf Affects libcudf (C++/CUDA) code. Python Affects Python cuDF API. CMake CMake build issue pylibcudf Issues specific to the pylibcudf package labels Apr 22, 2026
@GPUtester GPUtester moved this to In Progress in cuDF Python Apr 22, 2026
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)
@simoneves simoneves force-pushed the simoneves/a-hirota/decimal-division-operations-rebased branch from aefd0bd to e3bbe5b Compare April 23, 2026 00:53
@GregoryKimball
Copy link
Copy Markdown
Contributor

Thank you @a-hirota for your excellent contribution in #19861! We are looking to refresh and rework your implementation here. 💚 😄

@GregoryKimball GregoryKimball moved this to Burndown in libcudf May 4, 2026
@mhaseeb123 mhaseeb123 changed the title feat(cudf): Add decimal division functionality with scale preservation Add decimal division functionality with scale preservation May 7, 2026
Comment on lines +1 to +15
/*
* 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.
*/
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/*
* 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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment on lines +42 to +49
* @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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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()`
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output contains the result of divide_decimal(lhs[i], rhs[i]) for all 0 <= 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
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to add default value here as clear from the param below. Also less future maintenance

Suggested change
* @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()));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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(
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like unused functor?

}
};

std::unique_ptr<column> divide_decimal_impl(column_view const& lhs,
Copy link
Copy Markdown
Member

@mhaseeb123 mhaseeb123 May 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Member

@mhaseeb123 mhaseeb123 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First-pass human review. Please update the PR description to be inline with cudf template and standards (clear, concise, direct, human-written preferred, no git or commit details unless needed for context)

@@ -0,0 +1,103 @@
/*
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CMake CMake build issue libcudf Affects libcudf (C++/CUDA) code. pylibcudf Issues specific to the pylibcudf package Python Affects Python cuDF API.

Projects

Status: In Progress
Status: Burndown

Development

Successfully merging this pull request may close these issues.

5 participants