Possible loss of precision

Discussion in 'Java' started by Stefan Ram, Nov 13, 2013.

  1. Stefan Ram

    Stefan Ram Guest

    When one writes

    char x = 'C' + 1;
    x = x + 1;

    in a block, one gets an error message

    »possible loss of precision«

    for »x = x + 1«. Ok, fair enough: »x + 1« has type »int«,
    and precision is lost when assigning this to the variable x
    of type char.

    I was somewhat surprised, though, that »char x = 'C' + 1;«
    does not yield an error, even though the type of »'C' + 1«
    is int, too. Possibly, this time, the compiler can figure
    out that the actual value still fits into a char.

    But then, »int i = 2.0;« gives an error, even though the
    compiler should see that »2.0« can be represented as an int.
    Stefan Ram, Nov 13, 2013
    #1
    1. Advertising

  2. Stefan Ram

    Michael Jung Guest

    -berlin.de (Stefan Ram) writes:
    > char x = 'C' + 1;
    > x = x + 1;
    > in a block, one gets an error message
    > »possible loss of precision«
    > for »x = x + 1«. Ok, fair enough: »x + 1« has type »int«,
    > and precision is lost when assigning this to the variable x
    > of type char.
    > I was somewhat surprised, though, that »char x = 'C' + 1;«
    > does not yield an error, even though the type of »'C' + 1«
    > is int, too. Possibly, this time, the compiler can figure
    > out that the actual value still fits into a char.
    > But then, »int i = 2.0;« gives an error, even though the
    > compiler should see that »2.0« can be represented as an int.


    You are right that x+1 is "promoted" to int and the second assignment
    fails. In the other cases the compiler will follow JLS 15.28 => 5.2.
    This concerns constant expressions first and the second allows a
    narrowing in rare cases, of which the first line is one but the
    "int i = 2.0" isn't.
    Michael Jung, Nov 14, 2013
    #2
    1. Advertising

  3. On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
    <> wrote:

    >-berlin.de (Stefan Ram) writes:
    >> char x = 'C' + 1;
    >> x = x + 1;
    >> in a block, one gets an error message
    >> »possible loss of precision«
    >> for »x = x + 1«. Ok, fair enough: »x + 1« has type »int«,
    >> and precision is lost when assigning this to the variable x
    >> of type char.
    >> I was somewhat surprised, though, that »char x = 'C' + 1;«
    >> does not yield an error, even though the type of »'C' + 1«
    >> is int, too. Possibly, this time, the compiler can figure
    >> out that the actual value still fits into a char.
    >> But then, »int i = 2.0;« gives an error, even though the
    >> compiler should see that »2.0« can be represented as an int.

    >
    >You are right that x+1 is "promoted" to int and the second assignment
    >fails. In the other cases the compiler will follow JLS 15.28 => 5.2.
    >This concerns constant expressions first and the second allows a
    >narrowing in rare cases, of which the first line is one but the
    >"int i = 2.0" isn't.


    Why isn't it though?

    Sincerely,

    Gene Wirchenko
    Gene Wirchenko, Nov 14, 2013
    #3
  4. Stefan Ram

    Eric Sosman Guest

    On 11/14/2013 6:03 PM, Gene Wirchenko wrote:
    > On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
    > <> wrote:
    >
    >> -berlin.de (Stefan Ram) writes:
    >>> char x = 'C' + 1;
    >>> x = x + 1;
    >>> in a block, one gets an error message
    >>> »possible loss of precision«
    >>> for »x = x + 1«. Ok, fair enough: »x + 1« has type »int«,
    >>> and precision is lost when assigning this to the variable x
    >>> of type char.
    >>> I was somewhat surprised, though, that »char x = 'C' + 1;«
    >>> does not yield an error, even though the type of »'C' + 1«
    >>> is int, too. Possibly, this time, the compiler can figure
    >>> out that the actual value still fits into a char.
    >>> But then, »int i = 2.0;« gives an error, even though the
    >>> compiler should see that »2.0« can be represented as an int.

    >>
    >> You are right that x+1 is "promoted" to int and the second assignment
    >> fails. In the other cases the compiler will follow JLS 15.28 => 5.2.
    >> This concerns constant expressions first and the second allows a
    >> narrowing in rare cases, of which the first line is one but the
    >> "int i = 2.0" isn't.

    >
    > Why isn't it though?


    Speculation: The fact that a floating-point expression happens
    to evaluate to a number with no fractional part doesn't mean the
    value "is" an integer. One reasonable view of FP is that a value
    is just a representative of a range of real values, namely, all
    those real values that round to the representative. In this
    view, converting 2.0 to 2 *does* lose precision, specifically,
    the amount of wiggle room.

    Then again, maybe the Java designers were just FP-wary.

    --
    Eric Sosman
    d
    Eric Sosman, Nov 14, 2013
    #4
  5. Stefan Ram

    Joerg Meier Guest

    On Thu, 14 Nov 2013 18:31:53 -0500, Eric Sosman wrote:

    > On 11/14/2013 6:03 PM, Gene Wirchenko wrote:
    >> On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
    >> <> wrote:
    >>> You are right that x+1 is "promoted" to int and the second assignment
    >>> fails. In the other cases the compiler will follow JLS 15.28 => 5.2.
    >>> This concerns constant expressions first and the second allows a
    >>> narrowing in rare cases, of which the first line is one but the
    >>> "int i = 2.0" isn't.

    >> Why isn't it though?

    > Speculation: The fact that a floating-point expression happens
    > to evaluate to a number with no fractional part doesn't mean the
    > value "is" an integer. One reasonable view of FP is that a value
    > is just a representative of a range of real values, namely, all
    > those real values that round to the representative. In this
    > view, converting 2.0 to 2 *does* lose precision, specifically,
    > the amount of wiggle room.


    My instinctive mental reply was that 2.0 instead of 2 is an explicit
    instruction to use double, much like L or F, which you wouldn't want to be
    silently ignored.

    Liebe Gruesse,
    Joerg

    --
    Ich lese meine Emails nicht, replies to Email bleiben also leider
    ungelesen.
    Joerg Meier, Nov 14, 2013
    #5
  6. Stefan Ram

    Eric Sosman Guest

    On 11/14/2013 6:31 PM, Eric Sosman wrote:
    > On 11/14/2013 6:03 PM, Gene Wirchenko wrote:
    >> On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
    >> <> wrote:
    >>
    >>> -berlin.de (Stefan Ram) writes:
    >>>> char x = 'C' + 1;
    >>>> x = x + 1;
    >>>> in a block, one gets an error message
    >>>> »possible loss of precision«
    >>>> for »x = x + 1«. Ok, fair enough: »x + 1« has type »int«,
    >>>> and precision is lost when assigning this to the variable x
    >>>> of type char.
    >>>> I was somewhat surprised, though, that »char x = 'C' + 1;«
    >>>> does not yield an error, even though the type of »'C' + 1«
    >>>> is int, too. Possibly, this time, the compiler can figure
    >>>> out that the actual value still fits into a char.
    >>>> But then, »int i = 2.0;« gives an error, even though the
    >>>> compiler should see that »2.0« can be represented as an int.
    >>>
    >>> You are right that x+1 is "promoted" to int and the second assignment
    >>> fails. In the other cases the compiler will follow JLS 15.28 => 5.2.
    >>> This concerns constant expressions first and the second allows a
    >>> narrowing in rare cases, of which the first line is one but the
    >>> "int i = 2.0" isn't.

    >>
    >> Why isn't it though?

    >
    > Speculation: The fact that a floating-point expression happens
    > to evaluate to a number with no fractional part doesn't mean the
    > value "is" an integer. One reasonable view of FP is that a value
    > is just a representative of a range of real values, namely, all
    > those real values that round to the representative. In this
    > view, converting 2.0 to 2 *does* lose precision, specifically,
    > the amount of wiggle room.


    As a more concrete example,

    static final double FOO = 17.316;
    static final double BAR = 8.658;
    int i = FOO / BAR; // Should javac be silent here?

    Neither the numerator nor the denominator can be represented
    exactly as stated, yet the quotient is (probably; cook up your
    own numbers if mine are faulty) exactly 2.0. Would it be a
    good idea to let this construct slide through unremarked? Or
    should javac acknowledge the inherent imprecisions in the
    operations leading to the exactly-integral result?

    --
    Eric Sosman
    d
    Eric Sosman, Nov 15, 2013
    #6
  7. Stefan Ram

    Guest

    On Thursday, November 14, 2013 8:19:27 PM UTC-5, Eric Sosman wrote:
    > On 11/14/2013 6:31 PM, Eric Sosman wrote:
    >
    > As a more concrete example,
    >
    > static final double FOO = 17.316;
    > static final double BAR = 8.658;
    > int i = FOO / BAR; // Should javac be silent here?
    >
    > Neither the numerator nor the denominator can be represented
    > exactly as stated, yet the quotient is (probably; cook up your
    > own numbers if mine are faulty) exactly 2.0. Would it be a
    > good idea to let this construct slide through unremarked? Or
    > should javac acknowledge the inherent imprecisions in the
    > operations leading to the exactly-integral result?


    In this case it's pretty clear that the error should be signaled since we have a floating point expression that involves computations where roundoff'scould do weird things:
    Consider the case when we use FOO = 3.3 and BAR = 1.1. Then the value of
    (int) (FOO/BAR) == 2
    and I certainly wouldn't want to have a language where

    int i = 3.3/1.1;
    gives a different result than
    double x = 3.3;
    double y = 1.1;
    int i = x/y;

    When the integer value of the ration is a power of 2, then the internal floating point representations will differ only in the exponent, so you're likely get 'correct' values when you do the computation, but for all other integer ratios the actual value that a proper Java program would computer will often differ from the 'correct' value. And even for powers of two one isgoing to run into problems if denormalized floats or doubles are being used.

    If we exclude expressions there would be still hard cases:
    E.g., if we were allowing
    int i = 2.0;
    presumably we'd also want to allow
    int i = 1.234E3; // = 1234)
    but then you might be surprised to get an error for the equivalent
    int i = 1.2345E3; // = 1234.5
    which doesn't really look very differnt.

    And what would one do with:

    int i = 123456789.f;

    which seems like a normal integer, but since we've gone beyond the precision of floats we'd find that
    float f = 123456789.f;
    int i = (int) f;
    yields
    i == 123456792


    We wouldn't run into this when converting doubles to ints, but a similar problem occurs for doubles to longs.

    So any relaxation of the rule that there is a loss-of-precision error in converting floating point values to integral values would have to be either arbitrarily limited (say to |integers| < 100) or hedged with lots of caveats.. Having a simple rule that you need to signal such a conversion with a cast seems like a reasonable choice.

    Personally I'd have preferred that Java be fully consistent here and not have the exception for operators like +=

    double x = 1.;
    int i = 0;
    i += x; // is legal

    but I believe that exception is essentially required by the (imho) folly ofautomatic promotion of bytes, shorts and chars to ints.

    Regards,
    Tom McGlynn
    , Nov 15, 2013
    #7
  8. Stefan Ram

    Michael Jung Guest

    Gene Wirchenko <> writes:
    > On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
    > <> wrote:
    >>-berlin.de (Stefan Ram) writes:

    [...]
    >>> But then, »int i = 2.0;« gives an error, even though the
    >>> compiler should see that »2.0« can be represented as an int.

    >>You are right that x+1 is "promoted" to int and the second assignment
    >>fails. In the other cases the compiler will follow JLS 15.28 => 5.2.
    >>This concerns constant expressions first and the second allows a
    >>narrowing in rare cases, of which the first line is one but the
    >>"int i = 2.0" isn't.

    > Why isn't it though?


    Since compile-time constant expressions are FP-strict and could be done,
    I guess it was seen as pathological and not worth the effort.

    Michael
    Michael Jung, Nov 15, 2013
    #8
  9. Stefan Ram

    Stefan Ram Guest

    Patricia Shanahan <> writes:
    >I think the difference is that there is a cast-free way of initializing
    >an int to the value 2.
    >On the other hand, without the special narrowing rule for initializers,
    >there would be no cast-free way of initializing a byte with the value 2.


    It's the same in C++:

    char c{ 7 }; // ok
    char d{ 999 }; // usually an error
    int i{ 3.0 }; // error

    . Bjarne Stroustrup writes:

    »The way C++11 avoids a lot of incompatibilities is by
    relying on the actual values of initializers (such as 7
    in the example above) when it can (and not just type)
    when deciding what is a narrowing conversion. If a value
    can be represented exactly as the target type, the
    conversion is not narrowing.«

    »Note that floating-point to integer conversions are
    always considered narrowing -- even 7.0 to 7.«

    http://www.stroustrup.com/C 11FAQ.html
    Stefan Ram, Nov 16, 2013
    #9
  10. Stefan Ram

    Michael Jung Guest

    Patricia Shanahan <> writes:

    > On 11/15/2013 10:24 AM, Michael Jung wrote:
    >> Gene Wirchenko <> writes:
    >>> On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
    >>> <> wrote:
    >>>> -berlin.de (Stefan Ram) writes:

    >> [...]
    >>>>> But then, »int i = 2.0;« gives an error, even though the
    >>>>> compiler should see that »2.0« can be represented as an int.
    >>>> You are right that x+1 is "promoted" to int and the second assignment
    >>>> fails. In the other cases the compiler will follow JLS 15.28 => 5.2.
    >>>> This concerns constant expressions first and the second allows a
    >>>> narrowing in rare cases, of which the first line is one but the
    >>>> "int i = 2.0" isn't.
    >>> Why isn't it though?

    >> Since compile-time constant expressions are FP-strict and could be done,
    >> I guess it was seen as pathological and not worth the effort.

    > I think the difference is that there is a cast-free way of
    > initializing an int to the value 2.


    Not if you wanted to do "int a = 2 * 0.5;" or something similar.

    > On the other hand, without the special narrowing rule for
    > initializers, there would be no cast-free way of initializing a byte
    > with the value 2.


    They could have spent a suffix "B/b" (for non-hex integer literals) as
    with "l/L".

    Michael
    Michael Jung, Nov 17, 2013
    #10
    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. John Wilcher

    Perceived Loss of All Session Objects

    John Wilcher, Aug 13, 2003, in forum: ASP .Net
    Replies:
    4
    Views:
    430
    John Wilcher
    Aug 14, 2003
  2. stevek

    Can I force precision loss?

    stevek, Jan 16, 2005, in forum: Java
    Replies:
    4
    Views:
    12,251
    Yu SONG
    Jan 17, 2005
  3. BigMan
    Replies:
    16
    Views:
    600
    E. Robert Tisdale
    Apr 13, 2005
  4. giff
    Replies:
    15
    Views:
    593
  5. Thomas
    Replies:
    22
    Views:
    1,062
    Twisted
    Jul 10, 2007
Loading...

Share This Page