Skip to main content
Engineering LibreTexts

15.3: With Floats, Printing Is Inexact

  • Page ID
    43752
  • \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

    One of the biggest trap we learned with above example is that despite the fact that 0.1 is printed '0.1' as if it were exact, it’s not. The name absPrintExactlyOn:base: used internally by printString is a bit confusing, it does not print exactly, but it prints the shortest decimal representation that will be rounded to the same Float when read back (Pharo always converts the decimal representation to the nearest Float).

    Another message exists to print exactly, you need to use printShowingDecimalPlaces: instead. As every finite Float is represented internally as a Fraction with a denominator being a power of 2, every finite Float has a decimal representation with a finite number of decimals digits (just multiply numerator and denominator with adequate power of 5, and you’ll get the digits). Here you go:

    0.1 asTrueFraction denominator highBit.
        → 56
    

    This means that the fraction denominator is \( 2^{55} \) and that you need 55 decimal digits after the decimal point to really print internal representation of 0.1 exactly.

    0.1 printShowingDecimalPlaces: 55.
        → '0.1000000000000000055511151231257827021181583404541015625'
    

    And you can retrieve the digits with:

    0.1 asTrueFraction numerator * (5 raisedTo: 55).
        → 1000000000000000055511151231257827021181583404541015625
    

    You can just check our result with:

    1000000000000000055511151231257827021181583404541015625/(10 raisedTo: 55) =
        0.1 asTrueFraction
        → true
    

    You see that printing the exact representation of what is implemented in machine would be possible but would be cumbersome. Try printing 1.0e-100 exactly if not convinced.


    This page titled 15.3: With Floats, Printing Is Inexact is shared under a CC BY-SA 3.0 license and was authored, remixed, and/or curated by Alexandre Bergel, Damien Cassou, Stéphane Ducasse, Jannik Laval (Square Bracket Associates) via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.