C 中的浮点减法结果为零

发布于 2024-08-04 07:37:59 字数 250 浏览 4 评论 0原文

我有用 C 语言编写的代码,适用于 16 位微控制器。该代码本质上执行大量浮点运算。

在结果为正之前,算术工作正常,但在减法的情况下,如果预期结果为负,我会得到零。

result = 0.005 - 0.001;      Is correctly computed as 0.004
result = 0.001 - 0.005;      Is always zero.

为什么浮动会有这样的行为?

I have code written in C which is intended for a 16-bit microcontroller. The code essentially does lot of floating point arithmetic.

The arithmetic works fine till the result is positive, but in case of subtraction, if the expected result is negative, I get a zero.

result = 0.005 - 0.001;      Is correctly computed as 0.004
result = 0.001 - 0.005;      Is always zero.

Why is there such a behavior for float?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

花辞树 2024-08-11 07:37:59

有趣的。这很可能是浮点软件中的错误。嵌入式系统通常包含浮点作为选项,以减少代码大小。

我不确定这就是这里的问题,因为你的第一个声明有效。

发生了什么:

result = 0.005 - 0.001;
result = -result;

result = 0.002 - 0.001;
result = 0.002 - 0.002;
result = 0.002 - 0.003;

result = 0.001 - 0.002;
result = 0.001 - 0.003;
result = 0.001 - 0.004;

这里的想法是收集有用的信息,了解可能导致这种情况的原因,这是取证中常见的事情。这些计算的结果可能有助于确定实际问题。

根据您在评论中的结果:

result = 0.005 - 0.001;  // 0.004
result = -result;        // 0.000
result = 0.002 - 0.001;  // 0.001
result = 0.002 - 0.002;  // 0.000
result = 0.002 - 0.003;  // 0.000
result = 0.001 - 0.002;  // 0.000
result = 0.001 - 0.003;  // 0.000
result = 0.001 - 0.004;  // 0.000

看起来您的浮点库有一个严重的缺点。还有两个问题:

  • 您如何打印结果(向我们展示实际代码)?
  • 您使用哪种微控制器和开发环境?

您的打印方式可能存在一些问题,或者可能是您的环境的限制。

阿吉特,我认为你真的必须给我们一些代码来帮助你。不一定是您的真实代码(您对发布真实代码的担忧是可以理解的),只是一些演示问题的代码。

根据您的一些评论,即:

Adriaan,“result”的数据类型是float,即32位表示(单)。我有 CAN 作为系统接口,因此我将结果乘以 1000 来发送通过 CAN 总线。如果它恰好是负数,例如 -0.003,那么我期望 CAN 消息中出现 FF FD。我没有调试器。

我不确定我是否完全理解,但我会尝试一下。

您有一个 32 位浮点数,例如 -0.003,将其乘以 1000,然后将其放入整数(0xFFFD 是 -3 的 16 位二进制补码表示形式)。那么,当您运行类似以下代码的代码时会发生什么:

int main(void) {
    float w = -0.003;
    int x = (int)(w * 1000);
    int y = -3;
    int z = -32768;
    // Show us you code here for printing x, y and z.
    return 0;
}

我希望您测试整数的原因是它可能与浮点数完全无关。浮点值可能完全正确,但打印它的方式(CAN 方法)存在一些问题。

如果“CAN”是某种串行接口,则可能对允许通过它发送的字节有限制。我可以设想一种场景,其中高字节用作数据包标记,以便 FF 实际上可能提前结束消息。这就是为什么我还希望您测试-32768 (0x8000)。

很难相信 STMicroElectronics 会生产出如此脑残的运行时系统,无法处理负数漂浮。在我看来,信息更有可能在其他地方被破坏(例如,“打印”过程,无论是什么)。

Interesting. It could quite easily be a fault in the floating point software. Embedded systems often include floating point as an option so as to keep the code size down.

I'm not sure that's the problem here though since your first statement works.

What happens with:

result = 0.005 - 0.001;
result = -result;

result = 0.002 - 0.001;
result = 0.002 - 0.002;
result = 0.002 - 0.003;

result = 0.001 - 0.002;
result = 0.001 - 0.003;
result = 0.001 - 0.004;

The idea here is to collect useful information as to what could be causing it, a common thing to do in forensics. The results of those calculations are likely to be helpful in determining the actual problem.

Based on your results in the comments:

result = 0.005 - 0.001;  // 0.004
result = -result;        // 0.000
result = 0.002 - 0.001;  // 0.001
result = 0.002 - 0.002;  // 0.000
result = 0.002 - 0.003;  // 0.000
result = 0.001 - 0.002;  // 0.000
result = 0.001 - 0.003;  // 0.000
result = 0.001 - 0.004;  // 0.000

It looks like your floating point library has a serious shortcoming. Two more questions:

  • How are you printing out the results (show us the actual code)?
  • Which micro-controller and development environment are you using?

There may be some problem with the way you're printing or it may be a limitation of your environment.

Ajit, I think you're really going to have to give us some code to help you out. Not necessarily your real code (your concern about releasing the real code is understood), just some that demonstrates the problem.

Based on some of your comments, to wit:

Adriaan, the datatype for "result" is of float, that is, 32-bit representation (single). I have CAN as the system interface, and hence I am multiplying the result by 1000 to send it over the CAN bus. If it happens to be a negative number, like -0.003, then I am expecting FF FD in the CAN message. I do not have a debugger.

I'm not sure I totally understand, but I'll give it a shot.

You have a 32-bit float, for example, -0.003 and you multiply it by 1000 and put it in an integer (0xFFFD is the 16-bit two's complement representation of -3). So what happens when you run something like the following code:

int main(void) {
    float w = -0.003;
    int x = (int)(w * 1000);
    int y = -3;
    int z = -32768;
    // Show us you code here for printing x, y and z.
    return 0;
}

The reason I want you to test an integer is that it may have nothing to do with floats at all. It may be that the float value is perfectly correct, but there's some problem with the way you're printing it (the CAN method).

If "CAN" is some sort of serial interface, it may be there's a restriction on the bytes you're allowed to send across it. I can envisage a scenario where the high bytes are used as packet markers so that FF may actually end the message prematurely. That's why I also want you to test -32768 (0x8000).

It's hard to believe that STMicroelectronics would produce such a braindead runtime system that it couldn't handle negative floats. It seems much more likely to me that the information is being corrupted somewhere else (for example, the "printing" process, whatever that may be).

蝶…霜飞 2024-08-11 07:37:59

微控制器有浮点硬件吗?可能不会;微控制器通常不会。因此,这可能是浮点运算软件实现中的错误或限制。查找文档,和/或阅读源代码(如果有)。

Does the microcontroller have hardware for floating-point? Probably not; microcontrollers generally don't. So, this might be a bug or limitation in the software implementation of floating-point arithmetic. Look for documentation, and/or read the source if you have it.

孤独患者 2024-08-11 07:37:59

您是否可能尝试将 0.001 - 0.005 的结果打印为 5 个字符字段?如果是这样,结果将显示为四舍五入到 0.0。

Is it possible that you are trying to print out the result of 0.001 - 0.005 as a 5 character field? If so, the result will be displayed as rounded to 0.0.

分开我的手 2024-08-11 07:37:59

您能提供更多背景信息吗?在此示例中,评估可能由编译器完成,因为两个常量在编译时都是已知的。 “结果”的类型是什么? (即 IEEE-754 半或单或双?)您如何评价这?使用调试器、if 语句还是使用 printf?我之所以问这个问题,是因为可能存在转移注意力的情况。例如,如果您使用 printf 的格式不正确,您可能只是看不到减号。当您查看二进制表示形式(即,如果是 32 位,则通过 printf("%lx", result))并检查符号位。

Can you provide more context? In this example, the evaluation is propably done by the compiler as both constants are known at the time of compilation. What is the type of 'result'? (i.e. IEEE-754 half or single or double?) How do you evaluate this? Using a debugger, if-statement or with a printf? The reason I'm asking this is because there may be a red herring. For instance if you format incorrectly using printf, you may just not see the minus sign. When you take a look at the binary representation (i.e. by printf("%lx", result) if it is 32-bit) and check the sign bit.

变身佩奇 2024-08-11 07:37:59

它本质上不是 C 的东西,所以这取决于你没有说过的事情: -

  • 控制器(显然是 ST10)
  • 编译器(Cosmic 软件?如果是的话是否符合标准)
  • 浮点库(来自编译器?)
  • 程序(最短的完整 )证明它会很好的程序。)

是否是您从浮点转换为您尚未显示的 int 的转换?

It's not an inherently C thing, so it's down to the things you haven't said:-

  • Controller (ST10 Apparently)
  • Compiler (Cosmic software? If so is standards compliant)
  • Floating point library (From the compiler?)
  • The program (Shortest complete program that demonstrates it would be good.)

Could it be your cast converting from floating point to an int that you haven't shown?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文