我阅读了关于heisenbug的维基页面,但是不明白这个例子。能够 有人详细解释它吗?
一个常见的例子 一个heisenbug是一个错误,当程序编译时出现 优化编译器,但在没有编译相同程序时则不行 优化(通常用于使用调试器进行检查)。 在调试时,优化程序通常会保留的值 寄存器通常被推送到主存储器。例如,这可能会影响到 浮点比较的结果,因为内存中的值可能更小 范围和精度高于寄存器中的值。
答案 0 :(得分:8)
以下是最近发布的具体示例:
Infinite loop heisenbug: it exits if I add a printout
这是一个非常好的标本,因为我们都可以重现它:http://ideone.com/rjY5kQ
这些错误非常依赖于平台的非常精确的功能,人们也发现它们很难再现。
在这种情况下,当省略'print-out'时,程序在CPU寄存器内执行高精度比较(高于存储在double
中)。
但是要打印出值,编译器决定将结果移动到主存储器,这会导致精度的隐式截断。当它使用截断值进行比较时,它会成功。
#include <iostream>
#include <cmath>
double up = 19.0 + (61.0/125.0);
double down = -32.0 - (2.0/3.0);
double rectangle = (up - down) * 8.0;
double f(double x) {
return (pow(x, 4.0)/500.0) - (pow(x, 2.0)/200.0) - 0.012;
}
double g(double x) {
return -(pow(x, 3.0)/30.0) + (x/20.0) + (1.0/6.0);
}
double area_upper(double x, double step) {
return (((up - f(x)) + (up - f(x + step))) * step) / 2.0;
}
double area_lower(double x, double step) {
return (((g(x) - down) + (g(x + step) - down)) * step) / 2.0;
}
double area(double x, double step) {
return area_upper(x, step) + area_lower(x, step);
}
int main() {
double current = 0, last = 0, step = 1.0;
do {
last = current;
step /= 10.0;
current = 0;
for(double x = 2.0; x < 10.0; x += step) current += area(x, step);
current = rectangle - current;
current = round(current * 1000.0) / 1000.0;
//std::cout << current << std::endl; //<-- COMMENT BACK IN TO "FIX" BUG
} while(current != last);
std::cout << current << std::endl;
return 0;
}
编辑:已验证的错误和修复仍然展示:20-Feb-17
答案 1 :(得分:5)
它来自Uncertainty Principle,它基本上表明对粒子的某些物理属性对可以同时知道的精度存在基本限制。如果你开始过于密切地观察某些粒子(即,你精确地知道它的位置)那么你就无法准确地测量它的动量。 (如果你有精确的速度,那么你无法说出它的确切位置)
所以在此之后,Heisenbug是一个在你仔细观察时消失的虫子。
在您的示例中,如果您需要程序运行良好,您将使用优化进行编译,并且会出现错误。但是一旦你进入调试模式,你就不会使用优化来编译它,这将消除错误。
因此,如果你开始过于密切地观察这个错误,你将不确定知道它的属性(或无法找到它),这类似于海森堡的不确定性原则,因此被称为海森堡。
答案 2 :(得分:0)
我们的想法是将代码编译为两种状态 - 一种是正常模式或调试模式,另一种是优化或生产模式。
同样重要的是要知道在量子级别发生了什么事情,我们也应该知道编译器级别的代码会发生什么!