使用Float或Real数据类型的危险

SQL Prompt根据数据库的对象名称、语法和代码片断自动进行检索,为用户提供合适的代码选择。自动脚本设置使代码简单易读--当开发者不大熟悉脚本时尤为有用。SQL Prompt安装便可使用,能大幅提升编码效率。本文介绍了使用Float或Real数据类型的危险。程序员

浮点数据类型可容纳很是大的数字,可是缺乏了精度。它们对于某些类型的科学计算很方便,可是在更普遍地使用时很危险,由于它们会引入较大的舍入偏差。算法

浮点运算就是为了不计算中的溢出错误而容忍和管理近似。在现实世界中,咱们一般关心数字的准确性,而会牺牲空间和资源以免溢出。数据库

科学是在偏差范围内工做的,而精确在商业会计中相当重要。当我仍是一名初级程序员时,我曾经写过一种我认为是银行计算交易利润很是合适的方法。在一百万英镑中,最多也就一两便士的偏差,我很满意。它使用了咱们当时用来开发财务软件包的PL / 1编译器中固有的计算。我向他们展现了精心制做的应用程序,他们感到震惊。冷酷无情的银行家们绝不留情地表示一百万英镑没了几分钱。他们不会接受的。我被迫用精确的汇编代码编写一个精确的二进制编码的十进制(BCD)程序包。框架

SQL Prompt具备代码分析规则(BP023),该规则将提醒您使用Float或Real数据类型,这是由于它们可能会引入许多组织一般在其SQL Server数据上常规执行的那种计算方式。ide

SQL Prompt使用教程:使用Float或Real数据类型的危险

近似数的数据类型函数

浮点运算是在优先考虑节省内存的同时,提供了一种涉及大量运算的通用方法的时代设计出来的。尽管它对于许多类型的科学计算(尤为是那些符合浮点算术双精度IEEE 754标准的科学计算)仍然有用,但它必然是一种折衷方案。线索就是这种数据和算术的名称:“近似”。浮点数不能精确表示全部实数:此外,浮点运算不能精确表示全部算术运算。可是,即便不老是精确地保留数字,它们能够保留的数字的幅度范围也远大于其余数字类型。测试

使用浮点运算引发的问题是因为复杂计算过程当中的四舍五入而引发的,若是数据处于“不良条件”状态,则最多见的问题就是输入中的细微变化会在输出中放大。随着数字表示精度的提升,这种不精确性已经不那么明显了,可是它们仍然存在。在使用有效但不能用浮点数表示的数字时,还存在一些深奥的限制,例如tan(π/ 2),但这些可能仅会激发数学家的兴趣。编码

SQL Server浮点数据类型spa

SQL标准具备三个浮点,近似数据类型、REAL、DOUBLE PRECISION和FLOAT(n)。 SQL Server符合此要求,只是它没有DOUBLE PRECISION数据类型,而改用FLOAT(53)。 FLOAT(24)和FLOAT(53)数据类型对应于IEEE 754标准中的Binary32(Single)Binary64(double),并分别存储在4和8字节中,并分别保留7和16位数字。当计算产生与使用还使用IEEE 754的.NET框架的应用程序相同的结果很重要时,它们颇有用。当数字的大小超过DECIMAL数据类型所容许的最大值(38位)时,还须要双精度类型,但精度降低。固然,近似数不能可靠地用于任何相等性检验中,例如WHERE子句。设计

使用REAL数据类型的计算(单精度)

我将尝试REAL数据类型。FLOAT(24)数据类型或更小的数据类型以相同的方式反应。在SQL Server中使用浮点数进行实验时,要记住的第一件事是,SSMS以掩盖微小差别的方式呈现浮点数。例如:

SELECT Convert(REAL,0.100000001490116119384765625)

…获得0.1

为了更准确地看到浮点数中存储了什么值,您必须使用STR()函数,指定实际须要的精度。


SQL Prompt使用教程:使用Float或Real数据类型的危险

这已经使人担心。毕竟,咱们正在处理具备数百万行的数据,所以,除非像“银行家四舍五入”之类的结果取平均值,不然小错误就会堆积起来。这个错误已经接近我在引言中提到的“百万英镑的便士”(1/240000000)!

让咱们避免使用0.1,并将其归结为奇怪的浮点数。1除以3怎么样?这确定不是问题吧?


哎呀,它错了。好的,这是一个很小的错误,但请记住我关于银行家的故事。答案是对仍是错,穿着灰色西装的男人没有灰色阴影。在商学院,只有一个标记和一个叉。没有表示“足够近”的标志。

一个简单的测试是将数字1除以1到20。会出什么问题呢?

咱们能够存储浮点数和数值计算的结果,将它们都转换为字符串,而后比较字符串(请注意,字符串STR()能够放在前导空格中,这会使状况变得复杂)。


SQL Prompt使用教程:使用Float或Real数据类型的危险

如今,若是咱们列出那些数字不匹配的行呢?


SQL Prompt使用教程:使用Float或Real数据类型的危险

啊! 只有在除数为一、二、四、8或16的状况下,结果才正确。

若是您但愿某种程度上的浮点数是准确的,而数值版本却不正确,则如下是在Excel中计算出的数值商:

SQL Prompt使用教程:使用Float或Real数据类型的危险

使用FLOAT(25)或更高(双精度)的计算

若是使用双精度浮点数FLOAT(25)或更高的精度,则全部测试都将经过,由于STR()函数最多容许小数点右边16位。若是大于16,则结果将被截断。双精度数据类型具备16位数字,而单精度数据类型具备7位数字。您还将看到单精度数据类型正确获取了前七个数字。一样,双精度会正确获取前16位数字。咱们能够扩大数字以查看近似值。

DECLARE @FirstApproximate FLOAT(53) = 10000000000000000.1
SELECT Str(@FirstApproximate,40,16) AS BigNumberWithaDecimal

SQL Prompt使用教程:使用Float或Real数据类型的危险

那小部分消失了,不是吗?这可能只是微小的差别,可是在某些计算中,它可能会引发问题。

结论

浮点算法在存储上既快速又经济,但提供了近似的结果。它适用于条件良好的科学应用,但不适用于财务计算,由于财务计算要求数字是“正确”或“错误”。它在数据库中还具备额外的缺点,由于您不能可靠且一致地测试两个近似数是否相等。

说永远不要在SQL数据类型或算术中使用浮点数是不正确的。在SQL标准中,有一个特定的近似类型。现在,在有适当要求的SQL Server中,我始终坚持使用双精度浮点数据类型。它们很是适合用于建模天气系统或绘制轨迹等目的,但不适用于普通组织可能使用数据库的计算类型。

若是发现错误使用了这些类型,则应改用合适的DECIMAL/ NUMERIC类型。若是您知道须要浮点算法并能够解释缘由,那么您可能足够了解避免浮点的陷阱。

相关文章
相关标签/搜索