简体   繁体   English

整数环绕并没有真正理解

[英]integer wrap-around not really understood

I have the following piece of code which is called approximately 100 times per second 我有以下代码,每秒大约调用100次

if (elapsed_centiseconds_mod_60000 < 59999) {
    ++elapsed_centiseconds_mod_60000;
} else {
    elapsed_centiseconds_mod_60000 = 0;
}
if (elapsed_centiseconds_mod_60000 % 6000 == 0) {
    ++elapsed_minutes;
}

The types of the variables and constants are 变量和常量的类型是

volatile uint16_t elapsed_centiseconds_mod_60000;
volatile uint8_t start_minute_mod_10;
const int8_t calibration_second = 5;

Then exactly once per second the following is called 然后每秒恰好一次调用以下内容

int16_t get_phase_deviation(uint8_t current_second, uint8_t current_minute_mod_10) {
    int32_t deviation=
         (int32_t) elapsed_centiseconds_mod_60000 -
        ((int32_t) current_second        + (int32_t)600 - (int32_t)calibration_second) * (int32_t) 100 -
        ((int32_t) current_minute_mod_10 + (int32_t) 60 - (int32_t)start_minute_mod_10)* (int32_t)6000;
    deviation %= 60000;

    return (int16_t)(deviation<=30000? deviation: deviation-60000);
}

The idea of the code is to detect relative frequency error of two oscillators. 代码的思想是检测两个振荡器的相对频率误差。 However the code does not work as expected. 但是代码不能按预期工作。 It will start to output a deviation of zero. 它将开始输出零偏差。 But once the elapsed centiseconds are one more than they should it will jump immediately to an output of 5537 which coincidences with 2^16 % 60000 + 1. I tried to cast the intermediate values to int32_t but still the issue sticks. 但是一旦经过的百分之一比它们应该的那么多,它将立即跳到5537的输出,这与2 ^ 16%60000 + 1重合。我试图将中间值转换为int32_t,但问题仍然存在。 Usually the issue appears after 100 seconds or 10 000 centiseconds. 通常问题出现在100秒或10 000厘秒之后。 I suspect some wrap around issue but I fail to see it. 我怀疑有一些问题,但我没有看到它。

Has anyone any idea which term is causing this and why? 有谁知道哪个术语导致这个以及为什么?

You are incorrectly casting the return value of get_phase_deviation() as the range of deviation %= 60000 is -59999 to 59999 ( not 0 to 59999 ). 您错误地转换了get_phase_deviation()的返回值,因为deviation %= 60000范围deviation %= 60000-59999 to 59999不是 0 to 59999 -59999 to 59999 )。 You should change the line: 你应该改变这一行:

 return (int16_t)(deviation<=30000? deviation: deviation-60000);

to correctly deal with deviation <= -30000 as is appropriate or change the return type to int32_t . 正确处理偏差<= -30000或将返回类型更改为int32_t

Looking at the specific cases to understand the numbers you were getting, assuming: 查看具体案例以了解您获得的数字,假设:

 calibration_second = 0;
 start_minute_mod_10 = 0;

Then for a perfect system get_phase_deviation() is returning: 然后,对于一个完美的系统, get_phase_deviation()返回:

 deviation = -420000; // As computed
 deviation %= 60000;  // == 0
 return 0;

If you are 1 centisecond ahead this changes to: 如果您提前1厘米,则更改为:

 deviation = -419999; // As computed
 deviation %= 60000;  // == -59999
 return (int16_t) (-59999);  // == 5537

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

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