diff options
author | Po-Yen Huang <jeff.huang@ossii.com.tw> | 2023-11-07 13:01:27 +0800 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2024-02-27 11:00:24 +0100 |
commit | 9adffb1c7453aee77f9d52b1ed0aa99191a9c317 (patch) | |
tree | d25deb0cae2c509e09e9caf4a59eb405de6e6a45 /sal | |
parent | 8f7d4f1da306fc7e104050c96ae1538c3f04c52f (diff) |
tdf#158190 Fix Calc ROUND in floating-point calculate result very close to X.5
Location:
if (nDecPlaces == 0)
{
switch (eMode)
{
case rtl_math_RoundingMode_Corrected:
return std::round(fValue);
Because the functions are the same as the following
related codes, they are respectively:
if (nDecPlaces >= 0
&& (fValue >= 0x1p52
|| isRepresentableInteger(fValue)))
return fOrigValue;
as well as:
if (fValue < 0x1p52)
{
switch(eMode)
{
case rtl_math_RoundingMode_Corrected:
fValue = rtl::math::approxFloor(fValue + 0.5);
break;
:
:
:
Because some double-precision floating point
numbers cause std::round(fValue) and rtl::math::approxFloor(fValue + 0.5)
to produce different results.
For example, enter 10614.4999999999876 in Calc's
A1 cell (or any operation that will produce a long
decimal number such as .499999999999xyz after the
decimal point).
We expected it to be 10614.4999999999876, but it
was automatically rounded to 10614.5 (note: this
result is also the result of ubiquitous handheld
computers, OpenOffice.org and Excel)
Then, entering =ROUND(A1,0) in B1, we will see 10614,
A1 and B1 clearly don't meet expectations. (My boss
or tax collector might be unhappy :-p)
Although A1's 10614.4999999999876 is still faithfully
recorded, the rendering of 10614.5 is confusing.
Now, there are two views:
1. According to the established convention, B2
displays the expected answer 10615.
or
2. True to the laws of mathematics, A1 displays
10614.4999999999876 or at least 10614.49
Although the second point of view is correct (and I
completely agree with it), when opening
spreadsheets generated by other software (such as
OpenOffice.org or Excel), the results will be different,
which people do not like to see.
So when nDecPlaces == 0 is removed, use
std::round(fValue) and let the existing code below it do the rounding:
if (fValue < 0x1p52)
{
switch(eMode)
{
case rtl_math_RoundingMode_Corrected:
fValue = rtl::math::approxFloor(fValue + 0.5);
This is consistent with the first point.
By the way, in nDecPlaces == 0
case rtl_math_RoundingMode_HalfEven:
This piece of code can be checked to see if it is really
necessary, because rtl_math_round() also has the same purpose code.
If it is not needed, the entire nDecPlaces == 0 can be removed.
Co-authored-by: Firefly <firefly@ossii.com.tw>
Co-authored-by: Franklin Weng <franklin@goodhorse.idv.tw>
Change-Id: If32cdb18c70ec0025c83ba25a99e5d135d66aec9
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/159193
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
Diffstat (limited to 'sal')
-rw-r--r-- | sal/qa/rtl/math/test-rtl-math.cxx | 4 | ||||
-rw-r--r-- | sal/rtl/math.cxx | 2 |
2 files changed, 4 insertions, 2 deletions
diff --git a/sal/qa/rtl/math/test-rtl-math.cxx b/sal/qa/rtl/math/test-rtl-math.cxx index bab2774a414c..a5ce3b4e6262 100644 --- a/sal/qa/rtl/math/test-rtl-math.cxx +++ b/sal/qa/rtl/math/test-rtl-math.cxx @@ -301,6 +301,10 @@ public: fVal = 4503599627370491.0; CPPUNIT_ASSERT_EQUAL( 4503599627370000.0, rtl::math::round( fVal, -3, rtl_math_RoundingMode_Corrected)); + + // test #tdf158190: ROUND(16.83 * 650, 0) + fVal = 16.83; + CPPUNIT_ASSERT_EQUAL( 10940.0, rtl::math::round( fVal * 650, 0, rtl_math_RoundingMode_Corrected)); } void test_doubleToString() { diff --git a/sal/rtl/math.cxx b/sal/rtl/math.cxx index 68068eaf979f..75cada0b7d48 100644 --- a/sal/rtl/math.cxx +++ b/sal/rtl/math.cxx @@ -463,8 +463,6 @@ double SAL_CALL rtl_math_round(double fValue, int nDecPlaces, enum rtl_math_Roun { switch (eMode) { - case rtl_math_RoundingMode_Corrected: - return std::round(fValue); case rtl_math_RoundingMode_HalfEven: if (const int oldMode = std::fegetround(); std::fesetround(FE_TONEAREST) == 0) { |