[ic] Vend::Util::round_to_frac_digits() precision issue

Brian J. Miller wiggins at danconia.org
Wed Sep 2 14:19:39 UTC 2009


I've been messing with the oft seen issue of rounding floats in Perl and
noticed that the round_to_frac_digits() method can't handle
"exponentized" (word?) numbers. Basically it just returns the original
because the regex can't handle the number. The attached patch handles
this case by assuming we are close enough to zero to not care (I
suppose for correctness it should examine $digits to make that
judgement) and returns 0 in this case. A number recognized as before
should be handled as before. Anything else I've added a warning for, but
otherwise handle as before (aka returning what was given).

I don't know if this is a consequence of my Perl build, 64 bit OS, a
newer Perl version, or what. I'll leave that to the experts to suss out.

Example failure numbers:

-2.13370987545147e-16
-1.4210854715202e-14

Thoughts?


 From 1a133ec7a0119fdfee9702fb1a8f07a6b7542185 Mon Sep 17 00:00:00 2001
From: Brian J. Miller <brian at endpoint.com>
Date: Wed, 2 Sep 2009 07:59:25 -0600
Subject: [PATCH] Expand range of round_to_frac_digits to handle 
exponentized numbers

---
  lib/Vend/Util.pm |   20 +++++++++++++++-----
  1 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/lib/Vend/Util.pm b/lib/Vend/Util.pm
index 8356b84..5be6b5a 100644
--- a/lib/Vend/Util.pm
+++ b/lib/Vend/Util.pm
@@ -269,12 +269,22 @@ sub round_to_frac_digits {
         else {
                 $digits = 2;
         }
-       my @frac;
-       $num =~ /^(-?)(\d*)(?:\.(\d+))?$/
-               or return $num;
+       if ($num =~ /^(-?)(\d*)(?:\.(\d+)(?:e-(\d+)))?$/) {
+               # this number sufficiently close to zero for our purposes
+               return 0;
+       }
+       elsif ($num =~ /^(-?)(\d*)(?:\.(\d+))?$/) {
+               # no op
+       }
+       else {
+               warn "Vend::Util::round_to_frac_digits: invalid number 
($num)\n";
+               return $num;
+       }
+
         my $sign = $1 || '';
-       my $int = $2;
-       @frac = split(m{}, ($3 || 0));
+       my $int  = $2;
+       my @frac = split(m{}, ($3 || 0));
+
         local($^W) = 0;
         my $frac = join "", @frac[0 .. $digits - 1];
         if($frac[$digits] > 4) {
-- 
1.5.6.3

-- 
Brian J. Miller
End Point Corp.
http://www.endpoint.com/
brian at endpoint.com



More information about the interchange-users mailing list