[ImageJ-devel] Question regarding shortcut assignment operator in Java...
Brian Selinsky
bselinsky at wisc.edu
Tue Jun 22 10:18:24 CDT 2010
In any language, floating point arithmetic is going to be limited in accuracy by the size of the datatype used.
As a general rule of thumb, it's ALWAYS a good idea to parenthesize any floating point math, this is because associative and commutative properties may not hold if there is rounding. i.e. a * b * c may not exactly equal c * b * a may not equal a * (b * c)
The *= operator is defined where a *= b * c is exactly equal to a = a * (b * c) which multiplies the b * c first then multiplies a whereas a * b * c multiplies a * b then c. The variance in the rounding based on the 2 different statements explains the difference in the result.
So, basically, consistency is the thing, parenthesize to enforce order and don't assume associative and commutative properties hold.
Not using the *= with floating point is likely a good idea because you are relinquishing control of the order of operations to the language definition rather than defining it yourself when order is potentially important. Never assume you know what the system is going to do.
FYI - Java operator precedence table - http://java.sun.com/docs/books/tutorial/java/nutsandbolts/operators.html
On 06/21/10, Rick Lentz <rwlentz at wisc.edu> wrote:
> Greetings,
>
> I was running up against several 'bugs' in my implementations of NIO
> backed arrays for the ImageJ effort. I have identified the source of
> the bugs. It appears that the assignment operator '*=' in Java
> produces different results for some numbers in comparison to the
> expanded version of the notation. This was surprising to me since I
> assumed that use of the shortcut assignment operator in Java (E.g. A
> *= B ) would produce the same results as A = A * B.
>
> Although the initial difference is small, when carried forward for
> 30 steps over hundreds of iterations... the error (carried forward?)
> becomes considerable.
>
> Here is a snippet that demos the error (all data is float):
>
> //expanded notation
> float ad = data2[k][i + w*j] * gka[k]*gja[j]*gia[i];
> //existing implementation
> data2[k][i + w*j] *= gka[k]*gja[j]*gia[i];
> //result of shortcut notation
> float ac = data2[k][i + w*j];
> //direct comparison
> if(ad != ac)
> {
> System.out.println("Value at " + (k) + " , " + (i + w*j) + " of " +
> ac + " != " + ad );
> }
> //input values
> Value at 0 , 133 of 1.429051E-4 != 1.4290512E-4
> Value at 0 , 133 of 1.429051E-4 not = value at 133 of 1.4290512E-4
> Component values are 1.0 for gk
> Component values are 0.99993896 for gj
> Component values are 0.99847525 for gi
> Component values are 1.4313207E-4 for data2
>
> I am leaning towards standardizing the reference implementations to
> replace instances of *= with the expanded notation to obtain
> consistent results between imagelib NIO types and existing code. I am
> open to feedback regarding this issue and certainly hope that I am
> simply overlooking something trivial.
>
> Sincerely,
>
> Rick Lentz
> Bascom Hall - "...ever encourage that continual and fearless sifting
> and winnowing by which alone the truth can be found"
>
> _______________________________________________
> ImageJ-devel mailing list
> ImageJ-devel at imagejdev.org
> http://imagejdev.org/mailman/listinfo/imagej-devel
More information about the ImageJ-devel
mailing list