【发布时间】:2009-11-05 14:28:21
【问题描述】:
System.Math中的所有方法都以double为参数并返回参数。常量也是double 类型。我查看了MathNet.Numerics,那里的情况似乎也是如此。
这是为什么?特别是对于常量。 decimal 不应该更准确吗?在进行计算时这不是很有用吗?
【问题讨论】:
System.Math中的所有方法都以double为参数并返回参数。常量也是double 类型。我查看了MathNet.Numerics,那里的情况似乎也是如此。
这是为什么?特别是对于常量。 decimal 不应该更准确吗?在进行计算时这不是很有用吗?
【问题讨论】:
这是一个经典的速度与准确性的权衡。
但是,请记住,例如,对于 PI,您需要的最多位数是 41。
pi的最大位数 你永远需要的是 41。 计算周长 误差小于 一个质子的直径,你需要 41 pi † 的数字。看起来很安全 得出结论 41 位就足够了 任何圆的 pi 精度 您可能会遇到的测量问题 遇到。因此,在超过一个 万亿位数的 pi 计算在 2002,第 41 位以后的所有数字都有 没有实用价值。
此外,十进制和双精度的内部存储结构略有不同。小数被设计用于存储以 10 为底的数据,而作为双精度数(和浮点数)用于保存二进制数据。在二进制机器上(就像现有的每台计算机一样),在存储其范围内的任何数字时,双精度数都会减少浪费的位数。
同时考虑:
System.Double 8 字节 约 ±5.0e-324 至 ±1.7e308,有效数字为 15 或 16 System.Decimal 12 字节 约 ±1.0e-28 至 ±7.9e28,有效数字为 28 或 29
如您所见,十进制的范围更小,但精度更高。
【讨论】:
不,- 小数并不比双精度或任何类型更“精确”。 “精确度”的概念(当谈到计算机中的数字表示时)是错误的。任何类型在表示 一些 数字时都绝对 100% 准确。无符号字节在表示从 0 到 255 的整数时是 100% 准确的。但它们不适用于分数、负数或超出范围的整数。
小数在表示一组特定的 base 10 值时是 100% 精确的。双精度数(因为它们使用 二进制 IEEE 指数表示来存储它们的值)精确地表示一组 二进制 数字. 一般来说,两者都不比另一个更精确,它们只是用于不同的目的。
再详细一点,因为我对某些读者来说似乎不够清楚......
如果你取每一个可以表示为小数的数字,并在数轴上标记它们中的每一个,那么在 每 个相邻的对之间会有一个额外的 无穷大 个实数, 不能表示为小数。可以对可以表示为双精度数的数字做出完全相同的陈述。如果您将数字行上的每个小数标记为蓝色,并将每个双精度标记为红色,但整数除外,那么在两种颜色中标记相同值的地方将很少。 一般来说,对于 99.99999 % 的分数,(请不要挑剔我的百分比)蓝色组(小数)是与红色组(双打)完全不同的一组数字。
这是因为根据我们对蓝色集的定义,它是以 10 为底的尾数/指数表示,而双精度数是以 2 为底的尾数/指数表示。任何表示为底数为 2 尾数和指数的值,(1.00110101001 x 2 ^ (-11101001101001) 表示取尾数值 (1.00110101001) 并将其乘以 2 的指数幂(当指数为负时,这相当于除以 2 的幂指数的绝对值)。这意味着在指数为负数的情况下(或尾数的任何部分是小数二进制),该数字不能表示为十进制尾数和指数,反之亦然。
对于随机落在实数线上的任意实数,它要么更接近蓝色小数之一,要么更接近红色双精度数之一。
【讨论】:
十进制更精确,但范围更小。您通常会使用 Double 进行物理和数学计算,但您会使用 Decimal 进行财务和货币计算。
详情请参阅msdn上的以下文章。
【讨论】:
似乎这里关于“它不符合我的要求”的大多数论点都是“但它更快”,ANSI C+Gmp 库也是如此,但没有人提倡这样做吗?
如果您特别想控制精度,那么还有其他语言会花时间以用户可控的方式实现精确精度:
http://www.doughellmann.com/PyMOTW/decimal/
如果精度对您来说真的很重要,那么您最好使用数学家会使用的语言。如果你不喜欢 Fortran,那么 Python 是一个现代的替代品。
无论您使用哪种语言,请记住以下黄金法则: 避免混合类型... 因此,在尝试使用运算符 b 之前,请将 a 和 b 转换为相同
【讨论】:
如果我冒险猜测,我会说这些函数利用了内部不使用小数的低级数学功能(可能在 C 中),因此返回小数无论如何都需要从 double 转换为 decimal。此外,十进制值类型的目的是保证准确性;这些函数不会也不能在没有无限精度的情况下返回 100% 准确的结果(例如,无理数)。
【讨论】:
如果您需要精确的东西,那么 Decimal、float 或 double 都不够好。此外,十进制是如此昂贵且被过度使用,它已成为一个常见的笑话。
如果您使用分数并需要极高的精度,请使用分数。这是相同的旧规则,仅在必要时转换一次。您的四舍五入规则也会因应用程序、域等而异,但请确保您可以在合适的地方找到一两个奇怪的示例。但同样,如果您想要分数和最终精度,答案就是不要使用分数以外的任何东西。考虑一下您可能还需要任意精度的功能。
总的来说,CLR 的实际问题是,实现一个以通用方式处理数字的库非常奇怪和简单,这主要是由于糟糕的原始设计和平台上最流行的编译器的缺点。这与 Java 惨败几乎相同。
事实证明,double 是涵盖大多数领域的最佳折衷方案,而且效果很好,尽管 MS JIT 仍然无法利用现在大约 15 年历史的 CPU 技术。
[致 MSDN 减速编译器用户的文章]
【讨论】:
Double 是一种内置类型。 FPU/SSE 核心(以前称为“数学协处理器”)支持它,这就是它速度极快的原因。尤其是在乘法和科学函数方面。
十进制其实是一个复杂的结构,由若干个整数组成。
【讨论】: