yunfan188 2022-07-06 02:24 采纳率: 100%
浏览 102
已结题

【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条回答 默认 最新

  • 私房菜 移动开发领域优质创作者 2022-07-06 11:19
    关注

    这个问题还是提的挺好的,主要就是需要考虑float 和doubule 在内存中的分布情况。这个你可以网上搜一下。
    就这个代码,我们先直接来看第 3 处,我给你看下x 在内存中的分布:
    (gdb) p x
    $3 = 0.099999999860301614
    (gdb) p &x
    $4 = (double *) 0x7fffffffe210
    (gdb) x /16g 0x7fffffffe210
    0x7fffffffe210: 0x3fb9999999000000 0x4139999966666666

    看到了没0x7fffffffe210 为x 的内存地址,占用8个字节的话,值在内存中为 0x3fb9999999000000,转换成十进制为 0.099999999860301614 ,所以,用你的宏定义,那肯定是0.000000

    再来看下第 2 处,虽然是宏定义,但是在内存中这两个数是存放在静态区的,所以,结果跟第 3 处基本是一样的。

    至于第 1 处,本身在内存中的数就是0.1,所以,打印出来也是0.100000

    希望对你有帮助,有其他问题,也可以随时问我。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 7月19日
  • 已采纳回答 7月11日
  • 创建了问题 7月6日

悬赏问题

  • ¥15 网络科学导论,网络控制
  • ¥100 安卓tv程序连接SQLSERVER2008问题
  • ¥15 利用Sentinel-2和Landsat8做一个水库的长时序NDVI的对比,为什么Snetinel-2计算的结果最小值特别小,而Lansat8就很平均
  • ¥15 metadata提取的PDF元数据,如何转换为一个Excel
  • ¥15 关于arduino编程toCharArray()函数的使用
  • ¥100 vc++混合CEF采用CLR方式编译报错
  • ¥15 coze 的插件输入飞书多维表格 app_token 后一直显示错误,如何解决?
  • ¥15 vite+vue3+plyr播放本地public文件夹下视频无法加载
  • ¥15 c#逐行读取txt文本,但是每一行里面数据之间空格数量不同
  • ¥50 如何openEuler 22.03上安装配置drbd