浮点、实数和小数数据类型的回顾
Posted
技术标签:
【中文标题】浮点、实数和小数数据类型的回顾【英文标题】:Retrospection on Float, Real and Decimal data types 【发布时间】:2015-08-12 11:42:43 【问题描述】:在我的场景中,我试图了解在数据库(Sql Server)表中具有 real 数据类型的列的影响。我的数据库中有一个具有 real 数据类型的列。 数据是静态的,它始终是 0.0、0.1、0.2.. 到 1.0 范围内的值之一。
用例: 我必须总结列中的值并在一些包括财务数据的算术计算中使用总和值。
担心? 当我对列中的值求和时,它会给我更多小数位的结果。
测试:
我想对列值求和,并将其用于乘除计算。
我想对具有十进制和浮点数据类型的列中的同一组值重复 #1。
过程:我创建了三个不同的表,其中包含一个列和一组相同的值,但数据类型不同,一个是小数、浮点数和实数。并对它们中的每一个进行算术计算。
CREATE TABLE #tReal(d real);
INSERT INTO #tReal
SELECT 0.1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1;
select SUM(d) from #tReal
预期结果:5.9
实际结果: 5.8999999538064
而且,如果我对总和执行四舍五入运算,结果符合预期
declare @sumofd real
select @sumofd = SUM(d) from #tReal
select round(@sumofd , 1)
结果:5.9
另外,如果我将数据类型从 real 更新为 float
CREATE TABLE #tfloat(d float);
INSERT INTO #tfloat
SELECT 0.1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1;
select SUM(d) from #tfloat
预期结果:5.9
实际结果: 5.9
而且,如果我将数据类型从 real 更新为 decimal
,情况也是如此CREATE TABLE #tDecimal(d DECIMAL(3,2));
INSERT INTO #tDecimal
SELECT 0.1 UNION ALL
SELECT 1 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1 UNION ALL
SELECT 0.9 UNION ALL
SELECT 1;
select SUM(d) from #tDecimal
预期结果:5.94
实际结果: 5.94
而且,如果我对总和执行一些基本的算术运算,而不进行四舍五入,比如
declare @sumofdReal real
declare @sumofdFloat float
declare @sumofdDecimal decimal(3,2)
select @sumofdReal = SUM(d) from #tReal
select @sumofdFloat = SUM(d) from #tfloat
select @sumofdDecimal = SUM(d) from #tDecimal
乘法:
select @sumofdReal * 2
Result: 11.8
select @sumofdFloat * 2
Result: 11.8
select @sumofdDecimal * 2
Result: 11.88
部门:
select @sumofdReal / 2
Result: 2.95
select @sumofdFloat / 2
Result: 2.95
select @sumofdDecimal / 2
Result: 2.97000
删除表:
drop table #tReal
drop table #tfloat
drop table #tDecimal
以下是我的问题
-
在我的场景中,将数据类型设为真实会产生任何影响吗?
如果#1 是肯定的,会有什么样的影响?我是否必须将数据类型更改为浮点数或小数?为什么?
如果 #1 为否,为什么?请解释一下?
float 和 real 类型是否可以产生精确的结果,除此之外的任何舍入错误都会出现?
【问题讨论】:
小数部分的示例中是否有错误 - 为什么您的预期结果是 5.9?您的最后一个值为 0.944。 为什么你期望从小数计算中得到 5.9,一个小数(3,2)的精度是小数点后 2 位。 @Paddy 这是一个错字。更新为适当的值。 您的十进制示例完全错误:sqlfiddle.com/#!3/579e3. @Mady,由于您的编辑,您的总和不再累加。 【参考方案1】:SQL Server 中的real
是float(24)
的同义词,它占用4 个字节和最多7 位的精度。
float
本身与float(53)
相同,double
也相同,占用 8 个字节,精度高达 15 位。
在我的场景中,将数据类型设为 real 会产生什么影响?
可能。 decimal
、float
和 real
have different characteristics and are not fully interchangeable。如果要保持精确的十进制表示,请使用具有适当比例和精度的 decimal
数据类型。如果您的数字代表不精确的数据(例如温度、高度、时间或其他“自然”测量值,如果不精确就无法测量)并且想要更快的数学运算,请使用float
(或real
,如果您不需要;超过 7 位的精度。
当我对列中的值求和时,它会给我更多小数位的结果。
当您添加浮点数时,SQL 会确定结果的大小并将使用适当的数据类型。当您添加两个reals
时,结果可能具有超过7 位的精度,因此它可能使用float
作为结果数据类型。
我是否必须将数据类型更改为浮点数或小数?为什么?
如果您的精度可能超过 7 位,不需要从十进制的角度来看绝对精度,并且希望使用浮点类型来加快计算速度,请使用 float
。
如果您想要一个固定的比例和精度,并希望最大限度地减少浮点数所涉及的不精确性,请使用decimal
。
【讨论】:
【参考方案2】:使用浮点值总是会产生影响,因为它们没有被精确地表示,并且总是会出现一些舍入错误。在将值与常量进行比较时,您必须非常小心,例如if (a == 0.0) 因为如果 'a' 是数学运算的结果,这并不总是有效。 Float 和 Decimal 只是为您提供不同的范围和精度。
【讨论】:
【参考方案3】:如果您在财务计算中使用这些值,那么您应该始终(几乎)使用小数类型,否则您会在某些时候遇到浮点舍入问题。当你开始失去便士时,人们会非常伤心。
您可能想在此处阅读更多关于浮点运算的内容:
http://floating-point-gui.de/
十进制类型不受这些限制,应该是精确的。
例如,您最终会遇到尝试将数字四舍五入为 2 DP 的情况,例如0.695,您希望四舍五入到 0.70。
DECLARE @x REAL = 0.695
SELECT ROUND(@x, 2)
-- outputs 0.69
DECLARE @y DECIMAL(6,4) = 0.695
SELECT ROUND(@y, 2)
-- outputs 0.7000
这是因为您无法将 0.695 准确地表示为浮点数,而实际上它在保存时略小于 0.695。
【讨论】:
那正是我想通过一个例子来理解它,因为我之前读过这个理论。如果您查看所有三个的乘法计算结果是相似的。除法计算有一些变化不知道为什么? float 和 real 类型是否可以产生精确的结果,除此之外的任何舍入错误都会出现? 不,它总是作为潜在问题存在。在您的示例中,您包含数字 0.1 - 这并不完全表示为浮点数(请参见此处:exploringbinary.com/…)。在某些时候,根据您的计算,您会发现这些小增量会影响您的预期输出。以上是关于浮点、实数和小数数据类型的回顾的主要内容,如果未能解决你的问题,请参考以下文章