001/** 002 * The MIT License (MIT) 003 * 004 * Copyright (c) 2015-2016 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 <tt>round<sub>DOWN</sub>(value)</tt> 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 <tt>round(value)</tt> 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 <tt>round(value)</tt> 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 <tt>round(value)</tt> 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 <tt>round<sub>DOWN</sub>(value)</tt> 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 <tt>round(value)</tt> 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 <tt>round<sub>DOWN</sub>(value)</tt> 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 <tt>round(value)</tt> 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}