【问题标题】:What's the benefit of accepting floating point inaccuracy in c#在 c# 中接受浮点不准确有什么好处
【发布时间】:2011-01-05 12:24:13
【问题描述】:

lastfew 几天来我一直在想这个问题,我正在努力表达我的问题。不过,我想我已经掌握了我想知道的内容。

为什么 c# 接受不精确的方式是使用浮点数来存储数据?与其他方法相比,使用它有什么好处?

例如,Math.Pow(Math.Sqrt(2),2) 在 c# 中并不精确。有可以精确计算它的编程语言(例如,Mathematica)。

我能想到的一个论点是,精确计算它比仅仅处理不准确性要慢得多,但是 Mathematica 和 Matlab 用于计算巨大的科学问题,所以我很难相信这些语言真的慢得多比c#。

那为什么会这样呢?

PS:很抱歉给你发了这些问题,你们真的很有帮助

【问题讨论】:

  • MatLab 在 Java 沙箱中运行。如果您不相信 MatLab 速度较慢,请尝试在 MatLab 中创建一个实时程序。去过那里,做到了,没有乐趣... :-)
  • 好的,但是 Wolfram Mathematica 呢?我在互联网上找不到与 c# 相比的基准
  • 内置于 TI-89 计算器中的 CAS 几乎可以帮助我完成大学数学课程的学习,这也比 .NET Framework 内置的数学功能更胜一筹。事实上,它们是为完全不同的用例而设计的。
  • 是的,CAS 正是我想要的。但是没有可以实现的库吗?
  • 你见过Math.NET吗?它不如 Mathematica 强大,但它可能会做你想做的事。否则,我会觉得 C# 不适合这项工作。

标签: c# floating-point floating-accuracy


【解决方案1】:

为什么c#接受浮点数存储数据的不准确性?

“C#”不接受性能与准确性之间的权衡;用户接受或不接受。

C# 具有三种浮点类型——float、double 和 decimal——因为这三种类型满足了现实世界程序员的绝大多数需求。

float 和 double 适用于“科学”计算,其中精确到小数点后三位或四位的答案总是足够接近,因为这是原始测量的精度。假设您将 10.00 除以 3 并得到 3.333333333333。由于原始测量结果可能仅精确到 0.01,因此计算结果的偏差小于 0.0000000000004 的事实是无关紧要的。在科学计算中,您没有表示已知的精确数量。 如果原始测量值仅精确到小数点后第二位,则不精确到小数点后十五位是无关紧要的

财务计算当然不是这样。财务计算的操作数通常精确到小数点后两位并代表确切的数量。 Decimal 适合“财务”计算,因为只要所有输入和输出都可以精确地表示为小数(并且它们都在合理的范围内),十进制运算结果精确。当然,小数仍有舍入误差,但精确的运算正是您在进行财务计算时可能希望精确的运算。

与其他方法相比,使用它有什么好处?

您应该说明您希望与哪些其他方法进行比较。在计算机上执行计算有许多不同的技术。

例如,Math.Pow(Math.Sqrt(2),2) 在 c# 中并不精确。有可以精确计算它的编程语言(例如,Mathematica)。

让我们明确这一点; Mathematica 不会精确地“计算”根 2。这个数字是不合理的,因此无法在任何有限的存储量中精确计算。相反,mathematica 所做的是将数字表示为描述数字是如何产生的对象。如果你说“给我两个的​​平方根”,那么 Mathematica 实质上分配了一个对象,意思是“平方根运算符对精确数字 2 的应用”。如果你然后平方它,它有特殊用途的逻辑,即“如果你平方某个是其他东西的平方根,则返回原始值”。 Mathematica 也有代表各种特殊数字的对象,如 pi 或 e,以及关于这些数字的各种操作如何组合在一起的大量规则。

基本上,它是一个符号系统;它处理数字的方式与人们在纸笔数学中的操作方式相同。大多数计算机程序都像计算器一样处理数字:立即执行计算并四舍五入。如果这不可接受,那么您应该坚持使用符号系统。

我能想到的一个论点是,精确计算它比仅仅处理不准确性要慢得多,但是 Mathematica 和 Matlab 用于计算巨大的科学问题,所以我很难相信这些语言真的慢得多比c#。

并不是说它们更慢,尽管浮点乘法在现代硬件上确实非常快。就是符号计算引擎非常复杂。它编码了基础数学的所有规则,而且有很多这样的规则! C# 并非旨在成为专业级符号计算引擎,而是旨在成为通用编程语言。

【讨论】:

  • 大量科学计算器通过在幕后保留几个额外的数字并使用它们进行舍入而不是显示它们来“作弊”。考虑一下 Google,它很高兴地得到了 Sqrt(2)**2 正确...但是 sqrt(1.999999999)**2 呢?
  • +1 我无法告诉你看到一个真正理解和欣赏重要数字的程序员是多么令人耳目一新。但由于很多原因,这是一个非常棒的答案。
  • @Cody:很高兴你喜欢它。如果您对更多探索浮点数学各个有趣角落的文章感兴趣,请参阅blogs.msdn.com/b/ericlippert/archive/tags/…
  • 虽然浮点数/双精度数通常用于仅精确到小数点后 3-4 位的测量量,但它们更常用于最终会四舍五入到小数位的量在被使用或展示之前。例如,许多图形例程使用“float”或“double”。顺便说一句,比为什么使用浮点的问题更有趣的是为什么.net 没有提供任何方便的方法来使用 8087 long double 类型。虽然对 8 字节双精度的硬件支持比对长双精度的支持要好,但后者在某些用途上更好。
  • @Brian Somebody @Google 看到并修复了它。 :-)
【解决方案2】:

一个词:性能。浮点运算通常在硬件上实现,比其他方法快许多数量级。

更重要的是,您的 MATLAB 示例是假的。 MATLAB 使用双精度浮点运算,就像 C# 一样。

【讨论】:

  • +1 不仅是性能,而且在 99% 的情况下,价值与性能的权衡是不值得的。唯一需要您的问题假设的高精度的情况是您正在进行专门的数学或工程计算。并且已经有用于此的软件。
  • 好的,我已经删除了 MATLAB 示例。我不太确定,但mathematica 能做到吗?
  • @Timo 数值计算和符号计算是有区别的。大多数现实世界的工程和科学问题最好用数值算法来解决,对它们来说,浮点运算是最好的。这实质上是在重新表述@Cody Gray 所说的内容。
【解决方案3】:

c#为什么接受浮点数存储数据的不准确性?

这样,浮点支持可以映射到硬件支持浮点的方式,也就是说 - 它或多或少是在硬件中利用浮点运算的唯一方式,很多比软件解决方案更快。缺点是硬件用有限的位数来表示浮点数,这会导致不准确(请注意,不准确的定义是明确的)。

表示浮点值的其他方式需要软件解决方案,它明显较慢并且需要更多空间。 “任何人”都可以使用 c# 中可用的功能来实现这一点,包括对可用硬件的本机浮点支持,如果语言/CLR 尚不支持的话,“任何人”将很难做到这一点。

【讨论】:

    【解决方案4】:

    对于大多数编程问题,不准确不是问题,float(或double)数据类型已经足够好了。许多年前,没有“浮点值”之类的东西,软件必须将这些值存储为两个整数。并且性能一个问题(更不用说编程错误 - 和 wtf 场景 - 来自定制的浮点计算函数)。因此,在计算机配备FPUs 之后不久,设计了一个约定。

    现在,何时使用 FPU 进行计算或使用其他数学库/程序(如 Mathematica)取决于问题。例如,在 3d 环境中计算顶点更喜欢性能而不是精度。但会计软件不同。在这方面,两个问题都不同;会计软件不需要每秒计算数百万次复数 :)(编辑:或者如果需要,一些非常昂贵的硬件也可能是等式的一部分!)

    如果您知道您将使用 Math.pow(Math.sqrt(2),2),那么您应该重新考虑存储这两个值的方式(例如每次都重新计算它们)。这不是编程语言的问题,更多的是概念问题。

    【讨论】:

      【解决方案5】:

      C# 和大多数其他语言(除了特定语言,如 Matlab)将浮点数存储为固定大小的字段(6 或 8 个字节),这会导致不准确。

      【讨论】:

      • 我知道,但是如果有其他方法,为什么它使用浮点数。
      • @Timo 如果您使用固定大小的字段,还有什么其他方法?除科​​学计算外,绝大多数计算不需要无限精度,并且可以接受某种程度的不准确性。
      • 因为处理速度快,存储效率高。这是主要原因。大多数程序不需要点后 10 个符号的准确性。
      • 我不知道你是怎么做到的,但是mathematica可以精确计算,而且可能还有其他语言也可以。
      • 常用大小为 IEEE float(4 字节)、IEEE double(8 字节)和“扩展精度”(10 字节;仅限某些系统)。 float 类型在 3D 应用程序(例如游戏)中被大量使用,double 类型在科学应用程序中是de rigueur。其他领域各不相同(例如,金融应用通常使用定点)。
      【解决方案6】:

      一个原因是数字和数字格式是明确和通用的。是的,存在舍入误差,但它们是恒定的且可预测的。尝试为任何算法问题设置通用格式并非易事。

      【讨论】:

        【解决方案7】:

        heremathematica 有一点解释

        短版本适用于常规的日常浮点数学运算,硬件可以快速完成运算,但存在已知的不准确性。因此,如果您的计算不依赖于更精确的计算,那么请以快速的方式进行。

        如果您确实需要精度,则程序员必须将算法编写到所需的精度。哪个会慢一些。

        【讨论】:

          【解决方案8】:

          我不认为这是 c# 的问题。 c# 是一种通用语言,为您提供基本的数据类型。如果您对它们不满意,您可以随时创建自己的。

          此外,c# 不接受错误。程序员可以。对于大量问题,不准确是可以接受的。当需要准确的结果时,不应使用浮点数,但这是程序员而不是语言设计师的决定。

          【讨论】:

            猜你喜欢
            • 2015-09-07
            • 1970-01-01
            • 2020-05-13
            • 2020-09-18
            • 2020-03-31
            • 1970-01-01
            • 2016-10-06
            • 1970-01-01
            相关资源
            最近更新 更多