Loading... # 关于double和float精度丢失的问题 ## 起因 这个问题,我记得我是在五年级的时候就有了,情况大概如下 > 现在,你需要将π放进一个变量中,需要保留到小数点后100位 ## 过程 ## 完成代码 ### 第一次代码 当时,我想着,不是so easy嘛,然后编写出了如下代码 ``` #include <bits/stdc++.h> using namespace std; int main(){ float x=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; cout<<x; } ``` 然后,我怀着激动的心情,颤抖的手,*内心OS:马上就可以AK了!哈哈哈哈!!!* ,但是,现实给我了种种一拳 ``` * 正在执行任务: C:\SOFTWARE\Dev-Cpp\MinGW64\bin\g++.EXE -Wall -Wextra -g3 -std=c++23 e:\double.cpp -o e:\output\double.exe PS E:\output> & .\'double.exe' 3.14159 ``` 我: > ? > > What FUCK??? 这感觉不太对啊,这输出怎么能这样子 *哦!我忘了,还有double!* ### 使用double完成 然后编写出了如下代码 ``` #include <bits/stdc++.h> using namespace std; int main(){ double x=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; cout<<x; } ``` 一键运行: ``` * 正在执行任务: C:\SOFTWARE\Dev-Cpp\MinGW64\bin\g++.EXE -Wall -Wextra -g3 -std=c++23 e:\double.cpp -o e:\output\double.exe PS E:\output> & .\'double.exe' 3.14159 ``` > ? > > 没保存吗 > > Try again ``` * 正在执行任务: C:\SOFTWARE\Dev-Cpp\MinGW64\bin\g++.EXE -Wall -Wextra -g3 -std=c++23 e:\double.cpp -o e:\output\double.exe PS E:\output> & .\'double.exe' 3.14159 ``` > What FUCK? > > 怎么还是这样? 那时候我情绪崩溃了,不知道咋回事 然后,我突然想起来了保留小数点的方法!即`setprecision` ### 使用`setprecision`的方法完成 然后写出了如下代码 ``` #include <bits/stdc++.h> using namespace std; int main(){ double x=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; cout<<setprecision(100)<<x; } ``` 嘿嘿嘿,兄弟们,终于可以AK了!!! ``` * 正在执行任务: C:\SOFTWARE\Dev-Cpp\MinGW64\bin\g++.EXE -Wall -Wextra -g3 -std=c++23 e:\double.cpp -o e:\output\double.exe PS E:\output> & .\'double.exe' 3.141592653589793115997963468544185161590576171875 ``` az 好像确实精确了亿点,但没有完全精确吧? 怀疑人生中。。。 哦!还有`printf`!!! ### 使用`printf`的方法完成 ``` #include <bits/stdc++.h> using namespace std; int main(){ double x=3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; printf("%.100lf",x); } ``` 这下总不能错了,`printf`可是C语言的,怎么可能错?? 可是... 现实又给我了重重一锤 ``` * 正在执行任务: C:\SOFTWARE\Dev-Cpp\MinGW64\bin\g++.EXE -Wall -Wextra -g3 -std=c++23 e:\double.cpp -o e:\output\double.exe PS E:\output> & .\'double.exe' 3.1415926535897931159979634685441851615905761718750000000000000000000000000000000000000000000000000000 ``` 我是不配学编程吗??? 为什么显示总是这么打击我 呜呜呜呜呜呜呜呜 呜呜呜呜呜呜 ## 现在的情况 ### 2024年,Deepseek-R1模型发布 我草,牛逼! ### 2025年9月24日,一学校老师向我询问此问题,又够引了我的兴趣 > 1. **IEEE 754 浮点数标准** > > 计算机使用固定的位数来存储浮点数: > > * **float**(单精度):32位,约6-7位有效数字 > * **double**(双精度):64位,约15-16位有效数字 > * **long double**:通常80位或128位 > > 2. **double 的存储结构** > > double 使用64位存储: > > * 1位符号位 > * 11位指数位 > * 52位尾数位 > > 这意味着 double 只能精确表示大约15-16位十进制数字。 > > *以上内容来自Deepseek-R1* EMM,似懂非懂,但是大概了解了 > 浮点数在计算机中以**二进制分数**形式存储,无法精确表示所有十进制小数。 > > *以上内容来自Deepseek-R1* 《二进制分数》 我嘞个二进制分数 依旧是补码,对吧??? > **二进制存储原理** > > double 的52位尾数只能表示有限精度的分数: > > ``` > 3.141592653588888... = 无法用有限二进制精确表示 > ``` > > 计算机找到**最接近的可表示二进制分数**,这就是你看到的"奇怪"数字。 > > 以上内容来自Deepseek-R1 我的评价:六百六十六 > 1. **浮点数都是近似值** > 2. **不要用 == 直接比较浮点数** > 3. **需要高精度时使用特殊库或整数运算** > > 以上内容来自Deepseek-R1 我的评价:近似值??? ### 现在看来,我为什么不使用先乘再除呢? ``` #include <bits/stdc++.h> using namespace std; int main(){ unsigned long long x=31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; cout<<double(x/99); } ``` 于是,我就发现了 ``` * 正在执行任务: C:\SOFTWARE\Dev-Cpp\MinGW64\bin\g++.EXE -Wall -Wextra -g3 -std=c++23 e:\double.cpp -o e:\output\double.exe e:\double.cpp:5:26: warning: integer constant is too large for its type 5 | unsigned long long x=31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PS E:\output> & .\'double.exe' 1.07941e+17 ``` 哦对对对对对对对,范围啊,我草 奇怪了,为什么我们不使用~~高精度~~**数组**呢? ### 使用数组 ``` #include <bits/stdc++.h> using namespace std; int main(){ string x="31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679"; cout<<x; } ``` 运行! ``` PS E:\output> & .\'double.exe' 31415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679 ``` 耶!成功! # 完 致谢 最后修改:2025 年 09 月 30 日 © 允许规范转载 打赏 赞赏作者 支付宝微信 赞 如果觉得我的文章对你有用,请随意赞赏