【C语言】定义一个宏命令,实现对一个数值保留小数点后一位有效数字的问题疑问?

我写了一个保留小数点后一位有效数字的宏定义,不进行四舍五入处理,如下所示:

#define PRECISION_1(x) (((double)((int32_t)((x) * 10))) / 10)

测试用例如下所示:

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

#define PRECISION_1(x) (((double)((int32_t)((x) * 10))) / 10)

int main()
{
    printf("result=%lf\n", PRECISION_1(3.1415926));
    double temp = 0.100000;
    printf("temp=%lf, result=%lf\n", temp, PRECISION_1(temp)); // --1
    printf("result=%lf\n", PRECISION_1(0.100000));
    printf("result=%lf\n", PRECISION_1(1677721.400000-1677721.300000)); // --2
    double x = 1677721.4-1677721.3;
    // float x = 1677721.4-1677721.3;  //改成float类型,结果又是正确的,离谱啊!
    printf("x=%lf, result=%lf\n", x, PRECISION_1(x)); // --3
    return 0;
}

使用 GCC 编译器进行编译:gcc test.c -o test (可以加 -std=c99 或 -std=c11)
运行结果如下:./test

result=3.100000
temp=0.100000, result=0.100000
result=0.100000
result=0.000000
x=0.100000, result=0.000000

可以看到上述代码第1处、第2处和第3处的 result 输出结果是有区别的,让人匪夷所思!

我对 test.c 源码进行预处理后:gcc -E test.c -o test.i,打开 test.i 文件,关键代码如下:

......
typedef int int32_t;
......
# 7 "test3.c"
int main()
{
    printf("result=%lf\n", (((double)((int32_t)((3.1415926) * 10))) / 10));
    double temp = 0.100000;
    printf("temp=%lf, result=%lf\n", temp, (((double)((int32_t)((temp) * 10))) / 10));
    printf("result=%lf\n", (((double)((int32_t)((0.100000) * 10))) / 10));
    printf("result=%lf\n", (((double)((int32_t)((1677721.400000-1677721.300000) * 10))) / 10));
    double x = 1677721.4-1677721.3;
    printf("x=%lf, result=%lf\n", x, (((double)((int32_t)((x) * 10))) / 10));
    return 0;
}

我这里不明白的是,为什么上述代码第1处、第2处和第3处的运行结果一个是0.100000,而另外两个却是0.000000,这让我感到很奇怪!
变量temp和x的值都是0.100000,PRECISION_1(temp)的结果是0.100000,而PRECISION_1(x)的值却是0.000000,离大谱啊!!!

还请C/C++语言大神们帮忙解答一下呀,感谢了!

阅读 2.2k
1 个回答

我认为这种情况是由两种原因导致:

  1. 因为1677721.400000和1677721.300000被默认为double型,而1677721.400000-1677721.300000=0.099999999860301614。(int32_t)(0.099999999860301614*10)=0,因此最终结果为0.000000。
    如果想要使用float型来计算,可以在变量后面加上f。例如printf("result=%lf\n", PRECISION_1(1677721.400000f-1677721.300000f));
  2. 打印的结果最多只能显示小数点后6位数,而且结果会进行四舍五入。因此尽管要求输出double型的结果,0.099999999860301614也会被输出为0.100000。想要看到真正的结果,需要在debug下调试。

下图是调试细节:
image.png

image.png

image.png

printf("result=%lf\n", PRECISION_1(1677721.400000f - 1677721.300000f));

// 输出:
result=0.100000

希望我的回答对你有所帮助。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进