in reply to Maintain accuracy of floating point numbers in simple arithmetic operation

You could avoid doing math all together and treat the problem as a string manipulation exercise:

#! perl -slw use strict; while( <DATA> ) { chomp; printf "Before '%s' becomes ", $_; s[ ( \d+ )+ (?: \. ( \d{0,2} ) ( \d* ) )? % ]{ local $^W; my $n = substr( $2 . '00', 0, 2 ); ($1||'') . $n . ( length($3) ? ".$3" : '' ); }xe; print "'$_'"; } __DATA__ 0.781063003540039% 2.25% 1.455% 4.9% 0.79% 75% 1.15% 0.45999999999999996% 0.9199999999999999% 0.22999999999999998% 1.3%

Gives:

c:\test>junk4 Before '0.781063003540039%' becomes '78.1063003540039' Before '2.25%' becomes '225' Before '1.455%' becomes '145.5' Before '4.9%' becomes '490' Before '0.79%' becomes '79' Before '75%' becomes '7500' Before '1.15%' becomes '115' Before '0.45999999999999996%' becomes '45.999999999999996' Before '0.9199999999999999%' becomes '91.99999999999999' Before '0.22999999999999998%' becomes '22.999999999999998' Before '1.3%' becomes '130'

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.
"Too many [] have been sedated by an oppressive environment of political correctness and risk aversion."

Replies are listed 'Best First'.
Re^2: Maintain accuracy of floating point numbers in simple arithmetic operation
by OfficeLinebacker (Chaplain) on Jun 13, 2007 at 16:20 UTC
    ++Browser,

    I must admit your solution takes the form of a brain teaser for me. I'll limit my query to the first thing that I can't figure out off the top of my head, which is why the + after the first set of parens? Isn't it redundant, given the + after the \d within?

    In general, IMHO, I think an explanation of your solution would be helpful not only to me, but to others who may come across this thread, especially in the future, perhaps from a search.

    EDIT: I guess what I don't understand is

    • The first thing with the +
    • Why test for $1 when the assumption is that there is always a digit before the decimal (w/ your program, Before '.6789%' becomes '.678900')
      • Note, that assumption is OK, for this application.

    EDIT 2: I see now that the test is not for definedness, but for 0, because you don't want to make 0.779999% become 077.9999.


    I like computer programming because it's like Legos for the mind.
      ... why the + after the first set of parens?

      Because I made a mistake and didn't notice because I was getting the right results. It is redundant and removing it makes no difference--'cept maybe it'll run a insy winsy bit quicker? :)

      There is a second 'artifact' in the replacement. ($1||'') can become just $1.

      I was attempting to avoid the need to suppress warnings, but it turns the code it a mess of bracketed ||s and ternaries; or a long if then else chain. Warnings are optional and turning them off, as an informed decision to avoid complicated code, is (IMO) legit. So I chose the cleaner option. You can replace local $^W; with no warnings 'uninitialised'; or the chain of defined and length tests if you prefer.

      Does this explain it?

      #! perl -slw use strict; while( <DATA> ) { chomp; printf "Before '%s' becomes ", $_; s[ ( \d+ ) ## Grab any digits before a decimal point (?: \. ## If there is a decimal point ( \d{0,2} ) ## Try grab two digits after it ( \d* ) ## And any more into another capture )? ## All conditionally % ## And finally... ]{ local $^W; ## I know some of the captures will be emp +ty. ## Pad (trailing zeros) the digits being moved to ensure exact +ly 2 my $n = substr( $2 . '00', 0, 2 ); ## Reassemble the number from ## Any digits previously before the decimal point ## The two digits being moved ## A decimal point and the remaining digits if there are +any. $1 . $n . ( length($3) ? ".$3" : '' ); }xe; print "'$_'"; } __DATA__

      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.

      Updates after the fact will often not be noticed unless you /msg the intended recipient.

      I used your tests which did not include a '.nnn%' example so that possibility didn't get tested. If you were my boss, I would probably deserve admonishment.

      This, as with most posts, is intended to give you ideas for solving your problem, not a fully tested piece of code that you can drop into you codebase for free.