处理小数精度

时间:2015-04-23 15:57:22

标签: mysql sql oracle casting

我们有许多字段定义为数字(38,20) - 因为数据传输到具有该比例/精度的ORACLE数据库。

执行计算时,舍入往往发生在12到14位小数之间(取决于)。我测试了浮点/小数的各种组合,希望保持精度并存储回数字(38,20)

e.g。

在这里输入代码

declare @dtest20 decimal(38,20) = cast( 1.44444444441234567892 as decimal(38, 20))
declare @ftest20 float = cast( 1.44444444441234567892 as float) 
declare @f100 float = cast( 100.0 as float ) 
declare @d100 decimal(38,20) = cast( 100.0 as decimal(38,20))

select @dtest20 * @d100 as 'dtest20 x d100'
, cast( @dtest20 * @d100 as decimal(38,20)) as 'dtest20 x d100' 
, @ftest20 * @f100 as 'ftest20 x f100' 
, cast( @ftest20 * @f100 as decimal(38,20)) as 'ftest20 x f100' 

dtest20 x d100 dtest20 x d100 ftest20 x f100 ftest20 x f100 144.444444 144.44444400000000000000 144.444444441235 144.44444444123457000000

我知道这确实是一个MS-SQL的东西,但有没有任何解决/建议对大精度数进行计算并避免无意的舍入?

谢谢!

1 个答案:

答案 0 :(得分:1)

必须遵守的规则:对所有值使用精确数字数据类型。不要超过你的精度和规模。 (PostgreSQL语法如下。)

select cast( 1.44444444441234567892 as decimal(38, 20)) as cast_decimal;
cast_decimal
numeric(38,20)
--
1.44444444441234567892

我机器上的双精度浮点数只有大约15个十进制数字的精度。在下面的情况中,我们给出的值将不适合。 dbms返回最接近的浮点值。

select cast( 1.44444444441234567892 as float) as cast_float;
cast_float
double precision
--
1.44444444441235

将小数乘以整数会返回小数。因此,在乘法中混合使用十进制和整数数据类型会产生令人惊讶的结果。这就是我们想要的 - 不足为奇的结果。

select cast( 1.44444444441234567892 as decimal(38, 20)) * 100 as dec_x_int;
dec_x_int
numeric
--
144.44444444123456789200

将小数除以整数会产生令人惊讶的结果。但是这个分区丢失了一个数字,因为实际结果中的数字位数超过20.这不应该是一个惊喜。

select cast( 1.44444444441234567892 as decimal(38, 20)) / 100 as dec_div_int;
dec_div_int
numeric
--
0.01444444444412345679

乘以小数点浮点数会返回实现定义的近似数字。 (见下文。)我们因不遵守必须遵守的规则而失去了精确度。

select cast( 1.44444444441234567892 as numeric(38,20)) * 100::float as dec_x_flt;
dec_x_flt
double precision
--
144.444444441235

SQL标准

SQL标准将精确数字与近似数字区分开来。最低有效数字(舍入,截断)的结果是实现定义的。乘法和除法结果的精度是实现定义的。

将精确数字与表达式中的近似数字混合将返回实现定义的近似数字。因此,将一个十进制与一个浮点数混合,然后你得到一个浮点数或一个双精度数。