两个迭代器初始化容器出现浮点数舍入

最近在整理笔记的时候发现了个奇怪的问题:



这段代码的输出为:

0.1 1.2 2.3 3.4 4.5 5.6 6.7 7.8 8.9 10
0 1 2 3 4 5 6 7 8 9

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
vector<double> testDouble;
for(double i=0.1;i<=10;i+=1.1){
testDouble.push_back(i);
}
//遍历输出testDouble
for(vector<double>::iterator testiter=testDouble.begin();
testiter!=testDouble.end();testiter++)
cout<<*testiter<<" ";
cout<<endl;
//将testin初始化为testDouble的副本(类型转换)
vector<int> testint(testDouble.begin(),testDouble.end());
//遍历输出testint
for(vector<int>::iterator testintiter=testint.begin();
testintiter!=testint.end();testintiter++){
cout<<*testintiter<<" ";
}

为什么会出现最后一对「10、9」的输出?

刚开始以为只是double转int的问题,然后测试了下:

1
2
3
4
vector<double> test;
test.push_back(8.9 + 1.1);
vector<int> testint(test.begin(), test.end());
cout<<*testint.begin()<<endl;

运行结果:

从结果来看并不只是转换的问题。

现在从后面的结果处可以得知:
前面计算后输出的容器元素值8.9与浮点常量8.9不相等

查了不少的资料才发现问题的症结所在

精度问题,计算机里的浮点数不是十进制的,所以不能精确的加出10,那个数大概是9.99999999999998(能输出10是因为浮点数舍入(IEEE 754)),然后转换int就成了9了(截尾)跟容器、迭代器无关。

浮点数的舍入(摘自维基百科IEEE 754):

  • 舍入到最接近:舍入到最接近,在一样接近的情况下偶数优先(Ties To Even,这是默认的舍入方式):会将结果舍入为最接近且可以表示的值,但是当存在两个数一样接近的时候,则取其中的偶数(在二进制中式以0结尾的)。
  • 朝+∞方向舍入:会将结果朝正无限大的方向舍入。
  • 朝-∞方向舍入:会将结果朝负无限大的方向舍入。
  • 朝0方向舍入:会将结果朝0的方向舍入。

解决方案:double转(强制转换)int是截尾,可以使用round函数来四舍五入double类型的值

double round(double);

测试下double赋值时使用round转换后的值(四舍五入了)

再来测试下test.end()-1round(test.end()-1)

结语:遇到需要强制转换数据类型的时候还是需要多注意下该类型的存储方式和运算方式,另外还要抽时间多看看IEEE标准啊。

全文完,若有不足之处请评论指正。
本文标题:两个迭代器初始化容器出现浮点数舍入
文章作者:ZhaLiPeng
发布时间:2015年08月18日 12时39分
本文字数:本文一共有627字
原始链接:https://imzlp.me/posts/15409/
许可协议: CC BY-NC-SA 4.0
转载请保留原文链接及作者信息,谢谢!
您的捐赠将鼓励我继续创作!