在没有显式转换为 float 的情况下使用 uint16_t 进行操作时出现意外结果

问题描述 投票:0回答:2

我正在做一些操作,但没有找到确切的解释来解释为什么我发现了特定的行为。 背景:

  • 我收到一个值(24.2),然后计算一些偏移和增益
  • 结果通过 CAN 发送。

最小工作示例:

#include <stdio.h>
#include <stdint.h>

int main()
{
printf("Operations with comas \n");

uint16_t a = (uint16_t)((24.2 - 0)/0.1);        /* 241  Incorrect*/
uint16_t b = (uint16_t)((24.2 - 0.0)/0.1);      /* 241 Incorrect */
uint16_t c = (uint16_t)((float)(24.2 - 0)/0.1); /* 242 Correct */
uint16_t d = (uint16_t)(24.2/0.1);              /* 241 Incorrect*/
uint16_t e = (uint16_t)(242.0);                 /* 242 Correct */

printf("a %u \n" , a);
printf("b %u \n" , b);
printf("c %u \n" , c);
printf("d %u \n" , d);
printf("e %u \n" , e);

return 0;
}

我知道使用 float 时无法准确表达该值。与

IEEE-754
24.2 is
的值实际上代表
24.200000762939453125
,因此
c
e
情况下的截断是正确的。

为什么情况

a
b
d
会产生意想不到的值? (我知道强制转换可以解决问题,但我想了解原因)

c gcc floating-point ieee-754
2个回答
0
投票

根据 C 标准,无后缀的浮点常量的类型为

double
,而不是
float
,因此代码中所有带点的常量都是
double
,其他所有内容都会提升为
double

采用以下代码(注意第二个表达式的值上的后缀

f
):

#include <stdio.h>
#include <inttypes.h>

int main(void) {
    uint16_t a = (uint16_t)((24.2 - 0)/0.1);
    uint16_t b = (uint16_t)((24.2f - 0)/0.1f);
    printf("%hu %hu\n", a, b);
}

输出为:

241 242

所以这里的重点是,因为使用了不同的浮点精度,所以发生了不同的近似值。


0
投票

常量

24.2
的类型为
double
,其值约为 24.1999999999999993。因此除以 0.1 大约得到 241.9999999999999716 并将该值转换为整数类型会截断为 241。

24.2
转换为
float
时,最接近的表示形式为 24.2000007629394531。

© www.soinside.com 2019 - 2024. All rights reserved.