Skip to content

ARROW-12685: [C++][Compute] Add unary absolute value kernel - #10274

Closed
edponce wants to merge 3 commits into
apache:masterfrom
edponce:ARROW-12685-Compute-Add-unary-absolute-value-kernel
Closed

ARROW-12685: [C++][Compute] Add unary absolute value kernel#10274
edponce wants to merge 3 commits into
apache:masterfrom
edponce:ARROW-12685-Compute-Add-unary-absolute-value-kernel

Conversation

@edponce

Copy link
Copy Markdown
Contributor

This PR adds the arithmetic absolute value kernels to the compute layer.

@github-actions

Copy link
Copy Markdown

Thanks for opening a pull request!

If this is not a minor PR. Could you open an issue for this pull request on JIRA? https://issues.apache.org/jira/browse/ARROW

Opening JIRAs ahead of time contributes to the Openness of the Apache Arrow project.

Then could you also rename pull request title in the following format?

ARROW-${JIRA_ID}: [${COMPONENT}] ${SUMMARY}

or

MINOR: [${COMPONENT}] ${SUMMARY}

See also:

@emkornfieldemkornfield changed the title Arrow 12685 compute add unary absolute value kernelARROW-12685: [C++][compute] add unary absolute value kernelMay 11, 2021
@github-actions

Copy link
Copy Markdown

@edponce

edponce commented May 11, 2021

Copy link
Copy Markdown
ContributorAuthor

I named the compute function as AbsoluteValue and kernels as "absolute_value" but this feels like too long a name. Convention across other libraries is "abs" but Arrow's compute kernels tend to follow the longer format and "absolute" seems ambiguous. @bkietz please advise

@edponce
edponce marked this pull request as ready for review May 11, 2021 19:24
Comment threadcpp/src/arrow/compute/kernels/scalar_arithmetic.cc Outdated
Comment threadcpp/src/arrow/compute/kernels/scalar_arithmetic.cc Outdated
Comment threadcpp/src/arrow/compute/kernels/scalar_arithmetic_test.cc Outdated
@edponceedponce changed the title ARROW-12685: [C++][compute] add unary absolute value kernelARROW-12685: [C++][Compute] Add unary absolute value kernelMay 12, 2021
Comment threadcpp/src/arrow/compute/api_scalar.cc Outdated
Comment threadcpp/src/arrow/compute/api_scalar.h Outdated
Comment threadcpp/src/arrow/compute/kernels/scalar_arithmetic.cc Outdated
@edponce

edponce commented May 13, 2021

Copy link
Copy Markdown
ContributorAuthor

@cyb70289 I noticed that clang removes the check of if (result < 0) because it seems that during the analysis it has a rule that the result of std::abs() is never negative, but this is not true if the input is std::numeric_limits<T>::min(). In other words, it does not considers the overflow case, although the value returned by std::abs() is negative and correct. See https://godbolt.org/z/7bsM4oTMG to observe this effect. I also tested the godbolt example using unknown values at compile-time and observe the same behavior. This behavior is observed across compilers. My conclusion is to follow the form of abs_2(), that is, if (arg == std::numeric_limits<T>::min()).

@cyb70289

cyb70289 commented May 13, 2021

Copy link
Copy Markdown
Contributor

Thanks @edponce for deep investigation.

From std::abs() document, it is UB if input is numeic_limit::min(). So compiler can do whatever optimization that doesn't violate the standard.

Computes the absolute value of an integer number. The behavior is undefined if the result cannot be represented by the return type.

For checked abs, you can check arg == min() before calling std::abs().
For non-checked abs, thought compiler generated code is safe (no UB), I think it's better to go back to return v < 0 ? (~(unsigned)v + 1) : v; approach. Though the assembly code is exactly the same, compiler may decide to change behaviour in the future.

@edponce

edponce commented May 13, 2021

Copy link
Copy Markdown
ContributorAuthor

For such a simple kernel we found:

  1. We need to handle overflow case manually because the standard states it is undefined behavior
  2. Compilers can prune checks that test for negative value the result of an absolute value operation. The purpose of such check is to detect overflow. For example,
result = std::abs(arg);
if (result < 0) {
ERROR(...);
}
return result;

becomes result = std::abs(arg). The solution is to first check if input is a value that will overflow

if (arg == std::numeric_limits<T>::min()) {
ERROR(...);
return arg;
}
result = std::abs(arg);
  1. Tests performing checks for special cases such as -0.0 == 0.0 should also check the sign bit, std::signbit(val).

@edponce
edponceforce-pushed the ARROW-12685-Compute-Add-unary-absolute-value-kernel branch from 03f6f1e to f8d6956CompareMay 13, 2021 12:39
@edponce
edponce requested review from cyb70289 and pitrouMay 13, 2021 13:18
Comment threaddocs/source/cpp/compute.rst Outdated
Comment threadcpp/src/arrow/util/int_util_internal.h Outdated
@cyb70289

Copy link
Copy Markdown
Contributor

Also, would you rebase to fix some CI failures? #10310

@edponce
edponceforce-pushed the ARROW-12685-Compute-Add-unary-absolute-value-kernel branch from 780c6a0 to 4294ba5CompareMay 14, 2021 16:48

@cyb70289cyb70289 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, +1

@cyb70289

Copy link
Copy Markdown
Contributor

@pitrou, do you have other comments to this PR?

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@edponce@cyb70289@pitrou