我正在做一些操作,没有找到确切的解释,为什么我发现一个特定的行为。内容:
- 我接收一个值(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
会产生意想不到的值?(我知道强制演员阵容可以解决问题,但我想了解原因)
4条答案
按热度按时间iaqfqrcu1#
常数
24.2
的类型为double
,其值约为24.1999999999993。所以除以0.1得到大约241.99999999999716,将此值转换为整数类型会截断为241。当您将
24.2
转换为float
类型时,最接近的表示是24.2000007629394531,除以0.1得到242.0000076293945312,它被截断为242。omqzjyyz2#
就像1/3是十进制中的周期数一样,
2/10是二进制的周期数,
1/10是二进制中的周期数。
这些将需要无限的存储来准确地存储为浮点数。
因此,24.2和0.1不能准确地表示为浮点数。
因此,一个接一个地潜水可能不会产生完全正确的结果。它可能稍微太大或稍微太小。
因此,截断可能具有不期望的效果。
在对
double
使用IEEE双精度数的机器上,当你使用
float
而不是double
(浮点常量的默认值)时,你很幸运。它恰好是一个比你想要的稍大的数字。但它也很容易被压下去。也许你应该使用四舍五入而不是截断?
tcomlyy63#
根据C标准,无后缀浮点常量的类型为
double
,而不是float
,因此代码中所有带点的常量都是double
,其他所有常量都升级为double
。以下面的代码为例(注意第二个表达式值的后缀
f
):输出为:
这里的要点是,由于使用了不同的浮点精度,所以会发生不同的近似。
4dc9hkyq4#
如果实现定义了
__STDC_IEC_559__
,浮点运算需要符合规范的附录F。尤其应注意C11 F.3中的以下项目:+
、-
、*
和/
运算符提供IEC 60559的加、减、乘和除运算。在这种情况下,编译器根据“as-if”规则执行的任何优化都需要考虑上述因素,包括每个操作的舍入误差。它不能仅仅使用24.2 / 0.1 = 242的数学事实。