Firebird truncates decimal places when dividing, rather than rounding. Furthermore, it bases the number of decimal points in the returned value on the number of decimal places in the numerator and denominator.
Why is Firebird truncating instead of rounding? And why does it base the returned value on the number of decimal places in the query?
Firebird 2.5:
select 187/60.00 from rdb$database; --result: 3.11
select 187.000/60 from rdb$database; --result: 3.116
select 187.000/60.00 from rdb$database --result: 3.11666
SQL Server 2012:
select 187/60.00; --result: 3.116666
Oracle 11gR2:
select 187/60.00 from dual; --result: 3.116666666667
MySQL 5.5.32:
select 187/60.00 from dual; --result: 3.1167
PostgreSQL 9.3.1:
select 187/60.00; --result: 3.116666666667
SQLite:
select 187/60.00; --result: 3.1166666666666667
In Firebird literals with a decimal point are of type
NUMERIC
, notDOUBLE PRECISION
(or another floating point type). This means it will apply its exact numeric calculation rules.So with
select 187/60.00 from rdb$database
this means that 187 is anINTEGER
and 60.00 is aNUMERIC(18,2)
.The rules for exact numeric calculation can be found in "Exact Numerics - Functional Specification":
When one of the operands is an integral type, it is considered as a numeric with scale 0. So in this case you have
NUMERIC(18,0)/NUMERIC(18,2)
and based on the above rules, the result isNUMERIC(18, 0+2) = NUMERIC(18,2)
.The fact that the number appears to be truncated is a result of the application of exact numeric calculation: the calculation stops once the last digit has been calculated. The fact that there is a remainder has no bearing on the result of the calculation:
Looking at the SQL:2011 Foundation specification the fact Firebird considers
60.00
to be a exact numeric is correct, as it has the following production rules for literals in section 5.3 <literal>:And syntax rules:
Section 6.27 <numeric value expression> specifies the following syntax rules:
In other words the behavior of Firebird complies with the SQL standard. By the looks of it most of the other database you tried (with the possible exception of SQL Server), either use a relatively large value for the scale when performing division, or seem to use the approximate numeric (aka double precision) behavior.
A workaround would be to use an approximate numeric literal. Use of exponent zero or
E0
will make the number a double precision without additional powers of ten. For example: