我在last few天的时间里已经遇到了这个问题,我很难说出我的问题。但是,我想我已经固定了我想知道的东西。
为什么c#通过使用浮点存储数据来接受不准确?使用它比其他方法有什么好处?
例如,Math.Pow(Math.Sqrt(2),2)
在c#中并不完全正确。有些编程语言可以精确计算它(例如,Mathematica)。
我能想到的一个论点是,计算它确实比仅仅应对不准确要慢得多,但Mathematica& Matlab用于计算巨大的科学问题,因此我发现很难相信这些语言真的比c#慢得多。
那么为什么呢?PS:我很抱歉用这些问题向你发送垃圾邮件,你们都非常乐于助人
答案 0 :(得分:32)
为什么c#通过使用浮点存储数据来接受不准确?
“C#”不接受性能与准确性的权衡;用户做或不接受。
C#有三种浮点类型 - float,double和decimal - 因为这三种类型满足了现实世界程序员的绝大多数需求。
float和double适用于“科学”计算,其中对三位或四位小数正确的答案总是足够接近,因为这是原始测量所带来的精度。假设你将10.00除以3得到3.333333333333。由于原始测量值可能精确到0.01,因此计算结果偏差小于0.0000000000004这一事实无关紧要。在科学计算中,您不代表已知的准确数量。 如果原始测量值仅精确到小数点后第二位,则小数点后十五位的不精确度无关紧要。
这当然不适用于财务计算。财务计算的操作数通常精确到两位小数并表示精确数量。十进制适用于“财务”计算,因为十进制运算结果是精确,前提是所有输入和输出都可以精确地表示为十进制(并且它们都在合理的范围内)。当然,小数仍然存在舍入误差,但精确的运算正是您在进行财务计算时可能想要精确的运算。
使用它比其他方法有什么好处?
您应该说明您想要比较的其他方法。在计算机上执行计算有很多不同的技术。
例如,Math.Pow(Math.Sqrt(2),2)在c#中并不精确。有些编程语言可以精确计算它(例如,Mathematica)。
我们在这一点上要明确; Mathematica没有完全“计算”根2;这个数字是不合理的,因此无法在任何有限的存储量中精确计算。相反,mathematica所做的是它将数字表示为描述数字生成方式的对象。如果你说“给我两个平方根”,那么Mathematica本质上会分配一个对象,意思是“将平方根运算符应用于精确数字2”。如果你然后对它进行说明,它就有一个特殊用途的逻辑,即“如果你把某些东西放在其他东西的平方根上,那么就给出原始值”。 Mathematica具有代表各种特殊数字的对象,如pi或e,以及关于这些数字的各种操作如何组合在一起的大量规则。
基本上,它是符号系统;它操纵数字的方式与人们做铅笔纸数学时的操作方式相同。大多数计算机程序操纵数字,如计算器:立即执行计算并将其四舍五入。如果这是不可接受的,那么你应该坚持使用符号系统。
我能想到的一个论点是,计算它确实比仅仅应对不准确要慢得多,但Mathematica& Matlab用于计算巨大的科学问题,因此我发现很难相信这些语言真的比c#慢得多。
虽然它们的速度并不慢,但浮点数的乘法在现代硬件上确实非常快。这是符号计算引擎非常复杂。它编码基本数学的所有规则,并且有很多这些规则! C#不是专业级的符号计算引擎,它旨在成为通用编程语言。
答案 1 :(得分:12)
一个词:表现。浮点算法通常在硬件上实现,并且比其他方法快许多个数量级。
你的MATLAB实例更是虚假。 MATLAB使用双精度浮点运算,就像C#一样。
答案 2 :(得分:3)
为什么c#通过使用浮点来存储数据来接受不准确?
这样,浮点支持可以映射到硬件支持浮点的方式,也就是说 - 它或多或少是在硬件中利用浮点运算的唯一方法,很多比软件解决方案更快。缺点是硬件代表具有有限位数的浮点,这会导致不准确(请注意,不准确性很明确)。
表示浮点值的其他方式需要软件解决方案,它明显更慢并且需要更多空间。 “任何人”都可以使用c#中提供的内容来实现,包括对可用硬件的本机浮点支持对于“任何人”来说都是非常困难的,如果语言/ CLR中尚不支持它。
答案 3 :(得分:2)
对于大多数编程问题,不准确性不是问题,float
(或double
)数据类型足够好。许多年前,没有“浮点值”这样的东西,软件必须存储两个整数这样的值。性能 是一个问题(没有提到编程错误 - 和wtf场景 - 来自自定义浮点计算函数)。因此,设计了一个惯例,并且在计算机配备FPU之后不久。
现在,何时使用FPU进行计算或使用其他数学图书馆/程序(如Mathematica)取决于问题。例如,计算3d环境中的顶点会优先考虑性能而不是精度。但会计软件是不同的。在这方面,两个问题都不同;会计软件不需要每秒数百万次计算复数:)(编辑:或者如果确实如此,一些非常昂贵的硬件也可能是等式的一部分!)
如果您知道您将要做Math.pow(Math.sqrt(2),2),那么您应该重新考虑存储这两个值的方式(比如每次重新计算它们)。这不是编程语言的问题,而是概念问题。
答案 4 :(得分:0)
C#和大多数其他语言(除了特定的语言,如Matlab)将浮点数存储为固定大小的字段(6或8字节),这会导致不准确。
答案 5 :(得分:0)
我不认为这是c#问题。 c#是一种通用语言,为您提供基本数据类型。如果您对他们不满意,您可以自由创建自己的。
此外,c#不是接受不准确的人。程序员呢。对于大量问题,不准确是可以接受的。如果预期得到确切的结果,则不应使用Float,但这是程序员不是语言设计者的决定。
答案 6 :(得分:0)
一个原因是数字和数字格式是明确的和通用的。是的,存在舍入错误,但它们是恒定且可预测的。尝试为任何算法问题设置通用格式并非易事。
答案 7 :(得分:0)
对mathematica有一些解释here
简短版本适用于常规的日常浮点数学运算,硬件可以快速完成并具有已知的不准确度。因此,如果您的计算不依赖于更精确,那么请快速进行。
如果确实需要精度,那么程序员必须将算法写入所需的精度。哪个会慢一些。