Issue 86775 - INT function gives an unexpected result due to too much precision
Summary: INT function gives an unexpected result due to too much precision
Status: CLOSED FIXED
Alias: None
Product: Calc
Classification: Application
Component: code (show other issues)
Version: DEV300m1
Hardware: All All
: P3 Trivial (vote)
Target Milestone: ---
Assignee: oc
QA Contact: issues@sc
URL: https://bugzilla.novell.com/show_bug....
Keywords:
Depends on:
Blocks:
 
Reported: 2008-03-06 17:57 UTC by kyoshida
Modified: 2013-08-07 15:15 UTC (History)
2 users (show)

See Also:
Issue Type: PATCH
Latest Confirmation in: ---
Developer Difficulty: ---


Attachments
test file that demonstrates the problem. (7.00 KB, application/vnd.oasis.opendocument.spreadsheet)
2008-03-06 17:59 UTC, kyoshida
no flags Details
proposed patch (634 bytes, patch)
2008-03-06 18:09 UTC, kyoshida
no flags Details | Diff
better patch - reduce precision only when the value is less than 1.0E10 (817 bytes, patch)
2008-03-06 18:44 UTC, kyoshida
no flags Details | Diff
test file to make sure the patch has not caused (obvious) regressions (11.08 KB, application/vnd.oasis.opendocument.spreadsheet)
2008-03-06 18:48 UTC, kyoshida
no flags Details
revised (probably final) patch (553 bytes, patch)
2008-03-24 23:34 UTC, kyoshida
no flags Details | Diff
revised patch.. the previous patch is no good. (3.02 KB, patch)
2008-03-25 01:55 UTC, kyoshida
no flags Details | Diff
test file (13.61 KB, application/vnd.oasis.opendocument.spreadsheet)
2008-03-25 01:57 UTC, kyoshida
no flags Details

Note You need to log in before you can comment on or make changes to this issue.
Description kyoshida 2008-03-06 17:57:14 UTC
The built-in INT function returns an unexpected result due to binary float-point
rounding error when the value passed is very close to an integer.  I'll attach
an example file shortly.
Comment 1 kyoshida 2008-03-06 17:59:26 UTC
Created attachment 51945 [details]
test file that demonstrates the problem.
Comment 2 kyoshida 2008-03-06 18:03:26 UTC
The first value (B1) returns 0.0 because the value being pushed to INT there is
0.999999999999999555910790, while the second value (B2) returns 1.0 because the
pushed value is 1.000000000000000444089210.

To minimize this problem, I propose reducing the precision to single-precision
before flooring the value.  It will not solve the fundamental problem entirely,
but at least it will minimize the damage.
Comment 3 kyoshida 2008-03-06 18:09:22 UTC
Created attachment 51946 [details]
proposed patch
Comment 4 kyoshida 2008-03-06 18:14:23 UTC
The patch isn't all that much.  Basically it reduces the double value to float,
back to double then floors it.  That's all.
Comment 5 kyoshida 2008-03-06 18:44:13 UTC
Created attachment 51948 [details]
better patch - reduce precision only when the value is less than 1.0E10
Comment 6 kyoshida 2008-03-06 18:48:11 UTC
Created attachment 51949 [details]
test file to make sure the patch has not caused (obvious) regressions
Comment 7 kyoshida 2008-03-06 22:24:34 UTC
Actually let's hold off on this.  Reducing the precision will cause other weird
problems down the road.
Comment 8 kyoshida 2008-03-06 22:25:05 UTC
Meanwhile I'll just assign this to myself.
Comment 9 kyoshida 2008-03-24 23:34:15 UTC
Created attachment 52270 [details]
revised (probably final) patch
Comment 10 kyoshida 2008-03-24 23:35:28 UTC
downstream issue: https://bugzilla.novell.com/show_bug.cgi?id=310706
Comment 11 kyoshida 2008-03-24 23:39:10 UTC
@er: could you take a quick look at this patch and give me an approval?  Thanks!
Comment 12 kyoshida 2008-03-25 01:55:54 UTC
Created attachment 52272 [details]
revised patch..  the previous patch is no good.
Comment 13 kyoshida 2008-03-25 01:57:17 UTC
Created attachment 52273 [details]
test file
Comment 14 kyoshida 2008-03-25 01:59:42 UTC
In the test file, the red cells show values that were previously mis-calculated
prior to applying this patch.
Comment 15 rail_ooo 2008-03-28 10:19:17 UTC
Kohei:
Seems like .Net 2003 doesn't like "round":

e:/build\2.4.0\src.pro\OOH680_m12\sc\source\core\tool\interpr1.cxx(109) : error

C3861: 'round': identifier not found, even with argument-dependent lookup

Please have a look.
Comment 16 ooo 2008-03-29 15:03:02 UTC
Hi Kohei,

Nice patch. Some small nitpick ;-)  instead of

if (::rtl::math::isNan(fValue) || ::rtl::math::isInf(fValue) ||
        fValue == HUGE_VAL || fValue == 0.0)

please use

if (!::rtl::math::isFinite(fValue) || fValue == 0.0 || fValue == HUGE_VAL)

isFinite() checks for both, NAN and INF, using the platform dependent
SAL_MATH_FINITE(), and internally isNan() and and isInf() use the same but do
extra work to determine whether it's a NAN or INF then, which is unnecessary here.

For the round() we may use ::rtl::math::round() instead, that also allows
control over the rounding mode, compiler libraries maybe differ in their
internal implementation of round().

I think we might use floor(approxValue()) also in other places where up to now
we use approxFloor(), what do you think? If so, we could add that as
::rtl::math::approxValue() and maybe should simply change the
::rtl::math::approxFloor() and ::rtl::math::approxCeil() methods to use that,
and then would get rid of their threshhold behavior as well. Just a quick idea,
could you imagine any negative side effect when doing so?

Thanks
  Eike
Comment 17 kyoshida 2008-03-31 14:30:09 UTC
Hi Eike,

>could you imagine any negative side effect when doing so?

Not off hand.  I too think it's a good idea to call approxValue from within
approxFloor() and approxCeil().  I can't think of any negatives since all the
approx*() functions already truncate digits below 15 anyway.

I'll change my patch to reflect this.  I'll attach a new one when it's ready.

Kohei
Comment 18 ooo 2008-05-08 15:28:21 UTC
In cws odff03:

sal/inc/rtl/math.h  1.3.380.1
sal/inc/rtl/math.hxx  1.6.380.1
sal/rtl/source/math.cxx  1.12.236.1
sal/util/sal.map  1.62.46.1

The patch needed some tweaking for values near DBL_MIN and DBL_MAX to not
produce #NUM! errors.

Added rtl_math_approxValue() and ::rtl::math::approxValue() wrapper; modified
::rtl::math::approxFloor() and ::rtl::math::approxCeil() to use
::rtl::math::approxValue(), hence no changes necessary in Calc code. Au
contraire, also the FLOOR() and CEILING() spreadsheet functions and others using
approxFloor()/approxCeil() internally actually benefit from this change because
the dreaded 3.55271e-015 threshold value is gone now.
Comment 19 kyoshida 2008-05-08 15:53:14 UTC
Ah, nice!  Sorry I couldn't get to this soon enough.

I have one question out of my ignorance.  What is the sal.map file used for ? 
It looks like a symbol map for the exported symbols in the shared library, but
is it used for all compilers or ... ?  When do we need to modify this ?
Comment 20 ooo 2008-05-09 18:06:08 UTC
Reassigning to QA for verification.
Comment 21 ooo 2008-05-29 13:41:35 UTC
@kohei:
Just returned from vacation, hence the long silence..

> What is the sal.map file used for ? It looks like a symbol map for the
> exported symbols in the shared library,

Exactly. All URE libraries use those map files, also each UNO
component's library to export the few methods necessary for registry
purposes. A few other libs that did not depend on the now removed SUPD
numbering also use it.

> but is it used for all compilers or ... ? 

Yes, used for all compilers. Platform specifics are handled in the
tooling processing those files. It also provides a versioning mechanism.
For details see
http://udk.openoffice.org/common/man/libraryversioning.html
Maybe a bit old, but basics didn't change.

> When do we need to modify this ?

Whenever you add a symbol that is to be exported ;-)
Comment 22 kyoshida 2008-05-30 15:58:06 UTC
@er: ah thanks!  I hope you enjoyed your vacation.  Everyone needs a break every
now and then. :-)
Comment 23 oc 2008-06-04 13:55:54 UTC
verified in internal build cws_odff3
Comment 24 oc 2008-10-17 10:34:02 UTC
closed because fix available in builds OOO300_m9 and DEV300_m33