表:
var1 | var2
-----+------
0.5 | 19.99
var1 和 var2 是双精度类型
我知道,保存的值可能是 19.9900000000000000000000000001 或 19.989999999999999999999999999999999 (或 0.5 不准确),但如何获得正确的值(如果小数部分恰好是 0.5,则正数向上舍入,向下舍入)对于负数。-其中来自轮定义):
SELECT var1, var2, round(var1*var2,2), round(0.5*19.99,2), round(9.995,2) FROM table
退货
var1 | var2 | this should be 10 | this is 10 | this is also 10
| | round(var1*var2,2)| round(0.5*19.99,2) | round(9.995,2)
-----+-------+-------------------+--------------------+-----------------
0.5 | 19.99 | 9.99 | 10 | 10
我尝试了 round(round(var1,2)*round(var2,2)) 但没有任何改变
像
0.5
和 19.99
这样的文字分别是 NUMERIC(18, 1)
和 NUMERIC(18, 2)
。文字 0.5 * 19.99
是一个 NUMERIC(18, 3)
,这意味着结果值恰好是 9.995,四舍五入到小数点后 2 位时,NUMERIC(18, 3)
值将是 10.000。
另一方面,对双精度值的相同操作并不精确。例如:
select
val1 * val2,
cast(val1 * val2 as varchar(100)),
round(val1 * val2, 2),
round(val1 * val2, 3),
round(round(val1 * val2, 3), 2),
round(val1 * val2 + 1e-10, 2)
from (
select
cast(0.5 as double precision) as val1,
cast(19.99 as double precision) as val2
from rdb$database) a
将分别产生(以火罗宾):
9.995000 9.994999999999999 9.990000 9.995000 10.000000 10.000000
第一列 9.995000 是由 Flamerobin 渲染的结果,最多保留 6 位小数(如第二列所示)。
这也可能暗示了一个解决方案:首先四舍五入到更高的小数位数,然后更低,或者添加一个小分数,如
1e-10
,但这仍然可能会产生与其他值不正确的舍入。
将结果转换为定点小数也是如此:您可能会在某处引入舍入误差。
目前的解决方案:
SELECT ROUND(CAST(var1 AS DECIMAL(9,2))*CAST(var2 AS DECIMAL(9,2)),2) FROM table
但也许有人有更好的解决方案
我认为这是最好的解决方案
SELECT round(round(val1 * val2, 3), 2) FROM table