Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #26504 > unrolled thread

Re: Possible loss of precision

Started byMichael Jung <miju@golem.phantasia.org>
First post2013-11-14 20:39 +0100
Last post2013-11-17 08:05 -0800
Articles 11 — 7 participants

Back to article view | Back to comp.lang.java.programmer

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Possible loss of precision Michael Jung <miju@golem.phantasia.org> - 2013-11-14 20:39 +0100
    Re: Possible loss of precision Gene Wirchenko <genew@telus.net> - 2013-11-14 15:03 -0800
      Re: Possible loss of precision Eric Sosman <esosman@comcast-dot-net.invalid> - 2013-11-14 18:31 -0500
        Re: Possible loss of precision Joerg Meier <joergmmeier@arcor.de> - 2013-11-15 00:55 +0100
        Re: Possible loss of precision Eric Sosman <esosman@comcast-dot-net.invalid> - 2013-11-14 20:19 -0500
          Re: Possible loss of precision taqmcg@gmail.com - 2013-11-15 07:01 -0800
          Re: Possible loss of precision Martin Gregorie <martin@address-in-sig.invalid> - 2013-11-15 21:36 +0000
      Re: Possible loss of precision Michael Jung <miju@golem.phantasia.org> - 2013-11-15 19:24 +0100
        Re: Possible loss of precision Patricia Shanahan <pats@acm.org> - 2013-11-15 20:48 -0800
          Re: Possible loss of precision Michael Jung <miju@golem.phantasia.org> - 2013-11-17 13:28 +0100
            Re: Possible loss of precision Patricia Shanahan <pats@acm.org> - 2013-11-17 08:05 -0800

#26504 — Re: Possible loss of precision

FromMichael Jung <miju@golem.phantasia.org>
Date2013-11-14 20:39 +0100
SubjectRe: Possible loss of precision
Message-ID<87txfe22o1.fsf@golem.phantasia.org>
ram@zedat.fu-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.

[toc] | [next] | [standalone]


#26505

FromGene Wirchenko <genew@telus.net>
Date2013-11-14 15:03 -0800
Message-ID<kkla89tv4vb3c60ao7qkj2hr3kd0ims4gc@4ax.com>
In reply to#26504
On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
<miju@golem.phantasia.org> wrote:

>ram@zedat.fu-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

[toc] | [prev] | [next] | [standalone]


#26506

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2013-11-14 18:31 -0500
Message-ID<l63mh7$afg$1@dont-email.me>
In reply to#26505
On 11/14/2013 6:03 PM, Gene Wirchenko wrote:
> On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
> <miju@golem.phantasia.org> wrote:
>
>> ram@zedat.fu-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
esosman@comcast-dot-net.invalid

[toc] | [prev] | [next] | [standalone]


#26507

FromJoerg Meier <joergmmeier@arcor.de>
Date2013-11-15 00:55 +0100
Message-ID<nnts78v1vsvu.ew4fz8qb7bhm$.dlg@40tude.net>
In reply to#26506
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
>> <miju@golem.phantasia.org> 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.

[toc] | [prev] | [next] | [standalone]


#26508

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2013-11-14 20:19 -0500
Message-ID<l63sqt$9bm$1@dont-email.me>
In reply to#26506
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
>> <miju@golem.phantasia.org> wrote:
>>
>>> ram@zedat.fu-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
esosman@comcast-dot-net.invalid

[toc] | [prev] | [next] | [standalone]


#26510

Fromtaqmcg@gmail.com
Date2013-11-15 07:01 -0800
Message-ID<4a561493-66cd-44c0-839a-542d752c405c@googlegroups.com>
In reply to#26508
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's could 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 is going 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 of automatic promotion of bytes, shorts and chars to ints.  

   Regards,
   Tom McGlynn

[toc] | [prev] | [next] | [standalone]


#26515

FromMartin Gregorie <martin@address-in-sig.invalid>
Date2013-11-15 21:36 +0000
Message-ID<l66447$qat$1@dont-email.me>
In reply to#26508
On Thu, 14 Nov 2013 20:19:27 -0500, Eric Sosman wrote:

> 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?
>
I think Java is weak in this area - the ancient Algol68 language did this 
better with its explicit concept of widening and narrowing numbers

	int n;
        float f;
        double d;

	d = f; d = n; f = n; 

are all examples of widening, and all are legal as you'd expect because 
there is no loss of precision, while 

       n = f; n = d; f = d;

are all examples of narrowing, which involves loss of precision, and so 
are rejected by the compiler, which forces you to use a conversion 
function, such as round(), floor() or ceil(). Compared with this, using a 
cast to narrow a number is a very blunt instrument.

The standard A68 library overloaded these functions so they worked 
correctly between all numeric types including, IIRC, that you could use 
them to convert and numeric type to or from a bool.

The odd thing is that all Java need to fix this is to extend the Math 
class with the appropriate methods.


-- 
martin@   | Martin Gregorie
gregorie. | Essex, UK
org       |

[toc] | [prev] | [next] | [standalone]


#26513

FromMichael Jung <miju@golem.phantasia.org>
Date2013-11-15 19:24 +0100
Message-ID<87txfded5c.fsf@golem.phantasia.org>
In reply to#26505
Gene Wirchenko <genew@telus.net> writes:
> On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
> <miju@golem.phantasia.org> wrote:
>>ram@zedat.fu-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

[toc] | [prev] | [next] | [standalone]


#26516

FromPatricia Shanahan <pats@acm.org>
Date2013-11-15 20:48 -0800
Message-ID<1cydnYUCtYikZBvPnZ2dnUVZ_umdnZ2d@earthlink.com>
In reply to#26513
On 11/15/2013 10:24 AM, Michael Jung wrote:
> Gene Wirchenko <genew@telus.net> writes:
>> On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
>> <miju@golem.phantasia.org> wrote:
>>> ram@zedat.fu-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.

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.

Patricia

[toc] | [prev] | [next] | [standalone]


#26523

FromMichael Jung <miju@golem.phantasia.org>
Date2013-11-17 13:28 +0100
Message-ID<878uwnw6t1.fsf@golem.phantasia.org>
In reply to#26516
Patricia Shanahan <pats@acm.org> writes:

> On 11/15/2013 10:24 AM, Michael Jung wrote:
>> Gene Wirchenko <genew@telus.net> writes:
>>> On Thu, 14 Nov 2013 20:39:42 +0100, Michael Jung
>>> <miju@golem.phantasia.org> wrote:
>>>> ram@zedat.fu-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

[toc] | [prev] | [next] | [standalone]


#26524

FromPatricia Shanahan <pats@acm.org>
Date2013-11-17 08:05 -0800
Message-ID<8pqdnQaCOuvddBXPnZ2dnUVZ_oSdnZ2d@earthlink.com>
In reply to#26523
On 11/17/2013 4:28 AM, Michael Jung wrote:
> Patricia Shanahan <pats@acm.org> writes:
...
>> 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".

Why non-hex? You would still need something like the current system for
hex initialization of a byte.

The would have needed to do the the same for short, [-32768, 32767], and
for numeric initializers for char, [0, 65535].

Patricia

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.java.programmer


csiph-web