简体   繁体   English

未初始化的浮点变量,再现不确定的行为

[英]Uninitialized floating point variables, repoducing indeterminate behavior

I had to debug some code that was exhibiting transient and sporadic behavior, which ultimately could be attributed to an uninitialized float in a line of initializations, ie: 我不得不调试一些表现出瞬时和零星行为的代码,这些代码最终可以归因于初始化行中未初始化的浮点数,即:

float a = number, b, c = other_number;

This section of code was rapidly sampling a device over a serial connection and averaging the output over some interval. 这部分代码是通过串行连接快速采样设备,并在一定间隔内对输出求平均。 Every once in a while, the number 2.7916085e+035 would get reported, but otherwise the code worked as intended and the bug was not reproducible. 每隔一段时间,就会报告编号2.7916085e + 035 ,但否则该代码将按预期工作,并且该错误无法再现。

Since the number was always 2.7916085e+035 , I thought there might have been some issues with the communications handling, or the device itself, but these were ruled out. 由于该数字始终为2.7916085e + 035 ,我认为通信处理或设备本身可能存在一些问题,但已排除了这些问题。 I was almost ready to blame it on external interference until I finally caught a faulty sample in the debugger. 我几乎准备将其归咎于外部干扰,直到最终在调试器中发现错误的样本。

So, to the question. 所以,这个问题。 Can someone postulate the significance of 2.7916085e+035 ? 有人可以假设2.7916085e + 035的重要性吗? I'm not sure it has any meaning outside of my context, but what bothers me is that this number was essentially unreproducibly reproducible . 我不确定它在我的上下文之外是否具有任何意义,但是令我困扰的是该数字本质上是不可复制的 That is to say, I couldn't replicate the problem reliably, but when it arose, it was always the same thing. 就是说,我无法可靠地复制问题,但是当问题出现时,总是一样。 From my understanding, uninitialized variables are supposed to be indeterminate. 据我了解,未初始化的变量应该是不确定的。 It's worth noting that the issue happened in all different places of program execution, phase, time of day, etc... but always on the same system. 值得注意的是,问题发生在程序执行的所有不同位置,阶段,一天中的时间等等,但是总是在同一系统上发生。

Is there something in the .NET framework, runtime, or operating system that was causing the behavior? .NET框架,运行时或操作系统中是否有引起此现象的东西? This was particularly troublesome to track down because the uninitialized variable always had the same value, when it didn't luckily get set to 0. 追踪起来特别麻烦,因为未幸运地将未初始化的变量设置为0时,它始终具有相同的值。

Edit: Some context. 编辑:一些上下文。 The code is within a timer with a variable tick rate, so the variables are local non-static members of a class: 该代码位于具有可变刻度率的计时器内,因此变量是类的局部非静态成员:

if(//some box checked)
{
    switch(//some output index)
    {
        case problem_variable:
        {
            if(ready_to_sample)
            {
               float average;

               for each(float num in readings)
               {
                 average += num;
               }

               average /= readings.Count;
            }
         }
    }
}

The variable in question here would be average . 这里讨论的变量将是average readings is a list of outputs that I want to average. readings是我要平均的输出列表。 average would be redeclared one time per.... average, which can happen in seconds, minutes, hours, or whenever the condition is met to take an average. average会被重新声明一次。平均,这可能会在几秒钟,几分钟,几小时内发生,或者只要满足条件就进行平均。 More often than not the variable would get 0, but occasionally it would get the number above. 变量经常会得到0,但偶尔也会得到上面的数字。

In the common floating-point encodings, 2.7916085e+035 is 0x7a570ec5 as a float and 0x474ae1d8a58be975 as a double, modulo endianness. 在常见的浮点编码中,2.7916085e + 035为0x7a570ec5(浮点数),0x474ae1d8a58be975为双模尾数。 These do not look like a typical text character string, a simple integer, or a common address. 这些看起来不像典型的文本字符串,简单的整数或公共地址。 (The low bits of the double encoding are uncertain, as you did not capture enough decimal digits to determine them, but the high bits do not look meaningful.) (双重编码的低位不确定,因为您没有捕获到足够的十进制数字来确定它们,但是高位看起来没有意义。)

I expect there is little information to be deduced from this value by itself. 我希望从此值本身可以推断出很少的信息。

That double in 64-bit binary translates to 64位二进制双精度转换为

0100011101001010111000011101100010100101100010111110100000000000

or 要么

01111010010101110000111011000101

as a 32-bit float. 作为32位浮点数。 Nearly all modern processors keep instructions and data separate--especially R/W data. 几乎所有现代处理器都将指令和数据分开,尤其是R / W数据。 The exception, of course, is the old x86, which is a CISC processor, based on the 4004 from the days when every byte was at a premium, and even minicomputers did not have caches to work with. 当然,例外是旧的x86,它是CISC处理器,基于每个字节都非常宝贵的4004,甚至微型计算机都没有缓存可以使用。 With modern OS's, however, it is much more likely that, while 4 or 8KB pages were being moved around, a page of instructions was changed without zeroing out the old page. 但是,在现代操作系统中,很有可能在移动4或8KB页面时,在不将旧页面清零的情况下更改了指令页面。

The double version might be the equivalent to 双重版本可能等同于

Increment by 1, where r7 (EDI - extended destination index) is selected

The second, viewed as a float, looks like it would translate to either x86 or x86-64: 第二个被视为浮点数,看起来它将转换为x86或x86-64:

How do I interpet this x86_64 assembly opcode? 如何插入此x86_64程序集操作码?

The value that you see for an uninitialized variable is whatever happens to be in that memory location. 您看到的未初始化变量的值就是该内存位置中的任何值。 It's not random; 这不是随机的。 it's a value that was stored in memory by a previous function call. 它是通过上一个函数调用存储在内存中的值。 For example: 例如:

void f() {
    int i = 3;
}

void g() {
    int i;
    std::cout << i << std::endl;
}

int main() {
    f();
    g();
    return 0;
}

Chances are, this program (assuming the compiler doesn't optimize out the initialization in f() ) will write 3 to the console. 该程序(假设编译器未优化f()的初始化)可能会将3写入控制台。

Floats are a base 2 number system. 浮点数是以2为基数的系统。 Because of this there are specific values that can not be accurately saved, and evaluate to an approximation. 因此,存在无法准确保存的特定值,无法进行近似估算。

Your output is probably giving you a value that specifically gets the same estimation. 您的输出结果可能会给您一个值,该值具体得到相同的估计。 Try running through some common values that you get from the serial connection and see if you can find the value that is causing you grief. 尝试遍历从串行连接中获得的一些常用值,看看是否可以找到引起悲伤的值。 I personally would use a double for something like this instead of floats, especially if you are going to be doing any kind of calculations against those numbers. 我个人会使用double代替浮点数,尤其是如果您要针对这些数字进行任何类型的计算时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM