C++ 浮点/舍入误差的简单示例是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/249467/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is a simple example of floating point/rounding error?
提问by MrDatabase
I've heard of "error" when using floating point variables. Now I'm trying to solve this puzzle and I think I'm getting some rounding/floating point error. So I'm finally going to figure out the basics of floating point error.
我听说过使用浮点变量时的“错误”。现在我正在尝试解决这个难题,我想我遇到了一些舍入/浮点错误。所以我终于要弄清楚浮点错误的基础知识。
What is a simple example of floating point/rounding error (preferably in C++) ?
什么是浮点/舍入错误的简单示例(最好在 C++ 中)?
Edit: For example say I have an event that has probability p of succeeding. I do this event 10 times (p does not change and all trials are independent). What is the probability of exactly 2 successful trials? I have this coded as:
编辑:例如,假设我有一个成功概率为 p 的事件。我做这个事件 10 次(p 不变,所有试验都是独立的)。恰好 2 次成功试验的概率是多少?我将此编码为:
double p_2x_success = pow(1-p, (double)8) * pow(p, (double)2) * (double)choose(8, 2);
Is this an opportunity for floating point error?
这是浮点错误的机会吗?
回答by Agnius Vasiliauskas
Picture is worth a thousand words - try to draw equation f(k)
:
and you will get such XY graph (X and Y are in logarithmic scale).
If computer could represent 32-bit floats without rounding error then for every k
we should get zero. But instead error increases with bigger values of k because of floating point error accumulation.
图片值一千字 - 尝试绘制方程f(k)
:
您将得到这样的 XY 图(X 和 Y 为对数刻度)。
如果计算机可以表示没有舍入误差的 32 位浮点数,那么对于每一个k
我们都应该得到零。但是由于浮点误差累积,误差随着 k 值的增大而增加。
hth!
嗯!
回答by Motti
for(double d = 0; d != 0.3; d += 0.1); // never terminates
回答by Matthew Schinckel
Generally, floating point error refers to when a number that cannot be stored in the IEEE floating point representation.
通常,浮点错误是指无法以 IEEE 浮点表示形式存储的数字。
Integers are stored with the right-most bit being 1, and each bit to the left being double that (2,4,8,...). It's easy to see that this can store any integer up to 2^n, where n is the number of bits.
整数存储时最右边的位是 1,左边的每一位都是 (2,4,8,...) 的两倍。很容易看出,这可以存储最多 2^n 的任何整数,其中 n 是位数。
The mantissa (decimal part) of a floating point number is stored in a similar way, but moving left to right, and each successive bit being half of the value of the previous one. (It's actually a little more complicated than this, but it will do for now).
浮点数的尾数(小数部分)以类似的方式存储,但从左向右移动,每个连续位都是前一位值的一半。(它实际上比这更复杂一点,但现在就可以了)。
Thus, numbers like 0.5 (1/2) are easy to store, but not every number <1 can be created by adding a fixed number of fractions of the form 1/2, 1/4, 1/8, ...
因此,像 0.5 (1/2) 这样的数字很容易存储,但并不是每个 <1 的数字都可以通过添加固定数量的 1/2、1/4、1/8、...
A really simple example is 0.1, or 1/10. This can be done with an infinite series (which I can't really be bothered working out), but whenever a computer stores 0.1, it's not exactly this number that is stored.
一个非常简单的例子是 0.1 或 1/10。这可以通过无限级数来完成(我真的不会费心去计算),但是每当计算机存储 0.1 时,存储的并不是这个数字。
If you have access to a Unix machine, it's easy to see this:
如果您可以访问 Unix 机器,很容易看到这一点:
Python 2.5.1 (r251:54863, Apr 15 2008, 22:57:26)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.1
0.10000000000000001
>>>
You'll want to be really careful with equality tests with floats and doubles, in whatever language you are in.
无论使用何种语言,您都需要非常小心地使用浮点数和双精度数进行相等测试。
(As for your example, 0.2 is another one of those pesky numbers that cannot be stored in IEEE binary, but as long as you are testing inequalities, rather than equalities, like p <= 0.2, then you'll be okay.)
(就您的示例而言,0.2 是另一个无法存储在 IEEE 二进制文件中的讨厌数字,但只要您测试的是不等式,而不是等式,例如 p <= 0.2,那么您就可以了。)
回答by SmacL
A simple example in C that caught me a while back :
C 语言中的一个简单示例让我想起了一段时间:
double d = 0;
sscanf("90.1000, "%lf", &d);
printf("%0.4f", d);
This prints 90.0999
这打印 90.0999
This was in a function that converted angles in DMS to radians.
这是一个将 DMS 中的角度转换为弧度的函数。
Why does it not work in the above case?
为什么在上述情况下不起作用?
回答by Rory O'Bryan
Here's one that caught me :
这是一个抓住我的:
round(256.49999) == 256
roundf(256.49999) == 257
doubles and floats have different precision, so the first will be represented as 256.49999000000003
, and the second one as 256.5
, and will thus be rounded differently
doubles 和 floats 具有不同的精度,因此第一个将表示为256.49999000000003
,第二个将表示为,256.5
因此四舍五入方式不同
回答by Samuel Li
I like this one from a Python interpreter:
我喜欢 Python 解释器中的这个:
Python 2.7.10 (default, Oct 6 2017, 22:29:07)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 0.1+0.2
0.30000000000000004
>>>
回答by formiaczek
super simple:
超级简单:
a = 10000000.1
b = 1/10
print(a - b == 10000000)
print ('a:{0:.20f}\nb:{1:.20f}'.format(a, b))
prints (depending on the platform) something like:
打印(取决于平台)类似于:
False
a:10000000.09999999962747097015
b:0.10000000000000000555
回答by Danilo Pianini
This is the simplest that comes to my mind, that should work with many languages is simply:
这是我想到的最简单的方法,它应该适用于多种语言:
0.2 + 0.1
Here are some examples with the REPLs that come into my mind, but should return this result on any IEEE754-compliant language.
以下是我想到的一些 REPL 示例,但应该在任何符合 IEEE754 的语言上返回此结果。
Python
Python
>>> 0.2 + 0.1
0.30000000000000004
Kotlin
科特林
0.2 + 0.1
res0: kotlin.Double = 0.30000000000000004
Scala
斯卡拉
scala> 0.2 + 0.1
val res0: Double = 0.30000000000000004
Java
爪哇
jshell> 0.2 + 0.1
==> 0.30000000000000004
Ruby
红宝石
irb(main):001:0> 0.2 + 0.1
=> 0.30000000000000004