public Decimal128 update(double val, short scale) {
    if (Double.isInfinite(val) || Double.isNaN(val)) {
      throw new NumberFormatException("Infinite or NaN");
    }

    checkScaleRange(scale);
    this.scale = scale;

    // Translate the double into sign, exponent and significand, according
    // to the formulae in JLS, Section 20.10.22.
    long valBits = Double.doubleToLongBits(val);
    byte sign = ((valBits >> 63) == 0 ? (byte) 1 : (byte) -1);
    short exponent = (short) ((valBits >> 52) & 0x7ffL);
    long significand = (exponent == 0 ? (valBits & ((1L << 52) - 1)) << 1
        : (valBits & ((1L << 52) - 1)) | (1L << 52));
    exponent -= 1075;

    // zero check
    if (significand == 0) {
      zeroClear();
      return this;
    }

    this.signum = sign;

    // Normalize
    while ((significand & 1) == 0) { // i.e., significand is even
      significand >>= 1;
      exponent++;
    }

    // so far same as java.math.BigDecimal, but the scaling below is
    // specific to ANSI SQL Numeric.

    // first, underflow is NOT an error in ANSI SQL Numeric.
    // CAST(0.000000000....0001 AS DECIMAL(38,1)) is "0.0" without an error.

    // second, overflow IS an error in ANSI SQL Numeric.
    // CAST(10000 AS DECIMAL(38,38)) throws overflow error.

    // val == sign * significand * 2**exponent.
    // this == sign * unscaledValue / 10**scale.
    // so, to make val==this, we need to scale it up/down such that:
    // unscaledValue = significand * 2**exponent * 10**scale
    // Notice that we must do the scaling carefully to check overflow and
    // preserve precision.
    this.unscaledValue.update(significand);
    if (exponent >= 0) {

      // both parts are scaling up. easy. Just check overflow.
      this.unscaledValue.shiftLeftDestructiveCheckOverflow(exponent);
      this.unscaledValue.scaleUpTenDestructive(scale);
    } else {

      // 2**exponent part is scaling down while 10**scale is scaling up.
      // Now it's tricky.
      // unscaledValue = significand * 10**scale / 2**twoScaleDown
      short twoScaleDown = (short) -exponent;
      if (scale >= twoScaleDown) {

        // make both scaling up as follows
        // unscaledValue = significand * 5**(scale) *
        // 2**(scale-twoScaleDown)
        this.unscaledValue.shiftLeftDestructiveCheckOverflow(scale
            - twoScaleDown);
        this.unscaledValue.scaleUpFiveDestructive(scale);
      } else {

        // Gosh, really both scaling up and down.
        // unscaledValue = significand * 5**(scale) /
        // 2**(twoScaleDown-scale)
        // To check overflow while preserving precision, we need to do a
        // real multiplication
        this.unscaledValue.multiplyShiftDestructive(
            SqlMathUtil.POWER_FIVES_INT128[scale],
            (short) (twoScaleDown - scale));
      }
    }
    return this;
  }
Update the value of this object with the given {@code double}. in the given
scaling. Note that, unlike java.math.BigDecimal, the scaling is given as
the parameter, not automatically detected. This is one of the differences
between ANSI SQL Numeric and Java's BigDecimal. See class comments for more
details.
<p>
Unchecked exceptions: ArithmeticException if {@code val} overflows in the
scaling. NumberFormatException if {@code val} is infinite or NaN.
</p>

@param val
         {@code double} value to be converted to {@code Decimal128}.
@param scale
         scale of the {@code Decimal128}.
common/src/java/org/apache/hadoop/hive/common/type/Decimal128.java