十进制与双精度!- 我应该使用哪一个,何时使用?[复制]

decimal vs double! - Which one should I use and when? [duplicate]

提问人:Soni Ali 提问时间:7/22/2009 最后编辑:HerbalMartSoni Ali 更新时间:11/16/2022 访问量:571618

问:

我一直看到人们在 C# 中使用双精度。我知道我在某个地方读到,双倍有时会失去精确度。 我的问题是什么时候应该使用双精度,什么时候应该使用十进制类型? 哪种类型适合货币计算?(即超过1亿美元)

C# 双进 精度 货币

评论

8赞 Daniel F. Thornton 7/22/2009
你想要几分钱吗?(就像在加油站一样)
0赞 AaronS 7/22/2009
stackoverflow.com/questions/803225/......
4赞 atlaste 4/4/2014
实际上有一个相当的答案:decimal 的工作方式类似于 long 和 int(它是一个整数类型!),但它的语法和输出格式在某处有一个点(参见 en.wikipedia.org/wiki/Integer_(computer_science) )。double 和 float 使用尾数和指数(见 en.wikipedia.org/wiki/Floating_point )。就是这样。

答:

28赞 Clement Herreman 7/22/2009 #1

为了钱: .它需要更多的内存,但不会像有时那样有舍入问题。decimaldouble

评论

15赞 user2622016 4/17/2015
它有四舍五入的所有麻烦:尝试.主要区别在于 - 有效数的位数更多,最重要的是:在除数的质因数分解中对 5 的数字进行操作时,精度不会损失。例如。 将完全等于 。1m/3m + 1m/3m == 2m/3m1m/5m + 1m/5m2m/5m
1216赞 David 7/22/2009 #2

对于金钱,总是十进制。这就是它被创建的原因。

如果数字必须正确相加或平衡,请使用十进制。这包括人们可能手动完成的任何财务存储或计算、分数或其他数字。

如果数字的确切值不重要,请使用 double 表示速度。这包括图形、物理或其他物理科学计算,其中已经有“有效数字数”。

评论

53赞 Michael Borgwardt 7/22/2009
这并不是说 double 不准确——它具有相对的准确性,可以表示十进制根本无法处理的非常大或小的量级。
100赞 Triynko 3/22/2012
这就是你使用十进制赚钱的原因:Double 的精度只有 16 位十进制数字,经过几次算术运算后,错误会迅速积累到足以蔓延到 15、14、13 等数字。四舍五入到“美分”需要在美分数字之后至少有一个数字是完全准确的,但实际上你应该保留 4 或 5 以避免累积算术错误,你不能允许这些错误破坏你用来四舍五入美分的百分之一列。这样一来,您就剩下 16(总计)- 2(美分)-(4 或 5 个错误填充)= 哦,$hit只有 7 个(或更少)可靠的整数数字供您使用!
27赞 Triynko 3/22/2012
因此,我不会操纵超过 9.99 美元(1 个整数)的货币值,因为我想要的不是 4 或 5 位错误累积填充,而是 10 或 11 位。由于十进制是一个 128 位数字,因此即使数字达到数十万亿美元,它也能为您提供这种隔离,因为它具有 28-29 位的精度。但是,你不能比这更高。999,999,999,999,999.99R(999 万亿)需要 18 位精度才能正确四舍五入,并且由于十进制为您提供 28-29,因此这只是 10 位累积算术误差绝缘。
64赞 Triynko 3/22/2012
只是为了揉搓它......如果你正在开发一款游戏,你真的会在乎你刚刚在田野上弹射四分之一英里的炸药桶是否因为数百个“位置+(速度*时间)”步骤的累积误差而偏离目标 1/16 英寸?我怀疑。
26赞 David 3/27/2012
为了澄清这一点,double 没有 16 位数字 - 这只是有意义的数字的数量。浮点数基于以 2 为基数的数学中的指数 - 一些以 10 为基数的数字被损坏,因为如果转换为以 2 为基数的 exp,它们是一个无限级数,在二进制浮点数数学中,因为 0.1 不能精确表示。数学运算也会导致漂移 - 用美元和美分加减,你可以得到像 0.99999999999999 这样的数字。toString() 最初通过舍入来隐藏它,但精确的比较会立即被打破。0.1 * 0.1 != 0.01
9赞 Otto Allmendinger 7/22/2009 #3

一定要使用整数类型进行货币计算。
这一点怎么强调都不为过,因为乍一看,浮点类型似乎就足够了。

下面是 python 代码中的示例:

>>> amount = float(100.00) # one hundred dollars
>>> print amount
100.0
>>> new_amount = amount + 1
>>> print new_amount
101.0
>>> print new_amount - amount
>>> 1.0

看起来很正常。

现在用津巴布韦元再试一次:10^20

>>> amount = float(1e20)
>>> print amount
1e+20
>>> new_amount = amount + 1
>>> print new_amount
1e+20
>>> print new_amount-amount
0.0

正如你所看到的,美元消失了。

如果使用整数类型,则工作正常:

>>> amount = int(1e20)
>>> print amount
100000000000000000000
>>> new_amount = amount + 1
>>> print new_amount
100000000000000000001
>>> print new_amount - amount
1

评论

9赞 David 7/22/2009
您甚至不需要非常大/非常小的值来查找双精度 base2 近似值和实际以 10 为基数的值之间的差异,许多小值无法准确存储。计算“1 - 0.1 - 0.9”(确保编译器没有优化等式),并将其与零进行比较。您会发现,使用双精度时,结果类似于 2e-17 而不是 0(请确保运行比较,因为许多 print/ToString 函数将双精度四舍五入到一定数量的小数位以消除这些类型的错误)。
3赞 Noctis 12/16/2014
整数?!当你有 1.5 美元时会发生什么?
4赞 Otto Allmendinger 12/16/2014
@Noctis,如果你仔细想想,你会想出一个解决方案
1赞 Noctis 12/17/2014
:)有很多解决方案,但他说的是双精度与十进制,所以除非他离得很远,否则他需要小数部分......这就是为什么你的回答让我感到奇怪。
3赞 BlueMonkMN 11/14/2017
没有理由使用代替,而不是出于准确性目的(可能是出于性能原因)。避免 ,但使用 .Decimal 使用以 10 为基数的指数,因此在解析以 10 为基数的值(如 0.1)时,您不会遇到与使用 double 相同的二进制舍入错误。intdecimaldoubledecimal
43赞 Ian Boyd 7/22/2009 #4

十进制表示精确值。Double 表示近似值。

USD: $12,345.67 USD (Decimal)
CAD: $13,617.27 (Decimal)
Exchange Rate: 1.102932 (Double)

评论

16赞 Triynko 3/22/2012
十进制不适用于精确值。根据文档,十进制提供 28-29 位十进制数字的精度。十进制不执行分析算术,因此不“精确”。十进制对金钱来说非常有用,因为即使价值数万亿美元,它仍然会让您与累积算术误差保持 10 位隔离,同时仍然能够准确地四舍五入到美分。
7赞 gerrit 11/20/2012
为什么汇率是双倍而不是十进制?这不也只是 1 USD 的 CAD 价格吗?
4赞 Ian Boyd 11/20/2012
@gerrit 汇率不是 1 美元加元的“价格”。它是两者价值的比率。根据您的来源,确定您将获得多少位小数。例如,1 美元价值 1.0016 加元。 1 大不列颠镑价值 1.5909 加元。 1 越南盾价值 0.000048 加元。这是一个这样的比率,实际上不能在不失去精度的情况下在任何地方截断。
1赞 Ian Boyd 11/20/2012
@gerrit 0.000048来自加拿大银行。XE 表示 1 VND 价值 0.0000478405 加拿大。它们以除法计算;这会产生浮点值。
0赞 user2622016 4/17/2015
不。小数点不精确。对于上面示例中的汇率,您应该使用十进制,因为输入和输出以 10 为基数(当使用 double 时,基数转换的精度会降低,因为质因式分解中没有 5)。
206赞 Michael Borgwardt 7/22/2009 #5

我的问题是什么时候应该使用 double 和什么时候应该使用小数 类型?

decimal因为当你处理 10^(+/-28) 范围内的值时,并且你对基于基数 10 表示的行为有期望 - 基本上是金钱。

double因为当您需要相对精度(即在大值上失去尾部数字的精度不是问题)时,跨越截然不同的量级 - 覆盖超过 10^(+/-300)。科学计算就是最好的例子。double

哪种类型适合钱 计算?

十进制,十进制,十进

不接受替代品。

最重要的因素是,作为二进制分数实现时,根本无法准确地表示许多分数(如 0.1),并且其总位数较小,因为它的宽度为 64 位,而 .最后,金融应用程序通常必须遵循特定的舍入模式(有时是法律规定的)。 支持这些; 不。doubledecimaldecimaldecimaldouble

评论

2赞 vgru 9/28/2011
毫无疑问,在表示财务价值时不会使用,但是与 a 相比,当您编写不支持特定舍入模式时,您到底是什么意思?AFAIK 具有重载,这些重载接受 和 ?doubledoubledecimalMath.RoundMidpointRoundingdoubledecimal
2赞 Michael Borgwardt 9/28/2011
@Groo:我想我一定看过 .Net 1.1 API,该方法是在 2.0 中添加的 - 但由于二进制分数的问题,它仍然有点毫无意义。当前 API 文档中有一个示例说明了此问题。
0赞 Imad 6/24/2018
在许多比较中看到这句话,但无法理解其含义。你能详细说明一下吗?“Double 根本无法准确表示许多小数(如 0.1)”
1赞 Michael Borgwardt 6/25/2018
@lmad:我有一个网站:floating-point-gui.de - 基本上这与十进制数不能准确表示 1/3 的原因相同
3赞 Shadi Alnamrouti 1/8/2019
@MichaelBorgwardt当你说“十进制,十进制十进制”时,我应该使用哪一个?
46赞 Chris S 2/4/2010 #6

根据浮点类型的特征

.NET 类型 C# 关键字 精度
System.Single ~6-9 位数字
System.Double ~15-17 位数字
System.Decimal 十进制 28-29 位数字

我被使用错误类型(几年前)刺痛的方式是大量:

  • £520,532.52 - 8 位数字
  • £1,323,523.12 - 9 位数字

你用完了 100 万的浮动。

15 位货币价值:

  • 1,234,567,890,123.45英镑

9万亿,翻了一番。但是对于除法和比较,它就更复杂了(我绝对不是浮点数和无理数方面的专家——参见 Marc 的观点)。混合使用小数和双精度会导致问题:

数学或比较运算 使用浮点数 如果出现以下情况,可能不会产生相同的结果 使用十进制数是因为 浮点数可能不会 精确近似于小数点 数。

什么时候应该使用双精度而不是十进制?有一些类似且更深入的答案。

使用而不是货币应用程序是一种微优化 - 这是我看待它的最简单方式。doubledecimal

评论

1赞 Royi Namir 4/6/2014
520,532.52具有 8 个有效数,具有 9 个 mathsfirst.massey.ac.nz/Algebra/Decimals/SigFig.htm1,323,523.12
1赞 Mass Dot Net 10/2/2020
帖子中的 、 和链接已损坏。下面是指向所有三个数字类型别名的最新 MSDN 文档的链接:learn.microsoft.com/en-us/dotnet/csharp/language-reference/...floatdoubledecimal
6赞 honzajscz 11/26/2011 #7

我认为除了位宽之外的主要区别在于十进制的指数底数为 10,而双精度的指数底数为 2

http://software-product-development.blogspot.com/2008/07/net-double-vs-decimal.html