in reply to Re^2: [s]printf %d oddity
in thread [s]printf %d oddity

This is *just* what happens when you convert between binary and decimal - see the links I provided in the post below.

update:
Think of it like this: decimal floats are inaccurate too, since they can't represent a rational number like 1/3 in finite notation:

1/3 = 0.333333333333333333....

If all arithmatic was done using decimal notation, assuming a maximum of 10 places you get:

$x = 1/3; # 0.3333333333 $y = $x * 3; $y == 1 -> false # $y == 0.9999999999

The same thing happens here, only since humans have a hard time thinking in floating binary, it's much harder to predict where.

Replies are listed 'Best First'.
Re^4: [s]printf %d oddity
by astroboy (Chaplain) on May 20, 2005 at 10:13 UTC
    Ok, well since I've had to do most of my financial calculations in PL/SQL in the past since I was dealing with Oracle Financials, I thought I'd try it out:
    create or replace function test return varchar2 as begin if (8.78 * 100 = 878) then return 'ok'; end if; return 'not ok'; end; /
    SQL> select test from dual; TEST ------------------------------------------------------------------- ok
    They're dealing with binary and decimal conversions. Now granted, I've had to deal with rounding errors in the past, but not for trivial calculations like the one above. I still contend that in this example, where we're not dealing with repeating numbers, that a language should be able to get it right
      Sure it would be nice if this would always work, but that's why it's recommended to always use sprintf() to round before comparing if you're working with floating point numbers. You won't know when it will break otherwise. Keep in mind that perl uses the underlying C compiler's native float.

      By the way, how do you know that 8.78 isn a repeating finite number in binary?

      On my machine:

      #!/usr/local/bin/perl -w use strict; my $x = pack("F",8.78); print(unpack("B*",$x)); __OUTPUT__ 1000111111000010111101010010100001011100100011110010000101000000

      Now, if I only knew which part was what :-)

      updated: s/8.98/8.78/

      Trivial? That would be some assembler