I think Dmitry is exactly right, it looks like there is a problem
with intermediate calculations where the representation digits
are being used during rounding
I consider this a pretty serious bug. Surprised this has been
around for what seems to be forever
The problem also exists for FLOAT
(Sorry for the long winded email, but want to document this so it is in
an email for now)
(Testing with FB 3.10 on Win 64 only)
Double precision is supposed to be accurate to 15 significant digits.
If I read this right it actually is that if you convert to/from a string
you
will get the same number up to 15 or 16 digits
(
https://en.wikipedia.org/wiki/Double-precision_floating-point_format)
A very simple example is 4.015
The closes representation is
4.01499999999999968025576890795E0
(
https://www.binaryconvert.com/result_double.html?decimal=052046048049053)
The Firebird algorithm is apparently doing the rounding using the
'closest representation' digits?
That is, getting all the digits of the closes representation and
truncating to + 1 then rounding,
so round(4.015, 2) is doing this:
4.01499999999999968025576890795
->4.014
->4.01
This seems to be supported by doing this instead, which rounds as expected,
though I don't know that it would be correct in all cases:
round(round(4.015,3),2):
4.01499999999999968025576890795
->4.0149
->4.015
->4.02
FLOAT does not work either
select
'Double'
, cast( 4.015 as DOUBLE PRECISION) num
,round( cast( 4.015 as DOUBLE PRECISION), 2) rnd2 -- nope
,round(round(cast( 4.015 as DOUBLE PRECISION), 3),2) rnd32 -- yes
, cast( 4.015 as DOUBLE PRECISION) * 100 num100
,round( cast( 4.015 as DOUBLE PRECISION) * 100,0) rnd100 -- nope
from RDB$DATABASE
union ALL
select
'Float'
, cast( 4.015 as FLOAT) num
,round( cast( 4.015 as FLOAT), 2) rnd2 -- nope
,round(round(cast( 4.015 as FLOAT), 3),2) rnd32 -- yes
, cast( 4.015 as FLOAT) * 100 num100
,round( cast( 4.015 as FLOAT) * 100,0) rnd100 -- nope
from RDB$DATABASE;
FlameRobin:
CONSTANT NUM RND2 RND32
NUM100 RND100
======== ======================= =======================
======================= ======================= =======================
Double 4.015000000000000 4.010000000000000
4.020000000000000 401.499999999999943 401.000000000000000
Float 4.014999866485596 4.010000000000000
4.020000000000000 401.499986648559570 401.000000000000000
iSql:
CONSTANT NUM RND2 RND32
NUM100 RND100
======== ======================= =======================
======================= ======================= =======================
Double 4.015000000000000 4.010000000000000
4.020000000000000 401.4999999999999 401.0000000000000
Float 4.014999866485596 4.010000000000000
4.020000000000000 401.4999866485596 401.0000000000000
ROUND is broken for double precision and FLOAT.
Should either be fixed, or doc and code should be change to remove double as
accepted data type for ROUND