in reply to Integers sometimes turn into Reals after substraction

This misunderstanding is common to many languages not only Perl, because people expect a decimal calculation behind decimal representation.

But 4/25 isn't a number which can be accurately represented in a binary system and rounding errors come into play.

See also Humans have too many fingers

update

To elaborate further

(4*1000)/25 is an integer but 1000*(4/25) is a float with a very tiny error in the last bits of the mantissa.

Perl will still print this float like an integer because the error is too small.

But after the subtraction the leading zeros in the mantissa will cause a left shift (with adjustment of the exponent).

This means the error shifts out of Perl's tolerance margin and is printed as (decimal) fraction.

Cheers Rolf
(addicted to the Perl Programming Language and ☆☆☆☆ :)
Je suis Charlie!

  • Comment on Re: Integers sometimes turn into Reals after substraction

Replies are listed 'Best First'.
Re^2: Integers sometimes turn into Reals after substraction
by rduke15 (Beadle) on May 14, 2016 at 11:50 UTC
    Well, I understand that. The problem is that it is inconsistent. The result depends not only on the type of calculation which led to $x2:
    perl -e '$x1=256080; $x2 = 1000 * ( 4*60 + 18 + 4/25 ); $diff=$x2-$x1; print "x1=$x1, x2=$x2, diff=$diff\n";'
    x1=256080, x2=258160, diff=2080.00000000003
    perl -e '$x1=256080; $x2 = 1000 * ( 4*60 + 18 ) + 1000*(4/25); $diff=$x2-$x1; print "x1=$x1, x2=$x2, diff=$diff\n";'
    x1=256080, x2=258160, diff=2080

    but also on the value of $x1 which has never been calculated.

    perl -e '$x1=25608; $x2 = 1000 * ( 4*60 + 18 + 4/25 ); $diff=$x2-$x1; print "x1=$x1, x2=$x2, diff=$diff\n";'
    x1=25608, x2=258160, diff=232552
      Have you seen the update in my reply?

      Floats are automatically adjusted to avoid leading zeros in the mantissa.

      update

      Think float, this

      x1 = 256080 x2 = 258160 diff = 2080.00000000003

      really just means (in slightly inaccurate decimal interpretation)

      x1 = 2.56080 e5 x2 = 2.5816000000000003 e5 (error ignored when printed) diff = 2.08000000000003 e3 (error visible when printed)

      As you can see the error (here decimal 3) is shifted to the left and out of error margin into printed "visibility".

      update

      after firing up my laptop, here a proof of concept

      DB<115> $x1 = 2.56080e5 => 256080 DB<116> $x2 = 2.5816000000000003e5 => 258160 # within error margin, ignored in normal di +splay DB<117> printf '%.11f', $x2 258160.00000000003 # forced into visibility, hence $x2 NOT an +integer DB<118> $x2-$x1 => 2080.00000000003 # error can't be ignored any more

      Cheers Rolf
      (addicted to the Perl Programming Language and ☆☆☆☆ :)
      Je suis Charlie!

        Liked your post! I've been looking at illustrated perlguts,

        If my limited understanding is correct, then Perl keeps Integer Values IV's as a separate type from floats (NV's).
        This 4/25 stuff creates a NV. (1000*4/25) would still be an integer, an IV. So aside from the output precision issues, a root problem is creating an NV in the first place? If the math never used anything but all integer values, then this output precision issue doesn't appear? Right or not?

        Thank you for the very detailed replies in this thread. I will now use sprintf "%$x.0f" much more often to not be bitten again...