我们有许多字段定义为数字(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的东西,但有没有任何解决/建议对大精度数进行计算并避免无意的舍入?
谢谢!
答案 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标准将精确数字与近似数字区分开来。最低有效数字(舍入,截断)的结果是实现定义的。乘法和除法结果的精度是实现定义的。
将精确数字与表达式中的近似数字混合将返回实现定义的近似数字。因此,将一个十进制与一个浮点数混合,然后你得到一个浮点数或一个双精度数。