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);
}