001/*
002 * The MIT License (MIT)
003 *
004 * Copyright (c) 2015-2023 decimal4j (tools4j), Marco Terzer
005 *
006 * Permission is hereby granted, free of charge, to any person obtaining a copy
007 * of this software and associated documentation files (the "Software"), to deal
008 * in the Software without restriction, including without limitation the rights
009 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
010 * copies of the Software, and to permit persons to whom the Software is
011 * furnished to do so, subject to the following conditions:
012 *
013 * The above copyright notice and this permission notice shall be included in all
014 * copies or substantial portions of the Software.
015 *
016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
017 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
018 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
019 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
020 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
021 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
022 * SOFTWARE.
023 */
024package org.decimal4j.arithmetic;
025
026import org.decimal4j.api.DecimalArithmetic;
027import org.decimal4j.scale.ScaleMetrics;
028import org.decimal4j.truncate.DecimalRounding;
029import org.decimal4j.truncate.TruncatedPart;
030
031/**
032 * Contains methods to convert from and to float.
033 */
034final class FloatConversion {
035
036        private static final long LONG_MASK = 0xffffffffL;
037
038        // The mask for the significand, according to the {@link
039        // Float#floatToRawIntBits(float)} spec.
040        private static final int SIGNIFICAND_MASK = 0x007fffff;
041
042        // The mask for the exponent, according to the {@link Float#floatToRawIntBits(float)} spec.
043        @SuppressWarnings("unused")
044        private static final int EXPONENT_MASK = 0x7f800000;
045
046        // The mask for the sign, according to the {@link Float#floatToRawIntBits(float)} spec.
047        private static final int SIGN_MASK = 0x80000000;
048
049        private static final int SIGNIFICAND_BITS = 23;
050
051        private static final int EXPONENT_BIAS = 127;
052
053        /**
054         * The implicit 1 bit that is omitted in significands of normal floats.
055         */
056        private static final int IMPLICIT_BIT = SIGNIFICAND_MASK + 1;
057
058        private static final float MIN_LONG_AS_FLOAT = -0x1p63f;
059        /*
060         * We cannot store Long.MAX_VALUE as a float without losing precision. Instead, we store Long.MAX_VALUE + 1 ==
061         * -Long.MIN_VALUE, and then offset all comparisons by 1.
062         */
063        private static final float MAX_LONG_AS_FLOAT_PLUS_ONE = 0x1p63f;
064
065        /**
066         * Converts the specified float value to a long truncating the fractional part if any is present. If the value is
067         * NaN, infinite or outside of the valid long range, an exception is thrown.
068         * 
069         * @param value
070         *            the value to convert
071         * @return <code>round<sub>DOWN</sub>(value)</code>
072         * @throws IllegalArgumentException
073         *             if {@code value} is NaN or infinite or if the magnitude is too large for the float to be represented
074         *             as a {@code long}
075         */
076        public static final long floatToLong(float value) {
077                if (Float.isNaN(value)) {
078                        throw new IllegalArgumentException("Cannot convert float to long: " + value);
079                }
080                if (isInLongRange(value)) {
081                        return (long) value;
082                }
083                throw new IllegalArgumentException("Overflow for conversion from float to long: " + value);
084        }
085
086        /**
087         * Converts the specified float value to a long rounding the fractional part if necessary using the given
088         * {@code rounding} mode. If the value is NaN, infinite or outside of the valid long range, an exception is thrown.
089         * 
090         * @param rounding
091         *            the rounding to apply if necessary
092         * @param value
093         *            the value to convert
094         * @return <code>round(value)</code>
095         * @throws IllegalArgumentException
096         *             if {@code value} is NaN or infinite or if the magnitude is too large for the float to be represented
097         *             as a {@code long}
098         */
099        public static final long floatToLong(DecimalRounding rounding, float value) {
100                if (Float.isNaN(value)) {
101                        throw new IllegalArgumentException("Cannot convert float to long: " + value);
102                }
103                if (isInLongRange(value)) {
104                        return (long) roundIntermediate(value, rounding);
105                }
106                throw new IllegalArgumentException("Overflow for conversion from float to long: " + value);
107        }
108
109        /*
110         * Copied from guava. This method returns a value y such that rounding y DOWN (towards zero) gives the same result
111         * as rounding x according to the specified mode. PRECONDITION: isFinite(x)
112         */
113        private static final float roundIntermediate(float x, DecimalRounding mode) {
114                switch (mode) {
115                case UNNECESSARY:
116                        if (!isMathematicalInteger(x)) {
117                                throw new ArithmeticException("Rounding necessary to convert to an integer value: " + x);
118                        }
119                        return x;
120                case FLOOR:
121                        if (x >= 0.0f || isMathematicalInteger(x)) {
122                                return x;
123                        } else {
124                                return (long)x - 1L;
125                        }
126                case CEILING:
127                        if (x <= 0.0f || isMathematicalInteger(x)) {
128                                return x;
129                        } else {
130                                return (long)x + 1L;
131                        }
132                case DOWN:
133                        return x;
134                case UP:
135                        if (isMathematicalInteger(x)) {
136                                return x;
137                        } else {
138                                return (long)x + (x > 0 ? 1L : -1L);
139                        }
140                case HALF_EVEN:
141                        return rint(x);
142                case HALF_UP: {
143                        final float z = rint(x);
144                        if (Math.abs(x - z) == 0.5f) {
145                                return x + Math.copySign(0.5f, x);
146                        } else {
147                                return z;
148                        }
149                }
150                case HALF_DOWN: {
151                        final float z = rint(x);
152                        if (Math.abs(x - z) == 0.5f) {
153                                return x;
154                        } else {
155                                return z;
156                        }
157                }
158                default:
159                        throw new IllegalArgumentException("Unsupported rounding mode: " + mode);
160                }
161        }
162
163        /**
164         * Converts the specified float value to an unscaled decimal truncating extra fractional digits if necessary. If the
165         * value is NaN, infinite or outside of the valid Decimal range, an exception is thrown.
166         * 
167         * @param arith
168         *            the arithmetic associated with the result value
169         * @param value
170         *            the value to convert
171         * @return <code>round(value)</code>
172         * @throws IllegalArgumentException
173         *             if {@code value} is NaN or infinite or if the magnitude is too large for the float to be represented
174         *             as a Decimal of the arithmetic's scale
175         */
176        public static final long floatToUnscaled(DecimalArithmetic arith, float value) {
177                return floatToUnscaled(arith, DecimalRounding.DOWN, value);
178        }
179
180        /**
181         * Converts the specified float value to an unscaled decimal. The specified {@code rounding} mode is used if
182         * rounding is necessary. If the value is NaN, infinite or outside of the valid Decimal range, an exception is
183         * thrown.
184         * 
185         * @param arith
186         *            the arithmetic associated with the result value
187         * @param rounding
188         *            the rounding to apply if necessary
189         * @param value
190         *            the value to convert
191         * @return <code>round(value)</code>
192         * @throws IllegalArgumentException
193         *             if {@code value} is NaN or infinite or if the magnitude is too large for the float to be represented
194         *             as a Decimal of the arithmetic's scale
195         * @throws ArithmeticException
196         *             if {@code roundingMode==UNNECESSARY} and rounding is necessary
197         */
198        public static final long floatToUnscaled(DecimalArithmetic arith, DecimalRounding rounding, float value) {
199                if (value == 0) {
200                        return 0;
201                }
202                final int exp = Math.getExponent(value);
203                if (exp >= Long.SIZE) {
204                        throw newOverflowException(arith, value);
205                }
206
207                // multiply significand by scale factor into a 128bit integer
208                final ScaleMetrics scaleMetrics = arith.getScaleMetrics();
209                final long significand = getSignificand(value);
210
211                // HD + Knuth's Algorithm M from [Knu2] section 4.3.1.
212                final int lFactor = (int) (significand & LONG_MASK);
213                final int hFactor = (int) (significand >>> 32);
214                final long w1, w2, w3;
215                long k, t;
216
217                t = scaleMetrics.mulloByScaleFactor(lFactor);
218                w3 = t & LONG_MASK;
219                k = t >>> 32;
220
221                t = scaleMetrics.mulloByScaleFactor(hFactor) + k;
222                w2 = t & LONG_MASK;
223                w1 = t >>> 32;
224
225                t = scaleMetrics.mulhiByScaleFactor(lFactor) + w2;
226                k = t >>> 32;
227
228                final long hScaled = scaleMetrics.mulhiByScaleFactor(hFactor) + w1 + k;
229                final long lScaled = (t << 32) + w3;
230
231                // now multiply or divide by powers of two as instructed by the float exponent
232                final int shift = exp - SIGNIFICAND_BITS;
233                return floatToUnscaledShift(arith, rounding, value, hScaled, lScaled, shift);
234        }
235
236        private static final long floatToUnscaledShift(DecimalArithmetic arith, DecimalRounding rounding, float value, long hScaled, long lScaled, int shift) {
237                if (shift > 0) {
238                        // multiply: shift left
239                        if (hScaled != 0) {
240                                throw newOverflowException(arith, value);
241                        }
242                        final int zeros = Long.numberOfLeadingZeros(lScaled);
243                        if (shift >= zeros) {
244                                throw newOverflowException(arith, value);
245                        }
246                        final long absResult = lScaled << shift;
247                        return value >= 0 ? absResult : -absResult;
248                } else if (shift == 0) {
249                        if (hScaled != 0 | lScaled < 0) {
250                                throw newOverflowException(arith, value);
251                        }
252                        return value >= 0 ? lScaled : -lScaled;
253                } else {// shift < 0
254                        // divide: shift right
255                        if (rounding == DecimalRounding.DOWN) {
256                                return floatToUnscaledShiftRight(arith, value, hScaled, lScaled, -shift);
257                        }
258                        return floatToUnscaledShiftRight(arith, rounding, value, hScaled, lScaled, -shift);
259                }
260        }
261
262        private static final long floatToUnscaledShiftRight(DecimalArithmetic arith, float value, long hScaled, long lScaled, int shift) {
263                final long absResult;
264                if (shift < Long.SIZE) {
265                        if ((hScaled >>> shift) != 0) {
266                                throw newOverflowException(arith, value);
267                        }
268                        absResult = (hScaled << (Long.SIZE - shift)) | (lScaled >>> shift);
269                } else if (shift < 2 * Long.SIZE) {
270                        absResult = (hScaled >>> (shift - Long.SIZE));
271                } else {
272                        return 0;// rounded down
273                }
274                if (absResult < 0) {
275                        throw newOverflowException(arith, value);
276                }
277                return value >= 0 ? absResult : -absResult;
278        }
279
280        private static final long floatToUnscaledShiftRight(DecimalArithmetic arith, DecimalRounding rounding, float value, long hScaled, long lScaled, int shift) {
281                final long absResult;
282                final TruncatedPart truncatedPart;
283                if (shift < Long.SIZE) {
284                        if ((hScaled >>> shift) != 0) {
285                                throw newOverflowException(arith, value);
286                        }
287                        absResult = (hScaled << (Long.SIZE - shift)) | (lScaled >>> shift);
288                        final long rem = modPow2(lScaled, shift);
289                        truncatedPart = Rounding.truncatedPartFor2powN(rem, shift);
290                } else if (shift < 2 * Long.SIZE) {
291                        absResult = (hScaled >>> (shift - Long.SIZE));
292                        final long rem = modPow2(hScaled, shift - Long.SIZE);
293                        truncatedPart = Rounding.truncatedPartFor2powN(rem, lScaled, shift);
294                } else {
295                        absResult = 0;// rounded down
296                        truncatedPart = Rounding.truncatedPartFor2powN(hScaled, lScaled, shift);
297                }
298                final int inc = absResult < 0 ? 0
299                                : rounding.calculateRoundingIncrement(value >= 0 ? 1 : -1, absResult, truncatedPart);
300                if (absResult < 0 | (value >= 0 & absResult == Long.MAX_VALUE & inc == 1)) {
301                        throw newOverflowException(arith, value);
302                }
303                return (value >= 0 ? absResult : -absResult) + inc;
304        }
305
306        /**
307         * Converts the specified long value to a float truncating extra mantissa digits if necessary.
308         * 
309         * @param arith
310         *            the arithmetic associated with the value
311         * @param value
312         *            the long value
313         * @return <code>round<sub>DOWN</sub>(value)</code>
314         */
315        public static final float longToFloat(DecimalArithmetic arith, long value) {
316                return unscaledToFloat(arith, DecimalRounding.DOWN, value);
317        }
318
319        /**
320         * Converts the specified long value to a float rounding extra mantissa digits if necessary.
321         * 
322         * @param arith
323         *            the arithmetic associated with the value
324         * @param rounding
325         *            the rounding to apply if necessary
326         * @param value
327         *            the long value
328         * @return <code>round(value)</code>
329         * @throws ArithmeticException
330         *             if {@code roundingMode==UNNECESSARY} and rounding is necessary
331         */
332        public static final float longToFloat(DecimalArithmetic arith, DecimalRounding rounding, long value) {
333                if (rounding == DecimalRounding.HALF_EVEN) {
334                        return value;
335                }
336                return unscaledToFloat(arith, rounding, value);
337        }
338
339        /**
340         * Converts the specified unscaled decimal value to a float truncating extra precision digits if necessary.
341         * 
342         * @param arith
343         *            the arithmetic associated with the value
344         * @param unscaled
345         *            the unscaled decimal value
346         * @return <code>round<sub>DOWN</sub>(value)</code>
347         */
348        public static final float unscaledToFloat(DecimalArithmetic arith, long unscaled) {
349                return unscaledToFloat(arith, DecimalRounding.DOWN, unscaled);
350        }
351
352        /**
353         * Converts the specified unscaled decimal value to a float rounding extra precision digits if necessary.
354         * 
355         * @param arith
356         *            the arithmetic associated with the value
357         * @param rounding
358         *            the rounding to apply if necessary
359         * @param unscaled
360         *            the unscaled decimal value
361         * @return <code>round(value)</code>
362         * @throws ArithmeticException
363         *             if {@code roundingMode==UNNECESSARY} and rounding is necessary
364         */
365        public static final float unscaledToFloat(DecimalArithmetic arith, DecimalRounding rounding, long unscaled) {
366                if (unscaled == 0) {
367                        return 0;
368                }
369                if (rounding == DecimalRounding.HALF_EVEN) {
370                        return (float)DoubleConversion.unscaledToDouble(arith, rounding, unscaled);
371                }
372
373                final ScaleMetrics scaleMetrics = arith.getScaleMetrics();
374                final long absUnscaled = Math.abs(unscaled);
375                
376                // eliminate sign and trailing power-of-2 zero bits
377                final int pow2 = Long.numberOfTrailingZeros(absUnscaled);
378                final long absVal = absUnscaled >>> pow2;
379                final int nlzAbsVal = Long.numberOfLeadingZeros(absVal);
380
381                /*
382                 * 1) we align absVal and factor such that: 2*factor > absVal >= factor then the division 
383                 *    absVal/factor == 1.xxxxx, i.e. it is normalized 
384                 * 2) because we omit the 1 in the mantissa, we calculate 
385                 *    valModFactor = absVal - floor(absVal/factor)*factor = absVal - 1*factor 
386                 * 3) we shift valModFactor such that the 1 from the division would be on bit 24 
387                 * 4) we perform the division
388                 */
389
390                // (1) + (2)
391                final int exp;
392                final int mantissaShift;
393                final long valModFactor;
394                final int alignShift = nlzAbsVal - scaleMetrics.getScaleFactorNumberOfLeadingZeros();
395                if (alignShift >= 0) {
396                        final long scaledAbsVal = absVal << alignShift;
397                        final long diff = scaledAbsVal - scaleMetrics.getScaleFactor();
398                        exp = -alignShift + (int) (diff >> 63);
399                        // if scaledAbsVal < factor we shift left by 1, i.e. we add the absVal
400                        valModFactor = diff + ((diff >> 63) & scaledAbsVal);
401                        mantissaShift = SIGNIFICAND_BITS;
402                } else {
403                        final long scaledFactor = scaleMetrics.getScaleFactor() << -alignShift;
404                        if (Unsigned.isLess(absVal, scaledFactor)) {
405                                exp = -alignShift - 1;
406                                // if absVal < scaledFactor we shift by 1 (right shift of scaledFactor to avoid overflow)
407                                valModFactor = absVal - (scaledFactor >>> 1);
408                                mantissaShift = SIGNIFICAND_BITS + alignShift + 1;
409                        } else {
410                                exp = -alignShift;
411                                valModFactor = absVal - scaledFactor;
412                                mantissaShift = SIGNIFICAND_BITS + alignShift;
413                        }
414                }
415                if (rounding == DecimalRounding.DOWN) {
416                        return unscaledToFloatShiftAndDivideByScaleFactor(scaleMetrics, unscaled, exp + pow2, mantissaShift,
417                                        valModFactor);
418                }
419                // (3) + (4)
420                return unscaledToFloatShiftAndDivideByScaleFactor(scaleMetrics, rounding, unscaled, exp + pow2, mantissaShift,
421                                valModFactor);
422        }
423
424        private static final float unscaledToFloatShiftAndDivideByScaleFactor(ScaleMetrics scaleMetrics, long unscaled, int exp, int mantissaShift, long valModFactor) {
425                final long quot;
426                if (mantissaShift >= 0) {
427                        final long hValModFactor = (valModFactor >>> (Long.SIZE - mantissaShift)) & (-mantissaShift >> 63);
428                        final long lValModFactor = valModFactor << mantissaShift;
429                        if (hValModFactor == 0) {
430                                quot = scaleMetrics.divideUnsignedByScaleFactor(lValModFactor);
431                        } else {
432                                quot = Math.abs(Div.div128by64(DecimalRounding.DOWN, unscaled < 0, hValModFactor, lValModFactor,
433                                                scaleMetrics.getScaleFactor()));
434                        }
435                } else {
436                        quot = scaleMetrics.divideByScaleFactor(valModFactor >>> -mantissaShift);
437                }
438                final int signBit = (int) ((unscaled >>> 32) & SIGN_MASK);
439                final int raw = signBit | ((exp + EXPONENT_BIAS) << SIGNIFICAND_BITS) | (int) (quot & SIGNIFICAND_MASK);
440                return Float.intBitsToFloat(raw);
441        }
442
443        private static final float unscaledToFloatShiftAndDivideByScaleFactor(ScaleMetrics scaleMetrics, DecimalRounding rounding, long unscaled, int exp, int mantissaShift, long valModFactor) {
444                final long quotient;
445                final long scaleFactor = scaleMetrics.getScaleFactor();
446                if (mantissaShift >= 0) {
447                        final long hValModFactor = (valModFactor >>> (Long.SIZE - mantissaShift)) & (-mantissaShift >> 63);
448                        final long lValModFactor = valModFactor << mantissaShift;
449                        if (hValModFactor == 0) {
450                                final long truncated = scaleMetrics.divideUnsignedByScaleFactor(lValModFactor);
451                                final long remainder = applySign(unscaled, lValModFactor - scaleMetrics.multiplyByScaleFactor(truncated));
452                                quotient = truncated
453                                                + Math.abs(Rounding.calculateRoundingIncrementForDivision(rounding, truncated, remainder, scaleFactor));
454                        } else {
455                                quotient = Math.abs(Div.div128by64(rounding, unscaled < 0, hValModFactor, lValModFactor, scaleFactor));
456                                // rounding already done by div128by64
457                        }
458                } else {
459                        final long scaledVal = valModFactor >>> -mantissaShift;
460                        final long truncated = scaleMetrics.divideByScaleFactor(scaledVal);
461                        final long remainder = applySign(unscaled, ((scaledVal - scaleMetrics.multiplyByScaleFactor(truncated)) << -mantissaShift)
462                                        | (valModFactor & (-1L >>> (Long.SIZE + mantissaShift))));
463                        // NOTE: below shift can overflow as min(mantissaShift)=-39 for scale=1, -38 for scale=10, ..., -21 for scale=10^18
464                        //               hence we use MAX_VALUE in this case, should always be more than 2x remainder (which is good enough for HALF_UP etc)
465                        final long shiftedScaleFactor = -mantissaShift >= scaleMetrics.getScaleFactorNumberOfLeadingZeros() ? Long.MAX_VALUE : scaleFactor << -mantissaShift;
466                        quotient = truncated + Math.abs(Rounding.calculateRoundingIncrementForDivision(rounding, truncated, remainder,
467                                        shiftedScaleFactor));
468                }
469                final int raw;
470                final int signBit = (int) ((unscaled >>> 32) & SIGN_MASK);
471                if (quotient <= SIGNIFICAND_MASK) {
472                        raw = signBit | ((exp + EXPONENT_BIAS) << SIGNIFICAND_BITS) | (int) (quotient & SIGNIFICAND_MASK);
473                } else {
474                        // rounding made our value to be 1 instead of smaller than one. 1 + 1 == 2 i.e. our mantissa is zero due to
475                        // the implicit 1 and our exponent increments by 1
476                        raw = signBit | ((exp + 1 + EXPONENT_BIAS) << SIGNIFICAND_BITS);
477                }
478                return Float.intBitsToFloat(raw);
479        }
480
481        // @return value % (2^n)
482        private static final long modPow2(long value, int n) {
483                // return value & ((1L << n) - 1);
484                return value & (-1L >>> (Long.SIZE - n)) & (-n >> 31);// last bracket is for case n=0
485        }
486
487        private static final long applySign(final long signed, final long value) {
488                return signed >= 0 ? value : -value;
489        }
490
491        private static final boolean isInLongRange(float value) {
492                return MIN_LONG_AS_FLOAT - value < 1.0f & value < MAX_LONG_AS_FLOAT_PLUS_ONE;
493        }
494
495        private static final boolean isMathematicalInteger(float x) {
496                return isFinite(x) && (x == 0.0f
497                                || SIGNIFICAND_BITS - Long.numberOfTrailingZeros(getSignificand(x)) <= Math.getExponent(x));
498        }
499
500        private static final boolean isFinite(float f) {
501                return Math.abs(f) <= Float.MAX_VALUE;
502        }
503
504        // PRECONDITION: isFinite(d)
505        private static final int getSignificand(float f) {
506                final int exponent = Math.getExponent(f);
507                int bits = Float.floatToRawIntBits(f);
508                bits &= SIGNIFICAND_MASK;
509                return (exponent == Float.MIN_EXPONENT - 1) ? bits << 1 : bits | IMPLICIT_BIT;
510        }
511
512        /**
513         * Returns the {@code float} value that is closest in value to the argument and is equal to a mathematical integer.
514         * If two {@code float} values that are mathematical integers are equally close to the value of the argument, the
515         * result is the integer value that is even. Special cases:
516         * <ul>
517         * <li>If the argument value is already equal to a mathematical integer, then the result is the same as the
518         * argument.
519         * <li>If the argument is NaN or an infinity or positive zero or negative zero, then the result is the same as the
520         * argument.
521         * </ul>
522         *
523         * @param a
524         *            a value.
525         * @return the closest floating-point value to {@code a} that is equal to a mathematical integer.
526         * @author Joseph D. Darcy
527         */
528        private static final float rint(float a) {
529                /*
530                 * If the absolute value of a is not less than 2^23, it is either a finite integer (the float format does not
531                 * have enough significand bits for a number that large to have any fractional portion), an infinity, or a NaN.
532                 * In any of these cases, rint of the argument is the argument.
533                 *
534                 * Otherwise, the sum (twoToThe23 + a ) will properly round away any fractional portion of a since
535                 * ulp(twoToThe23) == 1.0; subtracting out twoToThe23 from this sum will then be exact and leave the rounded
536                 * integer portion of a.
537                 *
538                 * This method does *not* need to be declared strictfp to get fully reproducible results. Whether or not a
539                 * method is declared strictfp can only make a difference in the returned result if some operation would
540                 * overflow or underflow with strictfp semantics. The operation (twoToThe23 + a ) cannot overflow since large
541                 * values of a are screened out; the add cannot underflow since twoToThe23 is too large. The subtraction
542                 * ((twoToThe23 + a ) - twoToThe23) will be exact as discussed above and thus cannot overflow or meaningfully
543                 * underflow. Finally, the last multiply in the return statement is by plus or minus 1.0, which is exact too.
544                 */
545                float twoToThe23 = (float) (1L << 23); // 2^23
546                float sign = Math.copySign(1.0f, a); // preserve sign info
547                a = Math.abs(a);
548
549                if (a < twoToThe23) { // E_min <= ilogb(a) <= 51
550                        a = ((twoToThe23 + a) - twoToThe23);
551                }
552
553                return sign * a; // restore original sign
554        }
555
556        private static final IllegalArgumentException newOverflowException(final DecimalArithmetic arith, double value) {
557                return new IllegalArgumentException(
558                                "Overflow for conversion from float to decimal with scale " + arith.getScale() + ": " + value);
559        }
560
561        // no instances
562        private FloatConversion() {
563                super();
564        }
565}