Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re: Rounding to a Given Number of Significant Figures Rather Than Decimal Places

by davis (Vicar)
on Jan 13, 2003 at 13:58 UTC ( [id://226455]=note: print w/replies, xml ) Need Help??


in reply to Rounding to a Given Number of Significant Figures Rather Than Decimal Places

Hi, welcome to Perl, and welcome to PerlMonks
If you haven't yet heard of it, now's the time to check out the CPAN, where you can get pre-built and pre-tested1 modules to do common tasks. A quick trawl through the Math:: namespace revealed the Math::SigFigs module, which, once installed, can be used like this:
#!/usr/bin/perl use warnings; use strict; use Math::SigFigs; my $num = 123.456; print FormatSigFigs($num,1), "\n";

1. Don't underestimate the importance of the tested status. The modules will (usually) have been used by many people, on many platforms, and problems will hopefully have been reported back to the module author and fixed. You'll hear many people saying "Don't re-invent the wheel"; testing is just one reason why not.

Is this going out live?
No, Homer, very few cartoons are broadcast live - it's a terrible strain on the animator's wrist
  • Comment on Re: Rounding to a Given Number of Significant Figures Rather Than Decimal Places
  • Download Code

Replies are listed 'Best First'.
Re: Re: Rounding to a Given Number of Significant Figures Rather Than Decimal Places
by Clem (Sexton) on Jan 13, 2003 at 14:45 UTC
    Thank you very much for your advice. I have tried your suggestion and it does indeed work very well. However, it has made me realise that my question was ill considered. My problem is actually as follows: I have an 8 character wide field into which I must round a number (possibly with a decimal point, possibly not). I need to be able to say, "Take this number, and round it so that, including it's decimal point, if it has one, and any zeros, is only 8 characters long". I have tried using $num = sprintf "%8g", $num; but this seems to give me a 7 character long number with a space at the front. Thank you once again for your advice and any further help you can offer.
      $num = sprintf "%8g", $num;
      Almost. shell$> perldoc -f sprintf reveals this little snippet:
      # Format number with up to 8 leading zeroes $result = sprintf("%08d", $number);
      Change the "d" to a "g" (which you had), and you'll be there. You'll probably find you want to do the SigFig rounding first, then format it for display with the sprintf.
      cheers
      davis
      Is this going out live?
      No, Homer, very few cartoons are broadcast live - it's a terrible strain on the animator's wrist
        Sorry to be dim but with the following lines of code: $_ = FormatSigFigs($_,8); my $clem = sprintf("%08g", $_); print "$clem\n"; and starting with the number 1298.844667, I get the result 01298.84 and not 1298.845, as desired. Any ideas? Thanks again for your help.
        Sorry to be a bit dim but, with the following lines of code:
        $_ = FormatSigFigs($_,8); my $clem = sprintf("%08g", $_); print "$clem\n";
        and the number 1298.844667 as input, I get the output 01298.84 and not 1298.845, which is what I want.
        Any ideas?
        Thanks again for your help.

        Edit: larsen. Added <code> tags and some minor formatting.

      In that case, to a first approximation you could do something like the following:

      #! /usr/bin/perl -w use strict; while( <DATA> ) { chomp; my $nr = squeeze($_); print "[$nr] $_\n"; } sub squeeze { my $n = sprintf( '%0.8f', $_[0] ); $n =~ s/^0//; substr( $n, 0, 8 ); } __DATA__ 12345678901234567890 1234567890 1234567.0 1234567.9 123456.789012345 12345 123.4567 123.4 .1 .1234567890 0.00000999999

      Then again, the few test cases here reveal a certain number of bugs. I contend that the results to squeeze() contain a bug, in that 1234567.0 and 1234567.9 return the same results, but in truth the latter should return 1234568. I don't know whether you will hit these borderline cases or not.

      Maybe there's yet another module that deals with your problem.

      <update>In response to gjb's remark about whether this code is a good idea or not, I was trying to point out the folly of storing numbers in fixed-width fields. The idea being that when you see what this outputs, maybe you better start thinking about overflow conditions. As I don't know the domain. I can't really deal with in a satisfactory matter (at least to my standards). I prefer to let the code stand as it is.</update>


      print@_{sort keys %_},$/if%_=split//,'= & *a?b:e\f/h^h!j+n,o@o;r$s-t%t#u'

        I don't really think that this piece of code is such a good idea: representing 12345678901234567890 as 12345678 doesn't make sense in any situation I can think of.

        I'd suggest the author to check what he's written and either to modify or motivate this program.

        Update: Fair enough given the update grinder added.

        Just my 2 cents, -gjb-

      Heh. Try doing something like:
      my $num = 12345.678; # a total of 9 characters if (length $num > 8) { if ($num =~ /\./) # If there's a decimal point { # Put it to seven significant figures } else { # Put it to eight significant figures } }
      Another way to test for the decimal point, if you wanted to be purely math-based, could be if ($num == round($num)).

      ------
      We are the carpenters and bricklayers of the Information Age.

      Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

        What about a minus/plus sign in front of the number? And what if the number is longer than 8 characters, like 1234567890?

        I think there are a lot of corner cases lurking around in this problem ... :)

        -- Hofmator

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://226455]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (3)
As of 2024-04-19 01:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found