in reply to Re: Behaviour of int() unexpected
in thread Behaviour of int() unexpected

Internally, all floating points are represented as a binary fraction (effectively)

Interesting. To me, this makes no sense at all. Up to this point, I belived that a float point value such as 8.95 is stored as a plain integer like 895 along with an exponent which is -2. So, to turn that into the original number, you print "895" and then move the decimal point to the left by two spaces. But that's apparently not how it's done. But this would be the most logical way to encode a float number if you ask me.

Convert 8.95 to 8.9499999999999992894572642399 and store it like that. Who came up with this "standard" and WHY?????

Replies are listed 'Best First'.
Re^3: Behaviour of int() unexpected
by ikegami (Patriarch) on Mar 11, 2025 at 00:41 UTC

    Oh, and how do you imagine 1/3 being stored in your model? There's no pair of integers m and e where m * 10^e gives 1/3. Your model doesn't work for periodic numbers.

    You could approximate it. You could use m = 3333333333 and e = -10, but it's not quite exact.

    And guess what. That's exactly the problem faced here.

    The number is stored as two integers. But it's not a power of 10; it's a power of 2.

    So, in this case, you need a pair of integers m and e where m * 2^e = 895/100. There is no such pair of integers because 895/100 is periodic in binary.

    So the computer used m = 0x11E66666666666 and e = -49, but it's not quite exact.

    $ perl -Mv5.14 -e'say 8.95 == 0x11E66666666666 * 2**(-49) ? 1 : 0' 1 $ perl -Mv5.14 -e'say sprintf "%.751g", 0x11E66666666666 * 2**(-49)' 8.949999999999999289457264239899814128875732421875 $ perl -Mv5.14 -e'say sprintf "%.751g", 8.95' 8.949999999999999289457264239899814128875732421875

    If you want to be picky, an IEEE double is actually stored as follows to get a couple of extra bits:

    ( -1 )^s * ( 1 + ( m * 2^( -52 ) ) * 2^( e - 1023 ) )

      Okay, so if 1/3 gives us a problem, why didn't they introduce another variable such as r which would count the repeating digits at the end?

      So, a number like 23.676767676767 might be represented as m = 2367 e = -2 r = 2 where r tells us to repeat the last two digits to infinity. Or 1/3 would be stored as m = 3 e = -1 r = 1

      In a 64-bit variable, it would be 4 bits for r, 10 bits for e, and 48 bits for m. Then there would be one bit for mantissa's sign and another bit for exponent's sign. Total 64 bits.

      Mantissa would go from -281474976710656 to +281474976710656
      Exp would go from -1024 to +1024
      Rep would go from 0 to 15

        IIRC do some languages offer a data type for fractions.

        So 4/6 is stored as a tuple (2,3)

        I think Raku is one of them.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery

        It would be very expensive to perform math operations on a number stored that way, it at all possible.

        Assuming it's possible, even straight up comparisons would be super expensive. If you multiply m = 3 e = -1 r = 1 by three, you get m = 9 e = -1 r = 1. But that's equal to m = 1 e = 0 r = 0. Should every math operation perform this expensive normalization? Should comparison? Neither are appealing.

        And to what end? To avoid rounding? You'll need to do that anyway when r != 0, and you usually want to do that regardless. To make int work better? int will still give the wrong result in the example above (m = 9 e = -1 r = 1) without normalization.

Re^3: Behaviour of int() unexpected
by syphilis (Archbishop) on Mar 11, 2025 at 03:30 UTC
    But this would be the most logical way to encode a float number if you ask me.

    What you describe is essentially what Math::BigFloat does.
    If you use Math::BigFloat, then you won't be disappointed by the results you get. (Performance is comparatively sluggish - though perhaps not to an extent that it becomes an issue.)

    Cheers,
    Rob
Re^3: Behaviour of int() unexpected
by LanX (Saint) on Mar 11, 2025 at 03:48 UTC
    > plain integer like 895 along with an exponent which is -2.

    That's decimal logic not binary.

    Number crunching in decimal is a waste of digital resources.°

    And 10 is not a universal constant, just the number of the long things we use to hold our hamburgers.

    See also:

    Humans have too many fingers

    for a more detailed discussion.

    °) Unless you invent affordable micro transistors with 10-ary states.

    Cheers Rolf
    (addicted to the Perl Programming Language :)
    see Wikisyntax for the Monastery

      Number crunching in decimal is a waste of digital resources.

      Most of the time, yes. But there are certainly use cases, especially when using BCD (binary-coded decimal). When using very slow hardware, the tradeoff between using BCD and converting to/from binary can be significant, think battery powered digital watch.

      It's also quite useful when dealing with financial data and other "human math problems" (pocket calculators, etc). Yes, you still get rounding errors and stuff, but they are the rounding errors that humans expect in the decimal system we are used to (like on 10/3), not the ones binary calculation generate.

      Even the x86 architecture has (had?) very basic BCD support

      PerlMonks XP is useless? Not anymore: XPD - Do more with your PerlMonks XP
      Also check out my sisters artwork and my weekly webcomics
        > It's also quite useful when dealing with financial data

        Financial data, like banks, tax authorities, etc have fixed rules about precision and rounding to avoid ambiguity. And these date back to integer times.

        You can just calculate in integer if you use cents or the required fractions of them and respect the rounding rules.

        IOW instead of calculating with a float 5,02€ you calculate with 502¢ or 5020 deci-cents.

        You only need to "shift" the point once you're putting out the result (best string wise)

        I haven't seen a case yet where this didn't work.

        Cheers Rolf
        (addicted to the Perl Programming Language :)
        see Wikisyntax for the Monastery