为什么System.Math和例如MathNet.Numerics基于double?

问题描述 投票:7回答:7

System.Math中的所有方法都将double作为参数并返回参数。常数也是double类型。我检查了MathNet.Numerics,似乎就是那种情况。

为什么是这样?特别是对于常数。是不是decimal应该更精确?在进行计算时,这通常不会有用吗?

c# math double decimal
7个回答
16
投票

这是一种经典的速度与准确性权衡。

但是,请记住,对于PI,例如,您需要的最多数字是41。

你需要的pi的最大位数是41.要计算宇宙的周长,误差小于质子的直径,你需要41位数的pi†。对于您可能遇到的任何圆测量问题,41个数字在pi中的准确度是足够的,这似乎是安全的。因此,在2002年计算的超过一万亿个数字的pi中,超过41个的所有数字都没有实际价值。

另外,decimal和double的内部存储结构略有不同。十进制设计用于存储基数为10的数据,其中使用双精度数(和浮点数)来保存二进制数据。在二进制机器上(如现有的每台计算机),当在其范围内存储任何数字时,double将减少浪费的比特。

还要考虑:

System.Double      8 bytes    Approximately ±5.0e-324 to ±1.7e308 with 15 or 16 significant figures
System.Decimal    12 bytes    Approximately ±1.0e-28 to ±7.9e28 with 28 or 29 significant figures

如您所见,decimal的范围较小,但精度较高。


4
投票

不, - 小数不再是“精确”而不是双打,或者就此而言,任何类型。 “准确性”的概念(当谈到计算机中的数字表示时)是错误的。任何类型在表示某些数字时绝对是100%精确。无符号字节在表示从0到255的整数时是100%精确的。但它们对于分数或对于范围之外的负数或整数没有好处。

小数在表示一组基数10值时是100%精确的。双精度(因为它们使用二进制IEEE指数表示来存储它们的值)精确地表示一组二进制数。一般来说,它们都不比另一个更准确,它们只是出于不同的目的。

详细说明,因为我似乎对某些读者不够清楚......

如果将每个可表示为十进制数的数字,并在数字线上标记它们中的每一个,则在每对相邻数字之间存在一个额外的无穷大实数,这些数字不能表示为小数。可以对可以表示为double的数字进行完全相同的陈述。如果您在数字行上标记为蓝色的每个小数,并且除了整数之外,每个红色都标记为红色,那么在两种颜色中标记相同值的地方很少。一般来说,对于99.99999%的分数,(请不要挑选我的百分比)蓝色套装(小数)是一组完全不同的红色套装(双打)。

这是因为我们对蓝色集合的定义是它是基数10尾数/指数表示,而double是基数2尾数/指数表示。任何表示为基数2尾数和指数的值,(1.00110101001 x 2 ^ (-11101001101001)表示取尾数值(1.00110101001)并将其乘以指数的幂乘以2(当指数为负时,这等于将2除以绝对值的幂的指数)。这意味着当指数为负数时(或者尾数的任何部分是分数二进制),该数字不能表示为十进制尾数和指数,反之亦然。

对于任意实数,随机落在实数行上,它将更接近蓝色小数之一,或者更接近红色双精度之一。


3
投票

十进制更精确但范围更小。您通常会使用Double进行物理和数学计算,但您可以使用Decimal进行财务和货币计算。

有关详细信息,请参阅msdn上的以下文章。

http://msdn.microsoft.com/en-us/library/678hzkk9.aspx

十进制http://msdn.microsoft.com/en-us/library/364x0z75.aspx


1
投票

看起来像这里的大多数论据“它不能做我想要的”是“但它更快”,ANSI C + Gmp库也是如此,但没有人提倡这样做吗?

如果您特别想控制准确性,那么还有其他语言需要花时间以用户可控的方式实现精确的精度:

http://www.doughellmann.com/PyMOTW/decimal/

如果精确度对您来说非常重要,那么您最好使用数学家会使用的语言。如果你不喜欢Fortran,那么Python就是一个现代的选择。

无论你在做什么语言,都要记住黄金法则:避免混合类型......所以在尝试运算符之前将a和b转换成相同的b


0
投票

如果我冒险猜测,我会说这些函数利用内部不使用小数的低级数学函数(可能在C中),因此返回小数将需要从double到decimal的转换。此外,十进制值类型的目的是确保准确性;如果没有无限精度(例如,无理数),这些函数不能也不能返回100%准确的结果。


0
投票

如果你需要精确的东西,Decimal,float或double都不够好。此外,十进制是如此昂贵和过度使用它已成为一个常规的笑话。

如果您在分数中工作并且需要最高精度,请使用分数。它是同样的旧规则,转换一次,仅在必要时转换。您的舍入规则也会因应用,域等因素而异,但您确定可以找到适合的奇怪示例。但同样,如果你想要分数和最终精度,答案是不要使用除分数之外的任何东西。考虑一下你可能也想要一个任意精度的特征。

CLR的一般实际问题是,实现一个以通用方式处理数字的库是如此奇怪和简单,主要是由于糟糕的原始设计和最流行的平台编译器的缺点。它几乎与Java惨败相同。

虽然事实上MS JIT仍然无法使用现在已有15年历史的CPU技术,但事实证明它只是覆盖大多数领域的最佳折衷方案。

[片段给MSDN减速编译器的用户]


0
投票

Double是内置类型。 FPU / SSE核心(以前称为“数学协处理器”)支持,这就是为什么它非常快。特别是在增殖和科学功能方面。

十进制实际上是一个复杂的结构,由几个整数组成。

© www.soinside.com 2019 - 2024. All rights reserved.