Doing the 0.1-trick in C++

Discussion in 'C++' started by Stefan Ram, Mar 16, 2013.

  1. Stefan Ram

    Stefan Ram Guest

    When explaining the meaning of »0.1« in Java, I use a trick
    to exhibit the value of the internal representation of 0.1:

    public class Main
    { public static void main( final java.lang.String args[] )
    { java.lang.System.out.println( new java.math.BigDecimal( 0.1 )); }}

    0.1000000000000000055511151231257827021181583404541015625

    Is there a similar possibility in C++, too?
     
    Stefan Ram, Mar 16, 2013
    #1
    1. Advertising

  2. Stefan Ram

    Stefan Ram Guest

    Andy Champ <> writes:
    >>0.1000000000000000055511151231257827021181583404541015625
    >>Is there a similar possibility in C++, too?

    >std::cout << std::setprecision(50) << 0.1 << std::endl;


    Here, this gives

    0.1000000000000000055511151231257827021181583404541

    . It seems to miss the last 6 digits, but is quite close.
    The ending of the first numeral in »625« hints at a binary
    fraction.
     
    Stefan Ram, Mar 16, 2013
    #2
    1. Advertising

  3. Stefan Ram

    Ian Collins Guest

    Stefan Ram wrote:
    > Andy Champ <> writes:
    >>> 0.1000000000000000055511151231257827021181583404541015625
    >>> Is there a similar possibility in C++, too?

    >> std::cout << std::setprecision(50) << 0.1 << std::endl;

    >
    > Here, this gives
    >
    > 0.1000000000000000055511151231257827021181583404541
    >
    > . It seems to miss the last 6 digits, but is quite close.
    > The ending of the first numeral in »625« hints at a binary
    > fraction.


    std::cout << std::setprecision(60) << 0.1 << std::endl;

    :)

    --
    Ian Collins
     
    Ian Collins, Mar 16, 2013
    #3
  4. Stefan Ram

    SG Guest

    Am 16.03.2013 23:07, schrieb Ian Collins:
    > Stefan Ram wrote:
    >> Andy Champ <> writes:
    >>>> 0.1000000000000000055511151231257827021181583404541015625
    >>>> Is there a similar possibility in C++, too?
    >>> std::cout << std::setprecision(50) << 0.1 << std::endl;

    >>
    >> Here, this gives
    >>
    >> 0.1000000000000000055511151231257827021181583404541
    >>
    >> . It seems to miss the last 6 digits, but is quite close.
    >> The ending of the first numeral in »625« hints at a binary
    >> fraction.

    >
    > std::cout << std::setprecision(60) << 0.1 << std::endl;
    >
    > :)


    Right. Though, I do wonder how to determine the lowest possible
    precision value while the result will still accurately reflect the value
    of the floating point number. So far, I used
    numeric_limits<double>::digits+3 (see http://ideone.com/frexSH )
     
    SG, Mar 18, 2013
    #4
  5. Stefan Ram

    Öö Tiib Guest

    On Monday, 18 March 2013 15:03:35 UTC+2, SG wrote:
    > Right. Though, I do wonder how to determine the lowest possible
    > precision value while the result will still accurately reflect the value
    > of the floating point number. So far, I used
    > numeric_limits<double>::digits+3 (see http://ideone.com/frexSH )


    std::numeric_limits<double>::digits10.
     
    Öö Tiib, Mar 18, 2013
    #5
  6. Stefan Ram

    SG Guest

    Am 18.03.2013 17:36, schrieb Öö Tiib:
    > On Monday, 18 March 2013 15:03:35 UTC+2, SG wrote:
    >> Right. Though, I do wonder how to determine the lowest possible
    >> precision value while the result will still accurately reflect the value
    >> of the floating point number. So far, I used
    >> numeric_limits<double>::digits+3 (see http://ideone.com/frexSH )

    >
    > std::numeric_limits<double>::digits10.


    No.

    digits10 is the number of decimal digits that can be represented exactly
    as floating point number (15 for an IEEE-754 64bit float)

    Slightly higher: max_digits10 is the number of decimal digits one needs
    to uniquely identify a floating point value's bit pattern excluding bit
    patterns for +/-0, +/-Inf and NaN (17 for an IEEE-754 64bit float).

    But this thread is about _exact_ decimal representations. Not
    representations that are close enough. Consider this:

    binary decimal
    ---------------
    1,1 1,5
    1,01 1,25
    1,001 1,125
    1,0001 1,0625
    1,00001 1,03125

    So, you need at least the same amount of digits as the amount of bits to
    be able to represent the _same_ value. That was my motivation to use
    numeric_limits<T>::digits as a starting point (53 for an IEEE-754 64bit
    float).
     
    SG, Mar 18, 2013
    #6
  7. On 3/18/2013 1:07 PM, SG wrote:
    > Am 18.03.2013 17:36, schrieb Öö Tiib:
    >> On Monday, 18 March 2013 15:03:35 UTC+2, SG wrote:
    >>> Right. Though, I do wonder how to determine the lowest possible
    >>> precision value while the result will still accurately reflect the value
    >>> of the floating point number. So far, I used
    >>> numeric_limits<double>::digits+3 (see http://ideone.com/frexSH )

    >>
    >> std::numeric_limits<double>::digits10.

    >
    > No.
    >
    > digits10 is the number of decimal digits that can be represented exactly
    > as floating point number (15 for an IEEE-754 64bit float)
    >
    > Slightly higher: max_digits10 is the number of decimal digits one needs
    > to uniquely identify a floating point value's bit pattern excluding bit
    > patterns for +/-0, +/-Inf and NaN (17 for an IEEE-754 64bit float).
    >
    > But this thread is about _exact_ decimal representations. Not
    > representations that are close enough. Consider this:
    >
    > binary decimal
    > ---------------
    > 1,1 1,5
    > 1,01 1,25
    > 1,001 1,125
    > 1,0001 1,0625
    > 1,00001 1,03125
    >
    > So, you need at least the same amount of digits as the amount of bits to
    > be able to represent the _same_ value. That was my motivation to use
    > numeric_limits<T>::digits as a starting point (53 for an IEEE-754 64bit
    > float).


    But... Does 'setprecision' (that Andy recommended, and from which all
    this 'digits' conversation started) have anything to do with the binary
    representation? Or does it have everything to do with the decimal
    output? IOW, why care about 'digits' AFA 'setprecision' is concerned?

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Mar 18, 2013
    #7
  8. Stefan Ram

    SG Guest

    Am 18.03.2013 18:53, schrieb Victor Bazarov:
    > On 3/18/2013 1:07 PM, SG wrote:
    >> Am 18.03.2013 17:36, schrieb Öö Tiib:
    >>> On Monday, 18 March 2013 15:03:35 UTC+2, SG wrote:
    >>>> Right. Though, I do wonder how to determine the lowest possible
    >>>> precision value while the result will still accurately reflect the
    >>>> value
    >>>> of the floating point number. So far, I used
    >>>> numeric_limits<double>::digits+3 (see http://ideone.com/frexSH )
    >>>
    >>> std::numeric_limits<double>::digits10.

    >>
    >> No.
    >>
    >> digits10 is the number of decimal digits that can be represented exactly
    >> as floating point number (15 for an IEEE-754 64bit float)
    >>
    >> Slightly higher: max_digits10 is the number of decimal digits one needs
    >> to uniquely identify a floating point value's bit pattern excluding bit
    >> patterns for +/-0, +/-Inf and NaN (17 for an IEEE-754 64bit float).
    >>
    >> But this thread is about _exact_ decimal representations. Not
    >> representations that are close enough. Consider this:
    >>
    >> binary decimal
    >> ---------------
    >> 1,1 1,5
    >> 1,01 1,25
    >> 1,001 1,125
    >> 1,0001 1,0625
    >> 1,00001 1,03125
    >>
    >> So, you need at least the same amount of digits as the amount of bits to
    >> be able to represent the _same_ value. That was my motivation to use
    >> numeric_limits<T>::digits as a starting point (53 for an IEEE-754 64bit
    >> float).

    >
    > But... Does 'setprecision' (that Andy recommended, and from which all
    > this 'digits' conversation started) have anything to do with the binary
    > representation? Or does it have everything to do with the decimal
    > output? IOW, why care about 'digits' AFA 'setprecision' is concerned?


    I'm not sure if I understand your question. Given the OP's desire to
    display the exact value of a floating point number in decimal, he
    obviously has to pick an "output precision" that is large enough for the
    output to be exact.

    For an exact decimal representation of a radix-2-based floating point
    number x you need max(floor(log10(x)),0)+1 digits before the decimal
    point and about max(numeric_limits<T>::digits-log2(x),0) give or take
    decimal digits after the decimal point, I think.
     
    SG, Mar 18, 2013
    #8
  9. On 3/18/2013 3:37 PM, SG wrote:
    > Am 18.03.2013 18:53, schrieb Victor Bazarov:
    >> On 3/18/2013 1:07 PM, SG wrote:
    >>> Am 18.03.2013 17:36, schrieb Öö Tiib:
    >>>> On Monday, 18 March 2013 15:03:35 UTC+2, SG wrote:
    >>>>> Right. Though, I do wonder how to determine the lowest possible
    >>>>> precision value while the result will still accurately reflect the
    >>>>> value
    >>>>> of the floating point number. So far, I used
    >>>>> numeric_limits<double>::digits+3 (see http://ideone.com/frexSH )
    >>>>
    >>>> std::numeric_limits<double>::digits10.
    >>>
    >>> No.
    >>>
    >>> digits10 is the number of decimal digits that can be represented exactly
    >>> as floating point number (15 for an IEEE-754 64bit float)
    >>>
    >>> Slightly higher: max_digits10 is the number of decimal digits one needs
    >>> to uniquely identify a floating point value's bit pattern excluding bit
    >>> patterns for +/-0, +/-Inf and NaN (17 for an IEEE-754 64bit float).
    >>>
    >>> But this thread is about _exact_ decimal representations. Not
    >>> representations that are close enough. Consider this:
    >>>
    >>> binary decimal
    >>> ---------------
    >>> 1,1 1,5
    >>> 1,01 1,25
    >>> 1,001 1,125
    >>> 1,0001 1,0625
    >>> 1,00001 1,03125
    >>>
    >>> So, you need at least the same amount of digits as the amount of bits to
    >>> be able to represent the _same_ value. That was my motivation to use
    >>> numeric_limits<T>::digits as a starting point (53 for an IEEE-754 64bit
    >>> float).

    >>
    >> But... Does 'setprecision' (that Andy recommended, and from which all
    >> this 'digits' conversation started) have anything to do with the binary
    >> representation? Or does it have everything to do with the decimal
    >> output? IOW, why care about 'digits' AFA 'setprecision' is concerned?

    >
    > I'm not sure if I understand your question. Given the OP's desire to
    > display the exact value of a floating point number in decimal, he
    > obviously has to pick an "output precision" that is large enough for the
    > output to be exact.
    >
    > For an exact decimal representation of a radix-2-based floating point
    > number x you need max(floor(log10(x)),0)+1 digits before the decimal
    > point and about max(numeric_limits<T>::digits-log2(x),0) give or take
    > decimal digits after the decimal point, I think.


    Uh... Wait. To represent 0.1f exactly how many do you need digits?
    max(floor(log10(0.1f)),0)+1 is 1, so you need just 1 digit before the
    decimal separator, and mumeric_limits<float>::digits is 24, so you need
    max(24-log2(0.1),0) *decimal* digits _after_ the decimal separator?
    log2(0.1) is -3.3, so you need 20 (or 21) *decimal* digits? Did I get
    that right?

    V
    --
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Mar 18, 2013
    #9
  10. Stefan Ram

    SG Guest

    Am 18.03.2013 20:47, schrieb Victor Bazarov:
    > On 3/18/2013 3:37 PM, SG wrote:
    >>
    >> For an exact decimal representation of a radix-2-based floating point
    >> number x you need max(floor(log10(x)),0)+1 digits before the decimal
    >> point and about max(numeric_limits<T>::digits-log2(x),0) give or take
    >> decimal digits after the decimal point, I think.

    >
    > Uh... Wait. To represent 0.1f exactly how many do you need digits?
    > max(floor(log10(0.1f)),0)+1 is 1, so you need just 1 digit before the
    > decimal separator, and mumeric_limits<float>::digits is 24, so you need
    > max(24-log2(0.1),0) *decimal* digits _after_ the decimal separator?
    > log2(0.1) is -3.3, so you need 20 (or 21) *decimal* digits? Did I get
    > that right?


    First of all, let me mention that I should have said "you need up to"
    instead of just "you need". Second, 24-(-3.3) is about 27. ;-)

    Your example works as follows:

    0.1 (the decimal number you start with)

    Now, if you write this as binary number you get

    0.000110011001100110011001100110... (with a period of 4 bits)

    Picking the closest IEEE-754 single float value basically means limiting
    the number of consecutive significant bits to 24 with a leading one
    that's not explicitly stored for a normalized number:

    0.000110011001100110011001101 (LSB rounded up)
    ^^^^^^^^^^^^^^^^^^^^^^^^
    (24 significant bits)

    This is the number a float-type variable will actually store.

    Now, since 2 is a factor of 10 we are able to express this number in
    decimal _exactly_ :

    0.100000001490116119384765625

    That's a chunk of 27 consecutive decimal digits that starts and ends
    with something other than zero. So, 27 is in fact the lowest possible
    precision value to pass to the std::setprecision manipulator in order to
    see _this_number_.

    Of course, if you just want to see 0.1 being printed then
    numeric_limits<float>::digits10 is what you would want to use for the
    printing precision. digits10 for float on my machine is 6:

    0.10000000149...
    ^^^^^^
    6 digits

    But this thread is not about that. This thread is about printing the
    _exact_ value of a floating point number in decimal. Why? I guess it's
    just for educational purposes ... to make students understand that
    floating point numbers are typically just approximations and cannot
    exactly represent a number like 0.1. It's not uncommon for students to
    confuse the different kinds of roundings that happen during the
    conversions. OFten students think that writing 0.1 will yield a value of
    type double that exactly represents one tenth. In other cases I noticed
    students were convinced that the number printed on screen in decimal
    represents the exact value the floating point variable stores. We know
    that in both it's a false assumption.

    Cheers!
    SG
     
    SG, Mar 19, 2013
    #10
  11. Stefan Ram

    Stefan Ram Guest

    SG <> writes:
    >_exact_ value of a floating point number in decimal. Why? I guess it's
    >just for educational purposes ...


    Yes.
     
    Stefan Ram, Mar 19, 2013
    #11
  12. Stefan Ram

    SG Guest

    Am 19.03.2013 10:46, schrieb Juha Nieminen:
    > SG <> wrote:
    >> But this thread is about _exact_ decimal representations. Not
    >> representations that are close enough.

    >
    > If we are talking about exact representation, then trying to print the
    > value in base-10 is completely moot because not all IEEE double-precision
    > floating point values can be represented exactly in base-10.


    That's not true. There is always an exact decimal representation with a
    finite number of digits. That's because 2 (the radix of such a floating
    point number representation) is a factor of 10 (the radix of decimal
    representations). It may be very long, but there is one such
    representation. You might find hints for this in my other answers.
    Check'em out and think about it a little more. If you have trouble
    figuring it let me know.
     
    SG, Mar 19, 2013
    #12
  13. On Wed, 20 Mar 2013 08:44:52 +0000, Juha Nieminen wrote:

    > SG <> wrote:
    >>> If we are talking about exact representation, then trying to print the
    >>> value in base-10 is completely moot because not all IEEE
    >>> double-precision floating point values can be represented exactly in
    >>> base-10.

    >>
    >> That's not true. There is always an exact decimal representation with a
    >> finite number of digits. That's because 2 (the radix of such a floating
    >> point number representation) is a factor of 10 (the radix of decimal
    >> representations). It may be very long, but there is one such
    >> representation. You might find hints for this in my other answers.
    >> Check'em out and think about it a little more. If you have trouble
    >> figuring it let me know.

    >
    > Or you could simply print if with "%a" and get a compact accurate ascii
    > representation of the number which is also portable and readable back.


    And how does that hexadecimal representation make it clear that the
    decimal fraction 1/10 can not be accurately stored in a floating point
    variable that uses binary fractions?

    Bart v Ingen Schenau
     
    Bart van Ingen Schenau, Mar 20, 2013
    #13
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Nuri Yilmaz

    A .Net trick everyday!

    Nuri Yilmaz, Jul 28, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    403
    Nuri Yilmaz
    Jul 28, 2004
  2. Nuri YILMAZ

    A .Net trick everday!

    Nuri YILMAZ, Aug 9, 2004, in forum: ASP .Net
    Replies:
    0
    Views:
    443
    Nuri YILMAZ
    Aug 9, 2004
  3. valentin tihomirov

    Is this trick with reset acceptable?

    valentin tihomirov, Apr 11, 2004, in forum: VHDL
    Replies:
    6
    Views:
    564
    Jim Lewis
    Apr 14, 2004
  4. Stephajn Craig

    Perhaps an XML file might do this trick?

    Stephajn Craig, Jun 26, 2003, in forum: ASP .Net
    Replies:
    1
    Views:
    449
    Stephajn Craig
    Jun 26, 2003
  5. x1
    Replies:
    20
    Views:
    283
    Daniel Calvelo
    Dec 27, 2005
Loading...

Share This Page