[flang-commits] [flang] [flang][runtime] Use std::fmod for most MOD/MODULO (PR #78745)
via flang-commits
flang-commits at lists.llvm.org
Fri Jan 19 09:05:28 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-runtime
Author: Peter Klausler (klausler)
<details>
<summary>Changes</summary>
The new accurate algorithm for real MOD and MODULO in the runtime is not as fast as std::fmod(), which is also accurate. So use std::fmod() for those floating-point types that it supports.
Fixes https://github.com/llvm/llvm-project/issues/78641.
---
Full diff: https://github.com/llvm/llvm-project/pull/78745.diff
1 Files Affected:
- (modified) flang/runtime/numeric.cpp (+25-17)
``````````diff
diff --git a/flang/runtime/numeric.cpp b/flang/runtime/numeric.cpp
index 3f6f553e7bb554d..ad6b0e854522496 100644
--- a/flang/runtime/numeric.cpp
+++ b/flang/runtime/numeric.cpp
@@ -145,25 +145,33 @@ inline RT_API_ATTRS T RealMod(
} else if (std::isinf(p)) {
return a;
} else {
- // The standard defines MOD(a,p)=a-AINT(a/p)*p and
- // MODULO(a,p)=a-FLOOR(a/p)*p, but those definitions lose
- // precision badly due to cancellation when ABS(a) is
- // much larger than ABS(p).
- // Insights:
- // - MOD(a,p)=MOD(a-n*p,p) when a>0, p>0, integer n>0, and a>=n*p
- // - when n is a power of two, n*p is exact
- // - as a>=n*p, a-n*p does not round.
- // So repeatedly reduce a by all n*p in decreasing order of n;
- // what's left is the desired remainder. This is basically
- // the same algorithm as arbitrary precision binary long division,
- // discarding the quotient.
T tmp{std::abs(a)};
T pAbs{std::abs(p)};
- for (T adj{SetExponent(pAbs, Exponent<int>(tmp))}; tmp >= pAbs; adj /= 2) {
- if (tmp >= adj) {
- tmp -= adj;
- if (tmp == 0) {
- break;
+ if (tmp < pAbs) {
+ } else if constexpr (std::is_same_v<T, float> ||
+ std::is_same_v<T, double> || std::is_same_v<T, long double>) {
+ tmp = std::fmod(tmp, pAbs);
+ } else {
+ // The standard defines MOD(a,p)=a-AINT(a/p)*p and
+ // MODULO(a,p)=a-FLOOR(a/p)*p, but those definitions lose
+ // precision badly due to cancellation when ABS(a) is
+ // much larger than ABS(p) and the values are not
+ // integers
+ // Insights:
+ // - MOD(a,p)=MOD(a-n*p,p) when a>0, p>0, integer n>0, and a>=n*p
+ // - when n is a power of two, n*p is exact
+ // - as a>=n*p, a-n*p does not round.
+ // So repeatedly reduce a by all n*p in decreasing order of n;
+ // what's left is the desired remainder. This is basically
+ // the same algorithm as arbitrary precision binary long division,
+ // discarding the quotient.
+ for (T adj{SetExponent(pAbs, Exponent<int>(tmp))}; tmp >= pAbs;
+ adj /= 2) {
+ if (tmp >= adj) {
+ tmp -= adj;
+ if (tmp == 0) {
+ break;
+ }
}
}
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/78745
More information about the flang-commits
mailing list