实数 vs 浮点数 vs 货币

20

为什么当我在SQL Server中将一个值保存到Real类型的列中,它返回给我的值更像是40.53999878999而不是40.54?我已经看到过这种情况几次,但从未找出发生这种情况的原因。是否有其他人遇到过这个问题,如果有,是什么原因造成的?


这是:http://www.panix.com/~arnow/brooklyn_college/diatribe.html - Moshe
4个回答

46

看一下计算机科学家应该了解的浮点数算术

计算机中的浮点数并不能精确地表示十进制小数。相反,它们表示的是二进制小数。大多数分数在二进制小数中没有精确的表示,因此会进行一些四舍五入。当这样一个四舍五入的二进制小数被转换回十进制小数时,就会出现你所描述的效果。

对于存储货币值,SQL数据库通常提供了一个存储精确十进制数字的DECIMAL类型。这种格式对计算机来说稍微不那么高效,但在想要避免十进制舍入误差时非常有用。


3
实际上,对于计算机来处理(由于主要缺乏硬件支持),速度会显着变慢(大约慢了十倍),但是由于数值运算远远不是瓶颈,所以这种缓慢并不影响大多数应用程序。 - crazy2be
2
浮点数不能精确地表示某些十进制小数。现实生活中的实数也不能精确地表示某些分数。例如,1/2在两个系统上都可以精确地表示。 - axiac

13

浮点数使用二进制小数,与十进制小数不完全对应。

对于货币,最好将分数作为整数存储,或者使用十进制数类型。例如,Decimal(8,2) 存储 8 位数字,包括 2 位小数(xxxxxx.xx),即精确到分的精度。


我很希望你们两个都能因为回答得好而获得积分。我们使用货币值而不是存储分数,您认为这也是一个好的做法吗? - Middletone
存储分是个坏消息。金融机构在计算中经常使用分数的分,并且有时也需要将它们存储起来。我曾经参与过一个项目,在这个项目中,分存储应用程序部署后出现了问题。非常不好看。 - MusiGenesis
1
只是一个提醒,Decimal(8,2) 实际上不是 xxxxxxxx.xx 而是 xxxxxx.xx 吧?这里的 8 指的是小数点前后的总位数。 - Giannis Paraskevopoulos

6

1
为了澄清一下,计算机中存储的浮点数的行为与其他帖子中描述的一样,因为它是以二进制格式存储的。这意味着,除非它的值(值的尾数和指数分量)都是2的幂,否则无法准确表示。
另一方面,某些系统将小数存储为十进制(例如SQL Server Decimal和Numeric数据类型以及Oracle Number数据类型),因此它们的内部表示对于任何10的幂次方数字都是精确的。但是,不能准确表示不是10的幂次方的数字。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接