在 C# 中接受浮点不准确有什么好处
我最后几天,我正在努力表达我的问题。不过,我想我已经弄清楚了我想知道的事情。
为什么c#接受使用浮点存储数据的不准确性?与其他方法相比,使用它有什么好处?
例如,Math.Pow(Math.Sqrt(2),2)
在 c# 中并不精确。有一些编程语言可以精确计算它(例如 Mathematica)。
我能想到的一个论点是,精确计算它比仅仅处理不准确性要慢得多,但 Mathematica & Matlab 用于计算巨大的科学问题,所以我很难相信这些语言真的比 c# 慢得多。
那么为什么会这样呢?
PS:很抱歉向您发送这些问题,你们真的很有帮助
I've had this problem on my mind the last few days, and I'm struggling to phrase my question. However, I think I've nailed what I want to know.
Why does c# accept the inaccuracy by using floating points to store data? And what's the benefit of using it over other methods?
For example, Math.Pow(Math.Sqrt(2),2)
is not exact in c#. There are programming languages that can calculate it exactly (for example, Mathematica).
One argument I could think of is that calculating it exactly is a lot slower then just coping with the inaccuracy, but Mathematica & Matlab are used to calculate gigantic scientific problems, so I find it hard to believe those languages are really significantly slower than c#.
So why is it then?
PS: I'm sorry for spamming you with these questions, you've all been really helpful
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
“C#”不接受性能与准确性之间的权衡;用户接受或不接受这一点。
C# 具有三种浮点类型——float、double 和decimal——因为这三种类型满足了现实世界程序员的绝大多数需求。
float 和 double 适合“科学”计算,其中精确到小数点后三到四位的答案总是足够接近,因为这是原始测量值的精度。假设您将 10.00 除以 3,得到 3.333333333333。由于原始测量值可能仅精确到 0.01,因此计算结果偏差小于 0.0000000000004 的事实是无关紧要的。在科学计算中,您并不代表已知的精确数量。 如果原始测量值仅精确到小数点后第二位,那么小数点后十五位的不精确度是无关紧要的。
财务计算当然不是这样。财务计算的操作数通常精确到小数点后两位并代表精确的数量。小数对于“金融”计算很有用,因为只要所有输入和输出都可以精确地表示为小数(并且它们都在合理的范围内),小数运算结果就是精确。当然,小数仍然存在舍入误差,但精确的运算正是您在进行财务计算时可能希望精确的运算。
您应该说明您想与哪些其他方法进行比较。在计算机上执行计算有很多不同的技术。
让我们明确这一点; Mathematica 并不精确地“计算”根 2;该数字是无理数,因此在任何有限的存储量中都无法精确计算。相反,mathematica 所做的是将数字表示为描述数字如何产生的对象。如果您说“给我 2 的平方根”,那么 Mathematica 本质上会分配一个对象,该对象意味着“将平方根运算符应用于精确的数字 2”。如果你然后平方,它有特殊目的逻辑,即“如果你平方某个东西的平方根,则返回原始值”。 Mathematica 还拥有表示各种特殊数字(例如 pi 或 e)的对象,以及关于如何将这些数字的各种操作组合在一起的大量规则。
基本上,它是一个符号系统;它处理数字的方式与人们进行纸笔数学计算的方式相同。大多数计算机程序像计算器一样处理数字:立即执行计算并将其四舍五入。如果这是不可接受的,那么您应该坚持使用符号系统。
这并不是说它们更慢,尽管浮点乘法在现代硬件上确实快得令人难以置信。而是符号计算引擎极其复杂。它编码了所有基础数学规则,而且这些规则有很多! C# 并非旨在成为专业级符号计算引擎,而是旨在成为通用编程语言。
"C#" doesn't accept the tradeoff of performance over accuracy; users do, or do not, accept that.
C# has three floating point types - float, double and decimal - because those three types meet the vast majority of the needs of real-world programmers.
float and double are good for "scientific" calculations where an answer that is correct to three or four decimal places is always close enough, because that's the precision that the original measurement came in with. Suppose you divide 10.00 by 3 and get 3.333333333333. Since the original measurement was probably accurate to only 0.01, the fact that the computed result is off by less than 0.0000000000004 is irrelevant. In scientific calculations, you're not representing known-to-be-exact quantities. Imprecision in the fifteenth decimal place is irrelevant if the original measurement value was only precise to the second decimal place.
This is of course not true of financial calculations. The operands to a financial calculation are usually precise to two decimal places and represent exact quantities. Decimal is good for "financial" calculations because decimal operation results are exact provided that all of the inputs and outputs can be represented exactly as decimals (and they are all in a reasonable range). Decimals still have rounding errors, of course, but the operations which are exact are precisely those that you are likely to want to be exact when doing financial calculations.
You should state what other methods you'd like to compare against. There are a great many different techniques for performing calculations on computers.
Let's be clear on this point; Mathematica does not "calculate" root 2 exactly; the number is irrational, so it cannot be calculated exactly in any finite amount of storage. Instead, what mathematica does is it represents numbers as objects that describe how the number was produced. If you say "give me the square root of two", then Mathematica essentially allocates an object that means "the application of the square root operator to the exact number 2". If you then square that, it has special purpose logic that says "if you square something that was the square root of something else, give back the original value". Mathematica has objects that represent various special numbers as well, like pi or e, and a huge body of rules for how various manipulations of those numbers combine together.
Basically, it is a symbolic system; it manipulates numbers the same way people do when they do pencil-and-paper math. Most computer programs manipulate numbers like a calculator: perform the calculation immediately and round it off. If that is not acceptable then you should stick to a symbolic system.
It's not that they're slower, though multiplication of floating points really is incredibly fast on modern hardware. It's that the symbolic calculation engine is immensely complex. It encodes all the rules of basic mathematics, and there are a lot of those rules! C# is not intended to be a professional-grade symbolic computation engine, it's intended to be a general-purpose programming language.
一个词:性能。浮点运算通常在硬件上实现,并且比其他方法快多个数量级。
更重要的是,你的 MATLAB 示例是假的。与 C# 一样,MATLAB 使用双精度浮点运算。
One word: performance. Floating point arithmetic is typically implemented on hardware and is many orders of magnitude faster than other approaches.
What's more your example of MATLAB is bogus. MATLAB uses double precision floating point arithmetic just like C#.
这样,浮点支持可以映射到硬件支持浮点的方式,也就是说,它或多或少是利用硬件中浮点运算的唯一方法,这比硬件快得多。软件解决方案。缺点是硬件用有限位数表示浮点,这会导致不准确(请注意,不准确是明确定义的)。
其他表示浮点值的方法需要软件解决方案,它的速度明显慢并且需要更多空间。 “任何人”都可以使用 C# 中的可用功能来实现这一点,包括对可用硬件的本机浮点支持,如果语言/CLR 尚未支持,那么对“任何人”来说都将非常困难。
This way, floating point support can map to the way hardware supports floating points, that is - it's the more or less the only way of taking advantage of floating point operations in hardware, which is much faster than a software solution. The drawback is the hardware represents the floating points with a finite number of bits, which leads to inaccuracy (note that the inaccuracy is well defined).
Other ways of representing floating point values needs a software solution, it is significantly slower and require more space. "Anyone" can implement that with what's available in c#, including native floating point support for the available hardware would be quite hard for "anyone" if this wasn't already supported in the language/CLR.
对于大多数编程问题,不准确不是问题,
float
(或double
)数据类型就足够了。许多年前,还没有“浮点值”这样的东西,软件必须将这些值存储为两个整数。性能是一个问题(更不用说来自定制浮点计算函数的编程错误以及该死的场景)。因此,设计了一个约定,不久之后计算机就配备了 FPU。现在,何时使用 FPU 进行计算或使用其他数学库/程序(例如 Mathematica)取决于问题。例如,在 3D 环境中计算顶点更看重性能而不是精度。但会计软件则不同。在这方面,两个问题有所不同;会计软件不需要每秒数百万次计算复数:)(编辑:或者如果需要,一些非常昂贵的硬件也可能是等式的一部分!)
如果您知道您将执行 Math.pow(Math.sqrt(2),2) 那么您应该重新考虑存储这两个值的方式(例如每次重新计算它们)。这不是编程语言的问题,更多的是概念上的问题。
For most programming problems, the inaccuracy is not a problem and
float
(ordouble
) data types are good enough. Many years ago, there wasn't such thing as "floating point values" and software had to store such values as two integers. And performance was an issue (not mentioning programming errors--and wtf scenarios--from custom made floating point calculation functions). Thus a convention was designed and soon after computers were equiped with FPUs.Now, when to use the FPU for calculations or using other mathematical librairies/programs (such as Mathematica) depends on the problem. For example, calculating vertexes in a 3d environment prefers performance over precision. But accounting software is different. In that aspect, both problem differ; an accounting software will not need to calculate complex numbers millions of times per seconds :) (edit: or if it does, some very expensive hardware will probably be part of the equation too!)
If you know that you'll be doing Math.pow(Math.sqrt(2),2) then you should rethink the way you store both values (like recalculating them every time). This is not a problem with the programming language, but more a conceptual problem.
C# 和大多数其他语言(除了特定的语言,如 Matlab)将浮点数存储为固定大小的字段(6 或 8 字节),这会导致不准确。
C# and most of all other languages (except specific ones, like Matlab) store floating point numbers as fixed-size fields (6 or 8 bytes), which leads to inaccuracy.
原因之一是数字和数字格式是明确且通用的。是的,存在舍入误差,但它们是恒定且可预测的。尝试为任何算法问题建立通用格式并非易事。
One reason is that numbers and number formats are unambiguous and universal. Yes, there are rounding errors, but they are constant and predictable. Trying to set up a general format for any algorithmic problem is not trivial.
这里对mathematica有一些解释
简短的版本适用于日常使用日浮点数学,硬件可以快速完成,但有一定的不准确性。因此,如果您的计算不依赖于更精确,那么就以快速的方式进行。
如果确实需要精度,那么程序员必须按照所需的精度编写算法。哪个会更慢。
There's a bit of an explanation here for mathematica
The short version is for regular day to day floating point math, the hardware can do it quickly with a known amount of inaccuracy. So if your calculation doesn't rely on being more precise, then do it the quick way.
If you do need the precision, then the programmer has to write the algorithm to the degree of precision required. Which will be slower.
我不认为这是 c# 的问题。 c# 是一种通用语言,为您提供了可以使用的基本数据类型。如果您对它们不满意,您可以随时创建自己的。
此外,c# 并不接受不准确的情况。程序员就是这样。对于大量问题,不准确是可以接受的。当需要精确结果时,不应使用浮点数,但这是程序员的决定,而不是语言设计者的决定。
I don't think it's c# problem. c# is a general purpose language and gives you basic data types to play with. If you are not happy with them you are always free to create your own.
Moreover c# isn't the one who accept inaccuracy. Programmer does. For large set of problems inaccuracy is acceptable. Float shouldn't be used when exact result is expected but this is decision for programmer not for language designer.