关于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位
  1. 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

耶!成功!

致谢

最后修改:2026 年 05 月 30 日
如果觉得我的文章对你有用,请随意赞赏