Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

printing small numbers 1

Status
Not open for further replies.

PinkeyNBrain

IS-IT--Management
Dec 12, 2006
279
US
Ran into a scenario where I have some fairly small numbers that need to be printed. I'm wanting them to print as a decimal number without any x.xxxe-yyy scientific notation. One catch is that some of the incoming data may have text. Consider
Code:
#          Value                  #  Want to print
$data[0] = "0.001" ;              #  0.001
$data[1] = "Not Available" ;      #  Not Available
$data[2] = "0.0001" ;             #  0.0001
$data[3] = "0.000000001" ;        #  0.000000001
$data[4] = "0.1234567891234567" ; #  0.123456789
My previous formating routine worked will until $data[3] recently came along.
Code:
# some hard coding below to make it read faster
sub fmt_num {
   if ($_[0] =~ /^[\d\.]+$/) {
      return sprintf("%0.9f", $_[0])
   }
   return $_[0] ;
}
Now, $data[3] doesn't match because the "e-" is apparently being seen. I've subsequently modified things to
Code:
sub fmt_num {
   if ($_[0] =~ /^[\d\.]+$/) {
      return sprintf("%0.9f", $_[0])
   } elsif ($_[0] =~ /^[\d\.]+e\-\d{3}$/) {
      return sprintf("%0.9f", $_[0])
   }
   return $_[0] ;
}
Which works but looks awkward to me. In the pursuit of code that doesn't propagate poor programing, is there a better approach?
 
Sorry about that - hit submit too quickly. The new code actually looks like
Code:
sub fmt_num {
   if ($_[0] =~ /^[\d\.]+$/) {
      return sprintf("%0.9f", $_[0])
   } elsif ($_[0] =~ /^[\d\.]+e\-\d{3}$/) {
      my($tmp) = sprintf("%0.9f", $_[0] + 1) ;
      $tmp =~ s/^1/0/;
      return $tmp
   }
   return $_[0] ;
}
Here, the +1 will cause the e- to go away. If I subtract the 1 off, the e- comes back. But by keeping things as string, I avoid the translation.
 
You might want to take a look at Math::BigFloat and see if it does what you want.
 
Thanks - will have to think on that one. I can make it do what I want and definitely looks cleaner. First tests proves it to be kinda slow. The Math::BigFloat->new() call seems to be the snag. Under an impromptu test of 100K iterations, it took 36 seconds for BigFloat, but around 1 second for what I had.

Pondering....
 
For slightly less overhead, you can take advantage of sprintf's error checking.
(shamelessly adapted from a Perl Cookbook recipe)
Code:
sub fmt_num2 {
	use warnings FATAL => "numeric";
	$rv = eval { sprintf("%0.9f",$_[0]) };
	return $@ ? $_[0] : $rv;
}
the 'use warnings' elevates the non-numeric input warning to an error, which the eval traps. If you are especially fastidious you can check $@ that the error was truly non-numeric input.
 
In perl a string evaluated as a number evaluates to zero. Try this one, it might suit your needs:
Code:
sub fmt_num {
   if ($_[0]*1) {
      return sprintf("%0.9f", $_[0])
   }
   return $_[0] ;
}
Note however that a string starting with figures is interpreted as the numerical portion, and the text is discarded. If you can have this condition, it wouldn't work.

Franco
: Online engineering calculations
: Magnetic brakes for fun rides
: Air bearing pads
 
Dude - star for that one.
Now I'm back peddling trying to figure out why (I believe) I was getting the sci-notation back into the value and ended up with that ridiculous +1 ; s/^1/0/ ; hocus pocus (but that's my monkey)
 
Ahh - now I remember: The ($var*1) generates an error message if $var is a string (I tend to use the -w switch fairly religiously) Still a good idea that I think I can work with though.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top