[ 
https://issues.apache.org/jira/browse/NUMBERS-184?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Alex Herbert resolved NUMBERS-184.
----------------------------------
    Resolution: Fixed

Updated in commit:

286932d1306606e927c417409c14bb49751c61f8

> Reduce number of operations in Precision.equals using a maxUlps
> ---------------------------------------------------------------
>
>                 Key: NUMBERS-184
>                 URL: https://issues.apache.org/jira/browse/NUMBERS-184
>             Project: Commons Numbers
>          Issue Type: Improvement
>          Components: core
>    Affects Versions: 1.0
>            Reporter: Alex Herbert
>            Priority: Trivial
>             Fix For: 1.1
>
>
> The Precision class has a method to test if two arguments are equal using a 
> maximum number of representable float values between two arguments.
> This is performed on the IEEE 754 bit layout of the floats. When the two 
> inputs have opposite signs there is a lot of code to compute the distance of 
> the values from the bit representation of +0.0 or -0.0. This is redundant. If 
> the signs are opposite then the distance from the bit representation of 0.0 
> only requires dropping the sign bit from the bit representation. Here is an 
> extract from the current method:
> {code:java}
>         final int xInt = Float.floatToRawIntBits(x);
>         final int yInt = Float.floatToRawIntBits(y);
>         final boolean isEqual;
>         if (((xInt ^ yInt) & SGN_MASK_FLOAT) == 0) {
>             // number have same sign, there is no risk of overflow
>             isEqual = Math.abs(xInt - yInt) <= maxUlps;
>         } else {
>             // number have opposite signs, take care of overflow
>             final int deltaPlus;
>             final int deltaMinus;
>             if (xInt < yInt) {
>                 deltaPlus  = yInt - POSITIVE_ZERO_FLOAT_BITS;
>                 deltaMinus = xInt - NEGATIVE_ZERO_FLOAT_BITS;
>             } else {
>                 deltaPlus  = xInt - POSITIVE_ZERO_FLOAT_BITS;
>                 deltaMinus = yInt - NEGATIVE_ZERO_FLOAT_BITS;
>             }            
>             if (deltaPlus > maxUlps) {
>                 isEqual = false;
>             } else {
>                 isEqual = deltaMinus <= (maxUlps - deltaPlus);
>             }        
>         }{code}
> The second branch can be simplified using bit masking.
> {code:java}
>             final int deltaPlus = xInt & Integer.MAX_VALUE;
>             final int deltaMinus = yInt & Integer.MAX_VALUE;   
>             isEqual = (long) deltaPlus + deltaMinus <= maxUlps;{code}
> For the float method overflow can be avoid by using a long to sum the two 
> deltas eliminating a further branch condition.
> An different optimisation can be performed for the double argument method. 
> Since the ulp argument is an integer, when the signs are opposite then a NaN 
> bit value would be at least (2047L << 52) above zero. Thus there is no need 
> to check for NaN if the numbers are equal within the max ULPs and have 
> opposite signs.
> This optimisation could be made if using a short for the float equals method 
> but would require breaking API changes and cannot be done. For reference the 
> max difference for doubles is approximately 2^31 / 2^52 of the mantissa for 
> double values with the same exponent. This is a relative error of 
> approximately 4.77e-7.
> Using a short for floats would be 2^15 / 2^24 of the mantissa for a relative 
> error of approximately 3.8e-3. Using an int argument allows an extreme 
> relative error of 1 when both arguments are the same sign, and an absolute 
> error of more than Float.MAX_VALUE. It makes no sense to compare two float 
> values with a maximum possible ULP difference of more than the range from 
> zero to infinity.
>  



--
This message was sent by Atlassian Jira
(v8.20.1#820001)

Reply via email to