in reply to Re^7: RFC: Large Floating Point Numbers - Rounding Errors
in thread RFC: Large Floating Point Numbers - Rounding Errors

Sadly, Solaris doesn't implement _controlFP (nor does Inline exist in this environment). There is a Solaris method by which I can ask what the rounding method is on this system, just no way to set it.

Like I said, something bigger is wrong here, and no, I shouldn't have to use a string manipulation program to deal with this, but ... I'm pretty stuck otherwise.
  • Comment on Re^8: RFC: Large Floating Point Numbers - Rounding Errors

Replies are listed 'Best First'.
Re^9: RFC: Large Floating Point Numbers - Rounding Errors
by BrowserUk (Patriarch) on Sep 08, 2011 at 22:12 UTC
    Sadly, Solaris doesn't implement _controlFP()

    In that case, maybe something like this would work for you?

    sub rnd{ my( $p, $n ) = @_; return sprintf "%.${p}f", $n + "0.5e-$p" };; print $_, ': ', rnd( 5, $_ ) for 0.000005, 0.000015, 0.000025, 0.000035, 0.000045, 0.000055, 0.000065, 0.000075, 0.000085, 0.000095;; 5e-006 : 0.00001 1.5e-005 : 0.00002 2.5e-005 : 0.00003 3.5e-005 : 0.00004 4.5e-005 : 0.00005 5.5e-005 : 0.00006 6.5e-005 : 0.00007 7.5e-005 : 0.00008 8.5e-005 : 0.00009 9.5e-005 : 0.00010

    Even if it isn't faster than your code -- which instinct tells me it should be -- then it is at least a darn sight clearer :)


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      It's clear enough to plainly see that you are adding something to the number, then rounding it, which means that in any thing close to 0.49e-${p}, you'll force a round-up, so often wrong, in the other direction.

      Being 9.0e-5 + 0.5e-5 is 9.5e-5 -- So, you are forcing it to always add "up".

      Just adding a single 0.00009 at the end of your code, shows how bad this can be. However, the same problem also happens (with a smaller error area) if you try a higher exponent -- it simply intentionally inserts an error, which is a really dangerous way to try to correct a problem.

      sub rnd{ my( $p, $n ) = @_; return sprintf "%.${p}f", $n + "0.5e-$p" };; print $_, ': ', rnd( 5, $_ ), qq{\n} for 0.000005, 0.000015, 0.000025, 0.000035, 0.000045, 0.000055, 0.000065, 0.000075, 0.000085, 0.000095, 0.00009;; __DATA__ 5e-06: 0.00001 1.5e-05: 0.00002 2.5e-05: 0.00003 3.5e-05: 0.00004 4.5e-05: 0.00005 5.5e-05: 0.00006 6.5e-05: 0.00007 7.5e-05: 0.00008 8.5e-05: 0.00009 9.5e-05: 0.00010 9e-05: 0.00010

        Sorry to reply again, but I just realised that there was a think-o in my post above which corrected, addresses your objection.

        "0.5e-$p" should be "0.00000000000005e-$p":

        sub rnd{ my( $p, $n ) = @_; return sprintf "%.${p}f", $n + "0.00000000000005e-$p" };; print $_, ': ', rnd( 5, $_ ) for 0.000005, 0.000015, 0.000025, 0.00003, 0.000031, 0.000032, 0.000033, 0.000034, 0.0000341, 0.0000342, 0.0000343,0.0000344, 0.0000345, 0.0000346, 0.0000347, 0.0000348, 0.0000349, 0.00003499, 0.000034999, 0.0000349999, 0.00003499999, 0.0000349999 +99, 0.0000349999999, 0.00003499999999, 0.000034999999999, 0.000035, 0.000045, 0.000055, 0.000065, 0.000075, 0.000085, 0.00009, 0.000091, 0.000092, 0.000093, 0.000094, 0.0000941, 0.0000942, 0.0000943,0.0000944, 0.0000945, 0.0000946, 0.0000947, 0.0000948, 0.0000949, 0.00009499, 0.000094999, 0.0000949999, 0.00009499999, 0.0000949999 +99, 0.0000949999999, 0.00009499999999, 0.000094999999999, 0.000095,;; c:\test>junk 5e-006: 0.00001 1.5e-005: 0.00002 2.5e-005: 0.00003 3e-005: 0.00003 3.1e-005: 0.00003 3.2e-005: 0.00003 3.3e-005: 0.00003 3.4e-005: 0.00003 3.41e-005: 0.00003 3.42e-005: 0.00003 3.43e-005: 0.00003 3.44e-005: 0.00003 3.45e-005: 0.00003 3.46e-005: 0.00003 3.47e-005: 0.00003 3.48e-005: 0.00003 3.49e-005: 0.00003 3.499e-005: 0.00003 3.4999e-005: 0.00003 3.49999e-005: 0.00003 3.499999e-005: 0.00003 3.4999999e-005: 0.00003 3.49999999e-005: 0.00003 3.499999999e-005: 0.00003 3.4999999999e-005: 0.00003 3.5e-005: 0.00004 4.5e-005: 0.00005 5.5e-005: 0.00006 6.5e-005: 0.00007 7.5e-005: 0.00008 8.5e-005: 0.00009 9e-005: 0.00009 9.1e-005: 0.00009 9.2e-005: 0.00009 9.3e-005: 0.00009 9.4e-005: 0.00009 9.41e-005: 0.00009 9.42e-005: 0.00009 9.43e-005: 0.00009 9.44e-005: 0.00009 9.45e-005: 0.00009 9.46e-005: 0.00009 9.47e-005: 0.00009 9.48e-005: 0.00009 9.49e-005: 0.00009 9.499e-005: 0.00009 9.4999e-005: 0.00009 9.49999e-005: 0.00009 9.499999e-005: 0.00009 9.4999999e-005: 0.00009 9.49999999e-005: 0.00009 9.499999999e-005: 0.00009 9.4999999999e-005: 0.00009 9.5e-005: 0.00010

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
        it simply intentionally inserts an error, which is a really dangerous way to try to correct a problem.

        Hm. Sorry, but rounding for output is a cosmetic operation. And solutions to cosmetic operations are never "dangerous".

        If the accuracy of the value was important enough to be dangerous, then you wouldn't be rounding it. Rather you'd be printing it to it's full internal accuracy with an estimate of error deviation; or seeking a method of achieving higher accuracy storage.

        As is, you are discarding up to an extra 18 digits of accuracy for the sake of cosmetic appearance.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.