public static boolean fastRoundFractionalHalfUp5Words()

in kyuubi-hive-jdbc/src/main/java/org/apache/kyuubi/jdbc/hive/common/FastHiveDecimalImpl.java [5676:5827]


  public static boolean fastRoundFractionalHalfUp5Words(
      int fastSignum,
      long fast0,
      long fast1,
      long fast2,
      long fast3,
      long fast4,
      int scaleDown,
      FastHiveDecimal fastResult) {

    // Adjust all longs using power 10 division/remainder.
    long result0;
    long result1;
    long result2;
    long result3;
    long result4;
    if (scaleDown < LONGWORD_DECIMAL_DIGITS) {

      // Part of lowest word survives.

      // Divide down just before scaleDown to get round digit.
      final long withRoundDigit = fast0 / powerOfTenTable[scaleDown - 1];
      final long roundDigit = withRoundDigit % 10;

      final long divideFactor = powerOfTenTable[scaleDown];
      final long multiplyFactor = powerOfTenTable[LONGWORD_DECIMAL_DIGITS - scaleDown];

      if (roundDigit < 5) {
        result0 = withRoundDigit / 10 + ((fast1 % divideFactor) * multiplyFactor);
        result1 = fast1 / divideFactor + ((fast2 % divideFactor) * multiplyFactor);
        result2 = +fast2 / divideFactor + ((fast3 % divideFactor) * multiplyFactor);
        result3 = fast3 / divideFactor + ((fast4 % divideFactor) * multiplyFactor);
        result4 = fast4 / divideFactor;
      } else {
        // Add rounding and handle carry.
        final long r0 = withRoundDigit / 10 + ((fast1 % divideFactor) * multiplyFactor) + 1;
        result0 = r0 % MULTIPLER_LONGWORD_DECIMAL;
        final long r1 =
            fast1 / divideFactor
                + ((fast2 % divideFactor) * multiplyFactor)
                + r0 / MULTIPLER_LONGWORD_DECIMAL;
        result1 = r1 % MULTIPLER_LONGWORD_DECIMAL;
        final long r2 =
            fast2 / divideFactor
                + +((fast3 % divideFactor) * multiplyFactor)
                + r1 / MULTIPLER_LONGWORD_DECIMAL;
        result2 = r2 % MULTIPLER_LONGWORD_DECIMAL;
        final long r3 =
            fast3 / divideFactor
                + ((fast4 % divideFactor) * multiplyFactor)
                + r2 / MULTIPLER_LONGWORD_DECIMAL;
        result3 = r3 % MULTIPLER_LONGWORD_DECIMAL;
        result4 = fast4 / divideFactor + r3 % MULTIPLER_LONGWORD_DECIMAL;
      }
    } else if (scaleDown < TWO_X_LONGWORD_DECIMAL_DIGITS) {

      // Throw away lowest word.

      final int adjustedScaleDown = scaleDown - LONGWORD_DECIMAL_DIGITS;

      long roundDigit;
      long fast1Scaled;
      if (adjustedScaleDown == 0) {
        // Grab round digit from lowest word.
        roundDigit = fast0 / (MULTIPLER_LONGWORD_DECIMAL / 10);
        fast1Scaled = fast1;
      } else {
        // Divide down just before scaleDown to get round digit.
        final long withRoundDigit = fast1 / powerOfTenTable[adjustedScaleDown - 1];
        roundDigit = withRoundDigit % 10;
        fast1Scaled = withRoundDigit / 10;
      }

      final long divideFactor = powerOfTenTable[adjustedScaleDown];
      final long multiplyFactor = powerOfTenTable[LONGWORD_DECIMAL_DIGITS - adjustedScaleDown];

      if (roundDigit < 5) {
        result0 = fast1Scaled + ((fast2 % divideFactor) * multiplyFactor);
        result1 = fast2 / divideFactor + ((fast3 % divideFactor) * multiplyFactor);
        result2 = fast3 / divideFactor + ((fast4 % divideFactor) * multiplyFactor);
        result3 = fast4 / divideFactor;
      } else {
        // Add rounding and handle carry.
        final long r0 = fast1Scaled + ((fast2 % divideFactor) * multiplyFactor) + 1;
        result0 = r0 % MULTIPLER_LONGWORD_DECIMAL;
        final long r1 =
            fast2 / divideFactor
                + ((fast3 % divideFactor) * multiplyFactor)
                + r0 / MULTIPLER_LONGWORD_DECIMAL;
        result1 = r1 % MULTIPLER_LONGWORD_DECIMAL;
        final long r2 =
            fast3 / divideFactor
                + ((fast4 % divideFactor) * multiplyFactor)
                + r1 / MULTIPLER_LONGWORD_DECIMAL;
        result2 = r2 % MULTIPLER_LONGWORD_DECIMAL;
        result3 = fast4 / divideFactor + r2 / MULTIPLER_LONGWORD_DECIMAL;
      }
      result4 = 0;
    } else {

      // Throw away middle and lowest words.

      final int adjustedScaleDown = scaleDown - 2 * LONGWORD_DECIMAL_DIGITS;

      long roundDigit;
      long fast2Scaled;
      if (adjustedScaleDown == 0) {
        // Grab round digit from middle word.
        roundDigit = fast1 / (MULTIPLER_LONGWORD_DECIMAL / 10);
        fast2Scaled = fast2;
      } else {
        // Divide down just before scaleDown to get round digit.
        final long withRoundDigit = fast2 / powerOfTenTable[adjustedScaleDown - 1];
        roundDigit = withRoundDigit % 10;
        fast2Scaled = withRoundDigit / 10;
      }

      final long divideFactor = powerOfTenTable[adjustedScaleDown];
      final long multiplyFactor = powerOfTenTable[LONGWORD_DECIMAL_DIGITS - adjustedScaleDown];

      if (roundDigit < 5) {
        result0 = fast2Scaled + ((fast3 % divideFactor) * multiplyFactor);
        result1 = fast3 / divideFactor + ((fast4 % divideFactor) * multiplyFactor);
        result2 = fast4 / divideFactor;
      } else {
        // Add rounding.
        final long r0 = fast2Scaled + ((fast3 % divideFactor) * multiplyFactor) + 1;
        result0 = r0 % MULTIPLER_LONGWORD_DECIMAL;
        final long r1 =
            fast3 / divideFactor
                + ((fast4 % divideFactor) * multiplyFactor)
                + r0 / MULTIPLER_LONGWORD_DECIMAL;
        result1 = r1 % MULTIPLER_LONGWORD_DECIMAL;
        result2 = fast4 / divideFactor + r1 / MULTIPLER_LONGWORD_DECIMAL;
      }
      result3 = 0;
      result4 = 0;
    }

    if (result4 != 0 || result3 != 0) {
      throw new RuntimeException("Unexpected overflow into result3 or result4");
    }
    if (result0 == 0 && result1 == 0 && result2 == 0) {
      fastResult.fastReset();
    }
    fastResult.fastSignum = fastSignum;
    fastResult.fast0 = result0;
    fastResult.fast1 = result1;
    fastResult.fast2 = result2;

    return (result2 <= MAX_HIGHWORD_DECIMAL);
  }