in reply to Negative zero? There's gotta be a sprintf that undoes that, right?

Hey!
In the original post I could read this : "rounded float". The problem is that sprintf does not really "round" from a mathematical point of view. You can achieve a quick and dirty rounding simply by using:
int($example*100000)/100000
...in your sprintf

It is not strictly a rounding operation from a math point of view but it should do the trick.
  • Comment on Re: Negative zero? There's gotta be a sprintf that undoes that, right?
  • Download Code

Replies are listed 'Best First'.
Re^2: Negative zero? There's gotta be a sprintf that undoes that, right?
by suaveant (Parson) on Dec 13, 2007 at 14:37 UTC
    Oh, but it does...

    perl -e 'printf "%.1f %.1f\n",0.05,0.049' 0.1 0.0
    your method is good for truncating... course, with a suitable addition of .5 it rounds.

                    - Ant
                    - Some of my best work - (1 2 3)

Re^2: Negative zero? There's gotta be a sprintf that undoes that, right?
by rgiskard (Hermit) on Dec 13, 2007 at 14:50 UTC
    I would love to read what you mean by "sprintf does not really 'round' from a mathematical point of view". I have observed that sprintf will round up from the number right outside of the requested precision. For example, from my perspective, the following list when rounded to 5 decimal places should end in 70 (i.e. 1.777695 rounds to 1.77770), do note that it *does not* always work that way.
    @nums= ( 1.777695, 1.77769501, 1.667695, 1.66769501, 1.557695, 1.55769501, 1.000695, 1.00069500001, 1.000696 ); foreach (@nums) { print sprintf "%7.5f\n", $_; }
    Output on Perl 5.6.1: note: it usually rounds if the next significant digit is 5 or greater
    1.77770
    1.77770
    1.66769
    1.66770
    1.55770
    1.55770
    1.00069
    1.00070
    1.00070
    
    Output on Perl 5.8.5: note: it usually rounds if the next significant digit is 5 or greater
    1.77770
    1.77770
    1.66770
    1.66770
    1.55770
    1.55770
    1.00069
    1.00070
    1.00070
    
    Given the example, I would love for you to elaborate on your sprintf opinion.

      Yet another person who needs to be reminded that floating point can't represent most decimal values exactly? Note the following about the two numbers that exhibit your problem:

      printf "%.20f\n", 1.667695; printf "%.20f\n", 1.000695; __END__ 1.66769499999999990000 1.00069499999999990000

      So, I'm not surprised that those don't get rounded up to end in "70", since they are each less than 1.___695. They are as close to 1.___695 as the chosen floating point representation can get, but they are almost always going to be just above or just below and so how they round has to do with whether they can be more closer approximated by an n/2**p that is just above the desired value or just below the desired value.

      Now, Perl has been playing more and more tricks about ignoring the last bit or two if it would result in "0000001" or "9999999" to more effectively hide this fact from more people (in part because they tend to complain when they first discover it). It appears that perhaps your Perl 5.008_005 has added one more such trick (or gotten a bit more aggressive with an existing trick), though my Perl 5.008_008 agrees with both of our Perls 5.006_001.

      An interesting pattern is that pretty consistently about 72.5% of the numbers round as one would expect and only about 27.5% round lower due to this floating point short-coming. Update: I finally varied enough parts to find a bunch of ranges with 53% "normal" and 47% "low" or 85% "normal" and 15% "low"...

      Perl's being "smart" is a bit annoying here because Perl used to be more easily more useful for getting an understanding of this stuff. For example, perl4's output for my sample program is:

      1.66769499999999993000 1.00069499999999989000

      which gives us more information about how close the floating point values are able to get to our desired values. This also gives us a clue as to why the second number has "the problem" for both of your Perls while the first doesn't; the second is not as close. Update: And, I suspect that my sample program run on your Perl 5.008_005 will give 5 trailing zeros in the output unlike the 4 trailing zeros I got with my Perls v5 and the 3 trailing zeros I got with Perl4.

      - tye