View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  /*
19   * This is not the original file distributed by the Apache Software Foundation
20   * It has been modified by the Hipparchus project
21   */
22  
23  package org.hipparchus.util;
24  
25  import java.math.BigDecimal;
26  import java.math.RoundingMode;
27  
28  import org.hipparchus.exception.LocalizedCoreFormats;
29  import org.hipparchus.exception.MathRuntimeException;
30  import org.hipparchus.exception.MathIllegalArgumentException;
31  
32  /**
33   * Utilities for comparing numbers.
34   */
35  public class Precision {
36      /**
37       * Largest double-precision floating-point number such that
38       * {@code 1 + EPSILON} is numerically equal to 1. This value is an upper
39       * bound on the relative error due to rounding real numbers to double
40       * precision floating-point numbers.
41       * <p>
42       * In IEEE 754 arithmetic, this is 2<sup>-53</sup>.
43       *
44       * @see <a href="http://en.wikipedia.org/wiki/Machine_epsilon">Machine epsilon</a>
45       */
46      public static final double EPSILON;
47  
48      /**
49       * Safe minimum, such that {@code 1 / SAFE_MIN} does not overflow.
50       * <br>
51       * In IEEE 754 arithmetic, this is also the smallest normalized
52       * number 2<sup>-1022</sup>.
53       */
54      public static final double SAFE_MIN;
55  
56      /** Exponent offset in IEEE754 representation. */
57      private static final long EXPONENT_OFFSET = 1023l;
58  
59      /** Offset to order signed double numbers lexicographically. */
60      private static final long SGN_MASK = 0x8000000000000000L;
61      /** Offset to order signed double numbers lexicographically. */
62      private static final int SGN_MASK_FLOAT = 0x80000000;
63      /** Positive zero. */
64      private static final double POSITIVE_ZERO = 0d;
65      /** Positive zero bits. */
66      private static final long POSITIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(+0.0);
67      /** Negative zero bits. */
68      private static final long NEGATIVE_ZERO_DOUBLE_BITS = Double.doubleToRawLongBits(-0.0);
69      /** Positive zero bits. */
70      private static final int POSITIVE_ZERO_FLOAT_BITS   = Float.floatToRawIntBits(+0.0f);
71      /** Negative zero bits. */
72      private static final int NEGATIVE_ZERO_FLOAT_BITS   = Float.floatToRawIntBits(-0.0f);
73      /** Mask used to extract exponent from double bits. */
74      private static final long MASK_DOUBLE_EXPONENT = 0x7ff0000000000000L;
75      /** Mask used to extract mantissa from double bits. */
76      private static final long MASK_DOUBLE_MANTISSA = 0x000fffffffffffffL;
77      /** Mask used to add implicit high order bit for normalized double. */
78      private static final long IMPLICIT_DOUBLE_HIGH_BIT = 0x0010000000000000L;
79      /** Mask used to extract exponent from float bits. */
80      private static final int MASK_FLOAT_EXPONENT = 0x7f800000;
81      /** Mask used to extract mantissa from float bits. */
82      private static final int MASK_FLOAT_MANTISSA = 0x007fffff;
83      /** Mask used to add implicit high order bit for normalized float. */
84      private static final int IMPLICIT_FLOAT_HIGH_BIT = 0x00800000;
85  
86      static {
87          /*
88           *  This was previously expressed as = 0x1.0p-53;
89           *  However, OpenJDK (Sparc Solaris) cannot handle such small
90           *  constants: MATH-721
91           */
92          EPSILON = Double.longBitsToDouble((EXPONENT_OFFSET - 53l) << 52);
93  
94          /*
95           * This was previously expressed as = 0x1.0p-1022;
96           * However, OpenJDK (Sparc Solaris) cannot handle such small
97           * constants: MATH-721
98           */
99          SAFE_MIN = Double.longBitsToDouble((EXPONENT_OFFSET - 1022l) << 52);
100     }
101 
102     /**
103      * Private constructor.
104      */
105     private Precision() {}
106 
107     /**
108      * Compares two numbers given some amount of allowed error.
109      *
110      * @param x the first number
111      * @param y the second number
112      * @param eps the amount of error to allow when checking for equality
113      * @return <ul><li>0 if  {@link #equals(double, double, double) equals(x, y, eps)}</li>
114      *       <li>&lt; 0 if !{@link #equals(double, double, double) equals(x, y, eps)} &amp;&amp; x &lt; y</li>
115      *       <li>&gt; 0 if !{@link #equals(double, double, double) equals(x, y, eps)} &amp;&amp; x &gt; y or
116      *       either argument is NaN</li></ul>
117      */
118     public static int compareTo(double x, double y, double eps) {
119         if (equals(x, y, eps)) {
120             return 0;
121         } else if (x < y) {
122             return -1;
123         }
124         return 1;
125     }
126 
127     /**
128      * Compares two numbers given some amount of allowed error.
129      * Two float numbers are considered equal if there are {@code (maxUlps - 1)}
130      * (or fewer) floating point numbers between them, i.e. two adjacent floating
131      * point numbers are considered equal.
132      * Adapted from <a
133      * href="http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/">
134      * Bruce Dawson</a>. Returns {@code false} if either of the arguments is NaN.
135      *
136      * @param x first value
137      * @param y second value
138      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
139      * values between {@code x} and {@code y}.
140      * @return <ul><li>0 if  {@link #equals(double, double, int) equals(x, y, maxUlps)}</li>
141      *       <li>&lt; 0 if !{@link #equals(double, double, int) equals(x, y, maxUlps)} &amp;&amp; x &lt; y</li>
142      *       <li>&gt; 0 if !{@link #equals(double, double, int) equals(x, y, maxUlps)} &amp;&amp; x &gt; y
143      *       or either argument is NaN</li></ul>
144      */
145     public static int compareTo(final double x, final double y, final int maxUlps) {
146         if (equals(x, y, maxUlps)) {
147             return 0;
148         } else if (x < y) {
149             return -1;
150         }
151         return 1;
152     }
153 
154     /**
155      * Returns true iff they are equal as defined by
156      * {@link #equals(float,float,int) equals(x, y, 1)}.
157      *
158      * @param x first value
159      * @param y second value
160      * @return {@code true} if the values are equal.
161      */
162     public static boolean equals(float x, float y) {
163         return equals(x, y, 1);
164     }
165 
166     /**
167      * Returns true if both arguments are NaN or they are
168      * equal as defined by {@link #equals(float,float) equals(x, y, 1)}.
169      *
170      * @param x first value
171      * @param y second value
172      * @return {@code true} if the values are equal or both are NaN.
173      */
174     public static boolean equalsIncludingNaN(float x, float y) {
175         return (x != x || y != y) ? !(x != x ^ y != y) : equals(x, y, 1);
176     }
177 
178     /**
179      * Returns true if the arguments are equal or within the range of allowed
180      * error (inclusive).  Returns {@code false} if either of the arguments
181      * is NaN.
182      *
183      * @param x first value
184      * @param y second value
185      * @param eps the amount of absolute error to allow.
186      * @return {@code true} if the values are equal or within range of each other.
187      */
188     public static boolean equals(float x, float y, float eps) {
189         return equals(x, y, 1) || FastMath.abs(y - x) <= eps;
190     }
191 
192     /**
193      * Returns true if the arguments are both NaN, are equal, or are within the range
194      * of allowed error (inclusive).
195      *
196      * @param x first value
197      * @param y second value
198      * @param eps the amount of absolute error to allow.
199      * @return {@code true} if the values are equal or within range of each other,
200      * or both are NaN.
201      */
202     public static boolean equalsIncludingNaN(float x, float y, float eps) {
203         return equalsIncludingNaN(x, y) || (FastMath.abs(y - x) <= eps);
204     }
205 
206     /**
207      * Returns true if the arguments are equal or within the range of allowed
208      * error (inclusive).
209      * Two float numbers are considered equal if there are {@code (maxUlps - 1)}
210      * (or fewer) floating point numbers between them, i.e. two adjacent floating
211      * point numbers are considered equal.
212      * Adapted from <a
213      * href="http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/">
214      * Bruce Dawson</a>.  Returns {@code false} if either of the arguments is NaN.
215      *
216      * @param x first value
217      * @param y second value
218      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
219      * values between {@code x} and {@code y}.
220      * @return {@code true} if there are fewer than {@code maxUlps} floating
221      * point values between {@code x} and {@code y}.
222      */
223     public static boolean equals(final float x, final float y, final int maxUlps) {
224 
225         final int xInt = Float.floatToRawIntBits(x);
226         final int yInt = Float.floatToRawIntBits(y);
227 
228         final boolean isEqual;
229         if (((xInt ^ yInt) & SGN_MASK_FLOAT) == 0) {
230             // number have same sign, there is no risk of overflow
231             isEqual = FastMath.abs(xInt - yInt) <= maxUlps;
232         } else {
233             // number have opposite signs, take care of overflow
234             final int deltaPlus;
235             final int deltaMinus;
236             if (xInt < yInt) {
237                 deltaPlus  = yInt - POSITIVE_ZERO_FLOAT_BITS;
238                 deltaMinus = xInt - NEGATIVE_ZERO_FLOAT_BITS;
239             } else {
240                 deltaPlus  = xInt - POSITIVE_ZERO_FLOAT_BITS;
241                 deltaMinus = yInt - NEGATIVE_ZERO_FLOAT_BITS;
242             }
243 
244             if (deltaPlus > maxUlps) {
245                 isEqual = false;
246             } else {
247                 isEqual = deltaMinus <= (maxUlps - deltaPlus);
248             }
249 
250         }
251 
252         return isEqual && !Float.isNaN(x) && !Float.isNaN(y);
253 
254     }
255 
256     /**
257      * Returns true if the arguments are both NaN or if they are equal as defined
258      * by {@link #equals(float,float,int) equals(x, y, maxUlps)}.
259      *
260      * @param x first value
261      * @param y second value
262      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
263      * values between {@code x} and {@code y}.
264      * @return {@code true} if both arguments are NaN or if there are less than
265      * {@code maxUlps} floating point values between {@code x} and {@code y}.
266      */
267     public static boolean equalsIncludingNaN(float x, float y, int maxUlps) {
268         return (x != x || y != y) ? !(x != x ^ y != y) : equals(x, y, maxUlps);
269     }
270 
271     /**
272      * Returns true iff they are equal as defined by
273      * {@link #equals(double,double,int) equals(x, y, 1)}.
274      *
275      * @param x first value
276      * @param y second value
277      * @return {@code true} if the values are equal.
278      */
279     public static boolean equals(double x, double y) {
280         return equals(x, y, 1);
281     }
282 
283     /**
284      * Returns true if the arguments are both NaN or they are
285      * equal as defined by {@link #equals(double,double) equals(x, y, 1)}.
286      *
287      * @param x first value
288      * @param y second value
289      * @return {@code true} if the values are equal or both are NaN.
290      */
291     public static boolean equalsIncludingNaN(double x, double y) {
292         return (x != x || y != y) ? !(x != x ^ y != y) : equals(x, y, 1);
293     }
294 
295     /**
296      * Returns {@code true} if there is no double value strictly between the
297      * arguments or the difference between them is within the range of allowed
298      * error (inclusive). Returns {@code false} if either of the arguments
299      * is NaN.
300      *
301      * @param x First value.
302      * @param y Second value.
303      * @param eps Amount of allowed absolute error.
304      * @return {@code true} if the values are two adjacent floating point
305      * numbers or they are within range of each other.
306      */
307     public static boolean equals(double x, double y, double eps) {
308         return equals(x, y, 1) || FastMath.abs(y - x) <= eps;
309     }
310 
311     /**
312      * Returns {@code true} if there is no double value strictly between the
313      * arguments or the relative difference between them is less than or equal
314      * to the given tolerance. Returns {@code false} if either of the arguments
315      * is NaN.
316      *
317      * @param x First value.
318      * @param y Second value.
319      * @param eps Amount of allowed relative error.
320      * @return {@code true} if the values are two adjacent floating point
321      * numbers or they are within range of each other.
322      */
323     public static boolean equalsWithRelativeTolerance(double x, double y, double eps) {
324         if (equals(x, y, 1)) {
325             return true;
326         }
327 
328         final double absoluteMax = FastMath.max(FastMath.abs(x), FastMath.abs(y));
329         final double relativeDifference = FastMath.abs((x - y) / absoluteMax);
330 
331         return relativeDifference <= eps;
332     }
333 
334     /**
335      * Returns true if the arguments are both NaN, are equal or are within the range
336      * of allowed error (inclusive).
337      *
338      * @param x first value
339      * @param y second value
340      * @param eps the amount of absolute error to allow.
341      * @return {@code true} if the values are equal or within range of each other,
342      * or both are NaN.
343      */
344     public static boolean equalsIncludingNaN(double x, double y, double eps) {
345         return equalsIncludingNaN(x, y) || (FastMath.abs(y - x) <= eps);
346     }
347 
348     /**
349      * Returns true if the arguments are equal or within the range of allowed
350      * error (inclusive).
351      * <p>
352      * Two float numbers are considered equal if there are {@code (maxUlps - 1)}
353      * (or fewer) floating point numbers between them, i.e. two adjacent
354      * floating point numbers are considered equal.
355      * </p>
356      * <p>
357      * Adapted from <a
358      * href="http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/">
359      * Bruce Dawson</a>. Returns {@code false} if either of the arguments is NaN.
360      * </p>
361      *
362      * @param x first value
363      * @param y second value
364      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
365      * values between {@code x} and {@code y}.
366      * @return {@code true} if there are fewer than {@code maxUlps} floating
367      * point values between {@code x} and {@code y}.
368      */
369     public static boolean equals(final double x, final double y, final int maxUlps) {
370 
371         final long xInt = Double.doubleToRawLongBits(x);
372         final long yInt = Double.doubleToRawLongBits(y);
373 
374         final boolean isEqual;
375         if (((xInt ^ yInt) & SGN_MASK) == 0l) {
376             // number have same sign, there is no risk of overflow
377             isEqual = FastMath.abs(xInt - yInt) <= maxUlps;
378         } else {
379             // number have opposite signs, take care of overflow
380             final long deltaPlus;
381             final long deltaMinus;
382             if (xInt < yInt) {
383                 deltaPlus  = yInt - POSITIVE_ZERO_DOUBLE_BITS;
384                 deltaMinus = xInt - NEGATIVE_ZERO_DOUBLE_BITS;
385             } else {
386                 deltaPlus  = xInt - POSITIVE_ZERO_DOUBLE_BITS;
387                 deltaMinus = yInt - NEGATIVE_ZERO_DOUBLE_BITS;
388             }
389 
390             if (deltaPlus > maxUlps) {
391                 isEqual = false;
392             } else {
393                 isEqual = deltaMinus <= (maxUlps - deltaPlus);
394             }
395 
396         }
397 
398         return isEqual && !Double.isNaN(x) && !Double.isNaN(y);
399 
400     }
401 
402     /**
403      * Returns true if both arguments are NaN or if they are equal as defined
404      * by {@link #equals(double,double,int) equals(x, y, maxUlps)}.
405      *
406      * @param x first value
407      * @param y second value
408      * @param maxUlps {@code (maxUlps - 1)} is the number of floating point
409      * values between {@code x} and {@code y}.
410      * @return {@code true} if both arguments are NaN or if there are less than
411      * {@code maxUlps} floating point values between {@code x} and {@code y}.
412      */
413     public static boolean equalsIncludingNaN(double x, double y, int maxUlps) {
414         return (x != x || y != y) ? !(x != x ^ y != y) : equals(x, y, maxUlps);
415     }
416 
417     /**
418      * Rounds the given value to the specified number of decimal places.
419      * The value is rounded using the {@link BigDecimal#ROUND_HALF_UP} method.
420      *
421      * @param x Value to round.
422      * @param scale Number of digits to the right of the decimal point.
423      * @return the rounded value.
424      */
425     public static double round(double x, int scale) {
426         return round(x, scale, RoundingMode.HALF_UP);
427     }
428 
429     /**
430      * Rounds the given value to the specified number of decimal places.
431      * The value is rounded using the given method which is any method defined
432      * in {@link BigDecimal}.
433      * If {@code x} is infinite or {@code NaN}, then the value of {@code x} is
434      * returned unchanged, regardless of the other parameters.
435      *
436      * @param x Value to round.
437      * @param scale Number of digits to the right of the decimal point.
438      * @param roundingMethod Rounding method as defined in {@link BigDecimal}.
439      * @return the rounded value.
440      * @throws ArithmeticException if {@code roundingMethod == ROUND_UNNECESSARY}
441      * and the specified scaling operation would require rounding.
442      * @throws IllegalArgumentException if {@code roundingMethod} does not
443      * represent a valid rounding mode.
444      */
445     public static double round(double x, int scale, RoundingMode roundingMethod) {
446         try {
447             final double rounded = (new BigDecimal(Double.toString(x))
448                    .setScale(scale, roundingMethod))
449                    .doubleValue();
450             // MATH-1089: negative values rounded to zero should result in negative zero
451             return rounded == POSITIVE_ZERO ? POSITIVE_ZERO * x : rounded;
452         } catch (NumberFormatException ex) {
453             if (Double.isInfinite(x)) {
454                 return x;
455             } else {
456                 return Double.NaN;
457             }
458         }
459     }
460 
461     /**
462      * Rounds the given value to the specified number of decimal places.
463      * The value is rounded using the {@link BigDecimal#ROUND_HALF_UP} method.
464      *
465      * @param x Value to round.
466      * @param scale Number of digits to the right of the decimal point.
467      * @return the rounded value.
468      */
469     public static float round(float x, int scale) {
470         return round(x, scale, RoundingMode.HALF_UP);
471     }
472 
473     /**
474      * Rounds the given value to the specified number of decimal places.
475      * The value is rounded using the given method which is any method defined
476      * in {@link BigDecimal}.
477      *
478      * @param x Value to round.
479      * @param scale Number of digits to the right of the decimal point.
480      * @param roundingMethod Rounding method as defined in {@link BigDecimal}.
481      * @return the rounded value.
482      * @throws MathRuntimeException if an exact operation is required but result is not exact
483      * @throws MathIllegalArgumentException if {@code roundingMethod} is not a valid rounding method.
484      */
485     public static float round(float x, int scale, RoundingMode roundingMethod)
486         throws MathRuntimeException, MathIllegalArgumentException {
487         final float sign = FastMath.copySign(1f, x);
488         final float factor = (float) FastMath.pow(10.0f, scale) * sign;
489         return (float) roundUnscaled(x * factor, sign, roundingMethod) / factor;
490     }
491 
492     /**
493      * Rounds the given non-negative value to the "nearest" integer. Nearest is
494      * determined by the rounding method specified. Rounding methods are defined
495      * in {@link BigDecimal}.
496      *
497      * @param unscaled Value to round.
498      * @param sign Sign of the original, scaled value.
499      * @param roundingMethod Rounding method, as defined in {@link BigDecimal}.
500      * @return the rounded value.
501      * @throws MathRuntimeException if an exact operation is required but result is not exact
502      * @throws MathIllegalArgumentException if {@code roundingMethod} is not a valid rounding method.
503      */
504     private static double roundUnscaled(double unscaled,
505                                         double sign,
506                                         RoundingMode roundingMethod)
507         throws MathRuntimeException, MathIllegalArgumentException {
508         switch (roundingMethod) {
509         case CEILING :
510             if (sign == -1) {
511                 unscaled = FastMath.floor(FastMath.nextAfter(unscaled, Double.NEGATIVE_INFINITY));
512             } else {
513                 unscaled = FastMath.ceil(FastMath.nextAfter(unscaled, Double.POSITIVE_INFINITY));
514             }
515             break;
516         case DOWN :
517             unscaled = FastMath.floor(FastMath.nextAfter(unscaled, Double.NEGATIVE_INFINITY));
518             break;
519         case FLOOR :
520             if (sign == -1) {
521                 unscaled = FastMath.ceil(FastMath.nextAfter(unscaled, Double.POSITIVE_INFINITY));
522             } else {
523                 unscaled = FastMath.floor(FastMath.nextAfter(unscaled, Double.NEGATIVE_INFINITY));
524             }
525             break;
526         case HALF_DOWN : {
527             unscaled = FastMath.nextAfter(unscaled, Double.NEGATIVE_INFINITY);
528             double fraction = unscaled - FastMath.floor(unscaled);
529             if (fraction > 0.5) {
530                 unscaled = FastMath.ceil(unscaled);
531             } else {
532                 unscaled = FastMath.floor(unscaled);
533             }
534             break;
535         }
536         case HALF_EVEN : {
537             double fraction = unscaled - FastMath.floor(unscaled);
538             if (fraction > 0.5) {
539                 unscaled = FastMath.ceil(unscaled);
540             } else if (fraction < 0.5) {
541                 unscaled = FastMath.floor(unscaled);
542             } else {
543                 // The following equality test is intentional and needed for rounding purposes
544                 if (FastMath.floor(unscaled) / 2.0 == FastMath.floor(FastMath.floor(unscaled) / 2.0)) { // even
545                     unscaled = FastMath.floor(unscaled);
546                 } else { // odd
547                     unscaled = FastMath.ceil(unscaled);
548                 }
549             }
550             break;
551         }
552         case HALF_UP : {
553             unscaled = FastMath.nextAfter(unscaled, Double.POSITIVE_INFINITY);
554             double fraction = unscaled - FastMath.floor(unscaled);
555             if (fraction >= 0.5) {
556                 unscaled = FastMath.ceil(unscaled);
557             } else {
558                 unscaled = FastMath.floor(unscaled);
559             }
560             break;
561         }
562         case UNNECESSARY :
563             if (unscaled != FastMath.floor(unscaled)) {
564                 throw new MathRuntimeException(LocalizedCoreFormats.ARITHMETIC_EXCEPTION);
565             }
566             break;
567         case UP :
568             // do not round if the discarded fraction is equal to zero
569             if (unscaled != FastMath.floor(unscaled)) {
570                 unscaled = FastMath.ceil(FastMath.nextAfter(unscaled, Double.POSITIVE_INFINITY));
571             }
572             break;
573         default :
574             // this should nerver happen
575             throw MathRuntimeException.createInternalError();
576         }
577         return unscaled;
578     }
579 
580     /** Check is x is a mathematical integer.
581      * @param x number to check
582      * @return true if x is a mathematical integer
583      * @since 1.7
584      */
585     public static boolean isMathematicalInteger(final double x) {
586         final long bits   = Double.doubleToRawLongBits(x);
587         final int  rawExp = (int) ((bits & MASK_DOUBLE_EXPONENT) >> 52);
588         if (rawExp == 2047) {
589             // NaN or infinite
590             return false;
591         } else {
592             // a double that may have a fractional part
593             final long rawMantissa    = bits & MASK_DOUBLE_MANTISSA;
594             final long fullMantissa   = rawExp > 0 ? (IMPLICIT_DOUBLE_HIGH_BIT | rawMantissa) : rawMantissa;
595             final long fractionalMask = (IMPLICIT_DOUBLE_HIGH_BIT | MASK_DOUBLE_MANTISSA) >> FastMath.min(53, FastMath.max(0, rawExp - 1022));
596             return (fullMantissa & fractionalMask) == 0l;
597         }
598     }
599 
600     /** Check is x is a mathematical integer.
601      * @param x number to check
602      * @return true if x is a mathematical integer
603      * @since 1.7
604      */
605     public static boolean isMathematicalInteger(final float x) {
606         final int bits   = Float.floatToRawIntBits(x);
607         final int rawExp = (int) ((bits & MASK_FLOAT_EXPONENT) >> 23);
608         if (rawExp == 255) {
609             // NaN or infinite
610             return false;
611         } else {
612             // a float that may have a fractional part
613             final int rawMantissa    = bits & MASK_FLOAT_MANTISSA;
614             final int fullMantissa   = rawExp > 0 ? (IMPLICIT_FLOAT_HIGH_BIT | rawMantissa) : rawMantissa;
615             final int fractionalMask = (IMPLICIT_FLOAT_HIGH_BIT | MASK_FLOAT_MANTISSA) >> FastMath.min(24, FastMath.max(0, rawExp - 126));
616             return (fullMantissa & fractionalMask) == 0;
617         }
618     }
619 
620     /**
621      * Computes a number {@code delta} close to {@code originalDelta} with
622      * the property that <pre><code>
623      *   x + delta - x
624      * </code></pre>
625      * is exactly machine-representable.
626      * This is useful when computing numerical derivatives, in order to reduce
627      * roundoff errors.
628      *
629      * @param x Value.
630      * @param originalDelta Offset value.
631      * @return a number {@code delta} so that {@code x + delta} and {@code x}
632      * differ by a representable floating number.
633      */
634     public static double representableDelta(double x,
635                                             double originalDelta) {
636         return x + originalDelta - x;
637     }
638 }