include/sal/mathconf.h | 14 +++++ sal/rtl/math.cxx | 135 +++++++++++++++++++++++++------------------------ 2 files changed, 85 insertions(+), 64 deletions(-)
New commits: commit ead1cdd23f5379f5cd8f69d5e73f410a67896db2 Author: Eike Rathke <er...@redhat.com> AuthorDate: Thu Dec 17 20:44:43 2020 +0100 Commit: Eike Rathke <er...@redhat.com> CommitDate: Fri Dec 18 11:00:57 2020 +0100 Check intermediate for not to be rounded value, tdf#138360 follow-up This is a combination of 3 commits. Add sal_uInt64 fields to sal_math_Double We may need them later, and at least don't have a confusing inf_parts or nan_parts struct name but just parts as well. Ife0cf279c47d2815aa2a1483223397b147e9d776 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107924 Reviewed-by: Eike Rathke <er...@redhat.com> Tested-by: Jenkins Replace log2() call with parts.exponent-1023, tdf#138360 follow-up ... to save some cycles as we anyway need only the integer value of the exponent and even exactly this value for the number of possible decimals. I8d462f53cadde6a95d57d1342d8487fbfa001ae9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107928 Tested-by: Jenkins Reviewed-by: Eike Rathke <er...@redhat.com> Check intermediate for not to be rounded value, tdf#138360 follow-up I98cc25267e7a10c34179bab50d19f49436e1c48c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107929 Tested-by: Jenkins Reviewed-by: Eike Rathke <er...@redhat.com> Change-Id: I98cc25267e7a10c34179bab50d19f49436e1c48c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107931 Tested-by: Jenkins Reviewed-by: Eike Rathke <er...@redhat.com> diff --git a/include/sal/mathconf.h b/include/sal/mathconf.h index 687f6e3da133..11bd32c35de0 100644 --- a/include/sal/mathconf.h +++ b/include/sal/mathconf.h @@ -104,6 +104,13 @@ union sal_math_Double unsigned msw :32; unsigned lsw :32; } w32_parts; + struct + { + sal_uInt64 sign : 1; + sal_uInt64 exponent :11; + sal_uInt64 fraction :52; + } parts; + sal_uInt64 intrep; double value; }; @@ -130,6 +137,13 @@ union sal_math_Double unsigned lsw :32; unsigned msw :32; } w32_parts; + struct + { + sal_uInt64 fraction :52; + sal_uInt64 exponent :11; + sal_uInt64 sign : 1; + } parts; + sal_uInt64 intrep; double value; }; diff --git a/sal/rtl/math.cxx b/sal/rtl/math.cxx index 46a3e925b95b..a85c8ac6e959 100644 --- a/sal/rtl/math.cxx +++ b/sal/rtl/math.cxx @@ -1167,9 +1167,10 @@ double SAL_CALL rtl_math_round(double fValue, int nDecPlaces, // Determine how many decimals are representable in the precision. // Anything greater 2^52 and 0.0 was already ruled out above. // Theoretically 0.5, 0.25, 0.125, 0.0625, 0.03125, ... - const double fDec = 52 - log2(fValue) + 1; - if (fDec < nDecPlaces) - nDecPlaces = static_cast<sal_Int32>(fDec); + const sal_math_Double* pd = reinterpret_cast<const sal_math_Double*>(&fValue); + const sal_Int32 nDec = 52 - (pd->parts.exponent - 1023); + if (nDec < nDecPlaces) + nDecPlaces = nDec; } /* TODO: this was without the inverse factor and determining max @@ -1190,75 +1191,81 @@ double SAL_CALL rtl_math_round(double fValue, int nDecPlaces, fValue *= fFac; } - switch ( eMode ) + // Round only if not already in distance precision gaps of integers, where + // for [2^52,2^53) adding 0.5 would even yield the next representable + // integer. + if (fValue < (static_cast<sal_Int64>(1) << 52)) { - case rtl_math_RoundingMode_Corrected : - fValue = rtl::math::approxFloor(fValue + 0.5); - break; - case rtl_math_RoundingMode_Down: - fValue = rtl::math::approxFloor(fValue); - break; - case rtl_math_RoundingMode_Up: - fValue = rtl::math::approxCeil(fValue); - break; - case rtl_math_RoundingMode_Floor: - fValue = bSign ? rtl::math::approxCeil(fValue) - : rtl::math::approxFloor( fValue ); - break; - case rtl_math_RoundingMode_Ceiling: - fValue = bSign ? rtl::math::approxFloor(fValue) - : rtl::math::approxCeil(fValue); - break; - case rtl_math_RoundingMode_HalfDown : - { - double f = floor(fValue); - fValue = ((fValue - f) <= 0.5) ? f : ceil(fValue); - } - break; - case rtl_math_RoundingMode_HalfUp: + switch ( eMode ) { - double f = floor(fValue); - fValue = ((fValue - f) < 0.5) ? f : ceil(fValue); - } - break; - case rtl_math_RoundingMode_HalfEven: + case rtl_math_RoundingMode_Corrected : + fValue = rtl::math::approxFloor(fValue + 0.5); + break; + case rtl_math_RoundingMode_Down: + fValue = rtl::math::approxFloor(fValue); + break; + case rtl_math_RoundingMode_Up: + fValue = rtl::math::approxCeil(fValue); + break; + case rtl_math_RoundingMode_Floor: + fValue = bSign ? rtl::math::approxCeil(fValue) + : rtl::math::approxFloor( fValue ); + break; + case rtl_math_RoundingMode_Ceiling: + fValue = bSign ? rtl::math::approxFloor(fValue) + : rtl::math::approxCeil(fValue); + break; + case rtl_math_RoundingMode_HalfDown : + { + double f = floor(fValue); + fValue = ((fValue - f) <= 0.5) ? f : ceil(fValue); + } + break; + case rtl_math_RoundingMode_HalfUp: + { + double f = floor(fValue); + fValue = ((fValue - f) < 0.5) ? f : ceil(fValue); + } + break; + case rtl_math_RoundingMode_HalfEven: #if defined FLT_ROUNDS -/* - Use fast version. FLT_ROUNDS may be defined to a function by some compilers! - - DBL_EPSILON is the smallest fractional number which can be represented, - its reciprocal is therefore the smallest number that cannot have a - fractional part. Once you add this reciprocal to `x', its fractional part - is stripped off. Simply subtracting the reciprocal back out returns `x' - without its fractional component. - Simple, clever, and elegant - thanks to Ross Cottrell, the original author, - who placed it into public domain. - - volatile: prevent compiler from being too smart -*/ - if (FLT_ROUNDS == 1) - { - volatile double x = fValue + 1.0 / DBL_EPSILON; - fValue = x - 1.0 / DBL_EPSILON; - } - else -#endif // FLT_ROUNDS - { - double f = floor(fValue); - if ((fValue - f) != 0.5) + /* + Use fast version. FLT_ROUNDS may be defined to a function by some compilers! + + DBL_EPSILON is the smallest fractional number which can be represented, + its reciprocal is therefore the smallest number that cannot have a + fractional part. Once you add this reciprocal to `x', its fractional part + is stripped off. Simply subtracting the reciprocal back out returns `x' + without its fractional component. + Simple, clever, and elegant - thanks to Ross Cottrell, the original author, + who placed it into public domain. + + volatile: prevent compiler from being too smart + */ + if (FLT_ROUNDS == 1) { - fValue = floor( fValue + 0.5 ); + volatile double x = fValue + 1.0 / DBL_EPSILON; + fValue = x - 1.0 / DBL_EPSILON; } else +#endif // FLT_ROUNDS { - double g = f / 2.0; - fValue = (g == floor( g )) ? f : (f + 1.0); + double f = floor(fValue); + if ((fValue - f) != 0.5) + { + fValue = floor( fValue + 0.5 ); + } + else + { + double g = f / 2.0; + fValue = (g == floor( g )) ? f : (f + 1.0); + } } - } - break; - default: - OSL_ASSERT(false); - break; + break; + default: + OSL_ASSERT(false); + break; + } } if (nDecPlaces != 0) _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits