我正在学习C,并且出现了保护数字和舍入错误的想法。脚本语言的实践者(我在这里想到Python和Perl)需要担心这些东西吗?如果他们正在做科学编程怎么办?
答案 0 :(得分:10)
这取决于。 double
在任何地方的表现都相同,所以如果你用双打做数学,你将会遇到任何语言的同样问题。如果你使用原生的任意精度类型,那么不,这不是问题。考虑:
use Math::BigFloat;
my $big = Math::BigFloat->new("1_000_000_000_000_000_000_000");
my $small = Math::BigFloat->new("0.000000000000000000000000001");
print $big + $small;
(或者,如果你真的想隐瞒正在发生的事情:
use bignum;
print 1_000_000_000_000_000_000_000 + 0.000000000000000000000000001
)
正如所料,这会产生:
1000000000000000000000.000000000000000000000000001
同样如预期的那样,这不是在一条CPU指令中完成的。
答案 1 :(得分:7)
我不得不反对Lutz ......虽然您提到的舍入错误确实存在于Python / Perl / Ruby中,但它们与
与所有数据一样,浮点数在现代计算机上以二进制形式表示。正如存在具有周期性十进制表示的数字(例如,1/3 = 0.333333 ......),也存在具有周期性二进制表示的数字(例如,1/10 = 0.0001100110011 ......)。由于这些数字无法在(有限数量的)计算机内存中精确表示,因此涉及它们的任何计算都会引入错误。
这可以通过使用高精度数学库来解决,这些数学库将数字表示为分数的两个数字(即“numerator = 1,denominator = 10”)或字符串而不是使用本机二进制表示。但是,由于对作为其他东西存储的数字进行任何计算所涉及的额外工作,这些库必然会减慢必须通过它们的数学。
答案 2 :(得分:6)
Python中有几种类型的非整数:
x = 1 / 2
会给你标准浮点数。它的类型是float
,它与C中的基本相同,它由硬件处理,它与世界上其他float
的问题相同。
但是,还有小数型:
from fractions import Fraction
x = Fraction(1, 2)
具有合理数字的精确算术。
如果您要执行舍入,但不满意计算机上有意义数字的数量,或者跨平台可能有所不同,十进制类型是您的朋友:
from decimal import Decimal
x = Decimal('0.5')
如果您愿意,您可以将其精度设置为100位数。或者将银行应用程序设置为2。
只要计算机很愚蠢,我们就可能需要这么多不同的类型。至少,根据Pythonic原则,Python要求您对数字中的内容进行明确选择。
此外,一个很大的误解是,精确的算术不会导致舍入问题。任何时候你都可以精确地为用户做一些有用的事情 - 例如将其打印给用户或将多少美元添加到用户的银行账户---您会遇到舍入的“奇怪行为”。这是非整数算术所固有的。
答案 3 :(得分:4)
这取决于您如何表示您的数字,而不是您使用的语言。
例如,如果我在8051中编写所有代码,但实现了一个灵巧的有理数字库,那么舍入不是问题。 1/3仅等于1/3。
但是,如果我使用最新的时髦动态语言,并使用IEE754浮点数,那么IEEE754的所有限制都适用。
如果您需要关心所生成数字的详细信息,那么您需要了解它们的表示以及您选择的工具如何操纵它们。
PDL是一个在Perl中进行科学计算的流行库。
答案 4 :(得分:2)
答案 5 :(得分:1)
您可以使用外部模块对Python进行多次精确计算。 official web site中的“多精度数学”部分列出了其中的许多部分。
答案 6 :(得分:0)
嗯,你不能免受Ruby中的浮点错误的影响。例如:
irb(main):033:0> (2.01 * 1000).to_i
=> 2009
irb(main):034:0> ((2.01 * 1000.0) + 0.5).floor
=> 2010
答案 7 :(得分:0)
当然可以!
Python 2.6的一个例子:
>>> 1440.0 / 900.0
1.6000000000000001
正如lutz所说,由于脚本语言通常用C语言实现,因此它们继承了这些“功能”。用语言补偿它们无疑意味着在性能或可移植性方面进行某种权衡。
答案 8 :(得分:0)
当你进行科学编程时,无论你使用哪种编程语言或数字库,你总是要担心舍入错误。
证明:假设您想跟踪宇宙边界附近分子的运动。宇宙的大小约为930亿光年(据我们所知)。分子很小,所以你至少需要纳米级精度(10 ^ -6)。这是50个数量级。
出于某种原因,您需要旋转该分子。这涉及sin()
和cos()
操作以及相乘。乘法不是问题,因为有效数字的数量只是两个操作数的长度的总和。但sin()
怎么样?
您必须创建错误等式以确保保留足够的数字,以便最终结果具有已知的最大错误。我不知道任何“简单”的数字库可以自动执行此操作(例如,作为sin()
调用的一部分)。这是您需要Matlab或类似内容的地方。