[原]再说精度-用于显示的数字出现精度问题的处理-(Perl/Java)

2005年03月03日写的东西,整理了以前的博客,转到这里来。

 

 

描述

1. 昨天在ChinaUnix上看见一个问题:

$ad=1.25 - 1.24;                  #$ad答案是0.01 

#$ad答案应也是0.01,但出现的答案是0。009999999999999979...
$ad = 2.25 - 2.24;                 

为什麽?怎样更正? 谢


2. 前段时间刚做完的一个TOYOTA的J2EE项目也遇到类似问题:

  把12个字段的字符串转成float再相加,每个字段都是#.##的格式,结果应该等于12.00,可实际是11.9999....,插入到Text里时还出现了越界。

问题

1. 精度:浮点数不能准确的表示
2. 结果的用途:用于计算的数值出现误差时,可能导致计算结果出现很大偏差,即使不会有太大的影响最好也不要冒险;数值是用于显示时,并不一定要处理float使之符合要求,可以尝试处理字符串。本文针对后一种情况。
3. 四舍五入:我简单的翻了一下Perl的函数库,没找到round函数。


解决办法

  因为结果是用来显示的,所以并不一定要使float完全符合#.##的形式,可以考虑处理字符串。

  由于结果应该符合#.##的形式,也就是说就四舍五入到0.01,但round()[JAVA]和int()[Perl]只能处理整数,所以先将数值乘以100,然后转换为字符串。判断字符串长度,当长度大于1时,在length-2的位置插入“.”,否则从0位置插入“0.0”。 

$a = 2.25 - 2.24;        # $a = 0.00999999999999979 
$a = $a * 100 + 0.5;  # $a = 1.49999999999998 
                                  # prepare for round off 
$a = int( $a );             # $a = 1; 

# now, we got the int value 100 times more than the value wanted. 
$a = "0.0" . $a           # $a = 0.01 
# here is the value we wanted. But the value must less than 10. 
# If we want deal with the value more than 10, we must judging
# length of the value and whether append it "0.0" in the front 
# or insert a "." into the string. 
print $a;


输出:0.01

参考

1.MSDN对浮点数精度的描述

《为何浮点数可能丢失精度》

  浮点十进制值通常没有完全相同的二进制表示形式。这是 CPU 所采用的浮点数据表示形式的副作用。为此,可能会经历一些精度丢失,并且一些浮点运算可能会产生意外的结果。

导致此行为的原因是下面之一:

  十进制数的二进制表示形式可能不精确。 
  使用的数字之间类型不匹配(例如,混合使用浮点型和双精度型)。 
  为解决此行为,大多数程序员或是确保值比需要的大或者小,或是获取并使用可以维护精度的二进制编码的十进制 (BCD) 库。

  浮点值的二进制表示形式影响浮点计算的精度和准确性。Microsoft Visual C++ 使用 IEEE 浮点格式。

2 四舍五入的算法

  四舍五入的算法处理整数,先将数值加0.5,再取得整数部分。

  Java中的Math类有round函数,可我在Perl中没找到(可能有)。我想Perl主要是针对字符串处理,也许没有这方面的函数。所幸在Perl中找到int($)函数来截断整数。

  所以,在Perl中可以这样做:

$value = int( $old + 0.5 );

在Java中直接使用Math.round()。

作者:basecn 发表于2010-6-3 22:03:00 原文链接
阅读:124 评论:0 查看评论
posted @ 2010-06-03 22:03  BaseCN  阅读(430)  评论(0编辑  收藏  举报