浮点数精度计算出现的问题
2015-06-08 14:27
148 查看
当我们保存浮点数后再读取浮点数,结果可能会出现一点点偏差。
比如:
float ft1 = 20.2;(这样编译器会报警告,因为小点数默认为double)
CString str;
str.Format(_T("%f"),ft1);
这时候ft1的值等于20.200001。
float ft2 = 20.8;
CString str;
str.Format(_T("%f"),ft2);
这时候ft1的值等于20.799999。
解决方法1:
将float改用double存储:
double dt1 = 20.2;
解决方法2:
使用%g格式化,除去0后的有效位数。
float ft1 = 20.2;
CString str;
str.Format(_T("%g"),ft1);
这时候ft1的值等于20.2。但是没法再用0对齐了,嘿嘿嘿嘿。。。。。。
解决方法3:
使用%0.4格式化
float ft1 = 20.2;
CString str;
str.Format(_T("%0.4f"),ft1);
这时候ft1的值等于20.2000。
还有些比较复杂的,比如说计算过程中出现了精度损失。
如
我们通过简单的代码试验一下:
int newWidth, newHeight; GetThumbnailSize(200, 200, 100, 100, out newWidth, out newHeight); Console.WriteLine("{0}, {1}", newWidth, newHeight); GetThumbnailSize(300, 300, 100, 100, out newWidth, out newHeight); Console.WriteLine("{0}, {1}", newWidth, newHeight);
得到的结果是:
100, 100 99, 100
第一个结果自然没有问题,但是在第二个结果中为什么是99而不是100?为此,我们再通过以下的代码来观察一番:
ratio: 0.3333333333333333333333333333 new value: 99.99999999999999999999999999 to int: 99
可见,虽然使用了decimal,精度已经非常高的,但是在经过了一除一乘,它还是没有恢复到最精确值。虽然一直说要注意浮点数计算时的精度问题,但是对于这个问题许多朋友往往只是理解到“不能直接两个浮点数相等”,包括我自己的第一印象。但事实上,从上面的结果也可以看出,把一个浮点数直接转换成整形,它便是使用了“去尾”而不是“四舍五入”的方法。因此,虽然newValue的值无比接近100,但是在强制去尾后它还是变成了99。
如果要在原来的方法中改变这个问题,最简单的方法可能是把最后的强制转型替换成Math.Round方法。Math.Round方法使用四舍五入,应该能够解决问题。不过如果只是这样的话收获不大,我们再仔细想想,应该如何做到尽可能的精确。
两个浮点数相除可能会丧失精度,但如果是乘法操作,在一般情况下精度是不会丢失的,除非发生了溢出的话,或者小数位数太多。因此在计算过程中为了保持精度,我们应该尽可能的做乘法,而不是作除法。例如以下的判断:
if ((decimal)desiredWidth / originalWidth < (decimal)desiredHeight / originalHeight)
其实最好改写成“等价”的乘法操作。
相关文章推荐
- JavaScript编写连连看
- Java的23种设计模式
- VIM键盘映射 (Map)
- GDB(四) COFF
- POJ1226:Substrings(后缀数组)
- Android 5.0 如何正确启用isLoggable(一)__使用详解
- HexEdit 3.0爆破+部份分析
- 一张图帮你看懂 iPhone 6 Plus 的屏幕分辨率
- DataTable转换JSON
- Android之ContextMenu的使用方法以及与OptionMenu的区别(转)
- 关于E-R图的基础理解
- 小米又双叒叕降价了,这次是红米2A
- Java ArrayList源码分析
- iOS开发资源汇总
- Tomcat源码阅读(四)Server
- php开发网站编码统一问题
- Hive 锁 lock
- 基于Spring可扩展Schema提供自定义配置支持
- FFmpeg的HEVC解码器源代码简单分析:概述
- IGRP/EIGRP路由协议