# 魔性的float浮点数精度问题

## 从一个问题引入

#include <stdio.h>
int main(void)
{
float f_num1 = 21.75;
float f_num2 = 13.45;
printf("f_num1 = %f\n", f_num1);
printf("f_num2 = %f\n", f_num2);
printf("f_num1 + f_num2 = %f\n", f_num1 + f_num2);
return 0;
}

f_num1 = 21.750000
f_num2 = 13.450000
f_num1 + f_num2 = 35.200001

f_num1f_num2的结果和我们预想的一样，之所以后面多了四个0，是因为%f默认保留6位有效数字。但是f_num1 + f_num2的结果是什么鬼，这个35.200001是从哪里来的？

## 如果是C++呢

#include<iostream>
using namespace std;
int main(void)
{
float f_num1 = 21.75;
float f_num2 = 13.45;
cout << "f_num1 = " << f_num1 << endl;
cout << "f_num2 = " << f_num2 << endl;
cout << "f_num1 + f_num2 = " << f_num1 + f_num2 << endl;
return 0;
}

f_num1 = 21.75
f_num2 = 13.45
f_num1 + f_num2 = 35.2

## cout的神奇之处

#include <iostream>
using namespace std;
int main(void)
{
float num1 = 5;
float num2 = 5.00;
float num3 = 5.14;
float num4 = 5.140000;
float num5 = 5.123456;
float num6 = 5.987654321;
cout << "num1 = " << num1 << endl;
cout << "num2 = " << num2 << endl;
cout << "num3 = " << num3 << endl;
cout << "num4 = " << num4 << endl;
cout << "num5 = " << num5 << endl;
cout << "num6 = " << num6 << endl;
return 0;
}

num1 = 5
num2 = 5
num3 = 5.14
num4 = 5.14
num5 = 5.12346
num6 = 5.98765

num1num2num3num4这两组结果可以知道，cout对于float类型数值小数点后面的0是直接省去了的（这点和C语言格式化输出的%g有点像）。

num5num6两组结果不难分析出，cout对于浮点型数值，最多保留6位有效数字。

#include<iostream>
using namespace std;
int main(void)
{
float f_num1 = 21.75;
float f_num2 = 13.45;
cout.setf(ios_base::fixed, ios_base::floatfield);
cout << "f_num1 = " << f_num1 << endl;
cout << "f_num2 = " << f_num2 << endl;
cout << "f_num1 + f_num2 = " << f_num1 + f_num2 << endl;
return 0;
}

f_num1 = 21.750000
f_num2 = 13.450000
f_num1 + f_num2 = 35.200001

## 答案呼之欲出

#include<iostream>
using namespace std;
int main(void)
{
float f_num1 = 21.75;
float f_num2 = 13.45;
cout.setf(ios_base::fixed, ios_base::floatfield);
int billion = 1E9;
float f_num10 = f_num1 * billion;
float f_num20 = f_num2 * billion;
cout << "f_num1 = " << f_num1 << endl;
cout << "f_num2 = " << f_num2 << endl;
cout << "f_num10 = " << f_num10 << endl;
cout << "f_num20 = " << f_num20 << endl;
return 0;
}

f_num1 = 21.750000
f_num2 = 13.450000
f_num10 = 21749999616.000000
f_num20 = 13449999360.000000

## 再看一个例子

#include<iostream>
using namespace std;
int main(void)
{
float num1 = 2.3410E23;
float num2 = num1 + 1.0f;
cout << "num2 - num1 = " << num2 - num1 << endl;
return 0;
}

num2 - num1 = 0

## 怎么解决

### 首先，当然推荐大家在编程时尽量使用高精度的浮点类型

#include <stdio.h>
int main(void)
{
double f_num1 = 21.75;
double f_num2 = 13.45;
printf("f_num1 = %lf\n", f_num1);
printf("f_num2 = %lf\n", f_num2);
printf("f_num1 + f_num2 = %lf\n", f_num1 + f_num2);
return 0;
}

double类型可以解决大部分精度丢失问题，基本上满足日常使用了，但是仍然不能避免精度丢失（double也有精度限制），这时候就需要想另外的方法来解决了。

## 写在最后

|
4月前
QT里面字符串转ieee754标准的float浮点数
QT里面字符串转ieee754标准的float浮点数
96 0
|
11月前
|
Go
Go语言浮点数完全手册 float32和float64一文掌握!
Go语言浮点数完全手册 float32和float64一文掌握!
1284 0
Qt浮点数（float）/16进制转换
Qt浮点数（float）/16进制转换
367 0
|
2月前
|

MySQL设计规约问题之为何推荐用DECIMAL代替FLOAT和DOUBLE来存储精确浮点数
MySQL设计规约问题之为何推荐用DECIMAL代替FLOAT和DOUBLE来存储精确浮点数
24 0
|
2月前
|

31 0
|

376 0
|
Java Android开发
Android/Java判断字符串String是否为float浮点数或double类型
Android/Java判断字符串String是否为float浮点数或double类型 Android的TextUtils的isDigitsOnly方法检测整型数据没问题，但是检测浮点和double类型可能不会返回期望的...
5138 0
|
4月前
|

84 0