MCPcopy Create free account
hub / github.com/apache/impala / SubtractLarge

Function SubtractLarge

be/src/runtime/decimal-value.inline.h:279–328  ·  view source on GitHub ↗

Subtracts numbers that are large enough so that we can't subtract directly. Neither of the numbers can be zero and one must be positive and the other one negative.

Source from the content-addressed store, hash-verified

277// Subtracts numbers that are large enough so that we can't subtract directly. Neither
278// of the numbers can be zero and one must be positive and the other one negative.
279inline int128_t SubtractLarge(int128_t x, int x_scale, int128_t y, int y_scale,
280 int result_scale, bool round, bool *overflow) {
281 DCHECK(x != 0 && y != 0);
282 DCHECK((x > 0) != (y > 0));
283
284 int128_t left, right, x_left, x_right, y_left, y_right;
285 SeparateFractional(x, x_scale, y, y_scale, &x_left, &x_right, &y_left, &y_right);
286
287 int max_scale = std::max(x_scale, y_scale);
288 int result_scale_decrease = max_scale - result_scale;
289 DCHECK_GE(result_scale_decrease, 0);
290
291 left = x_left + y_left;
292 right = x_right + y_right;
293 // Overflow is not possible because one number is positive and the other one is
294 // negative.
295 DCHECK(abs(left) <= MAX_UNSCALED_DECIMAL16);
296 DCHECK(abs(right) <= MAX_UNSCALED_DECIMAL16);
297 // If the whole and fractional parts have different signs, then we need to make the
298 // fractional part have the same sign as the whole part. If either left or right is
299 // zero, then nothing needs to be done.
300 if (left < 0 && right > 0) {
301 left += 1;
302 right -= DecimalUtil::GetScaleMultiplier<int128_t>(max_scale);
303 } else if (left > 0 && right < 0) {
304 left -= 1;
305 right += DecimalUtil::GetScaleMultiplier<int128_t>(max_scale);
306 }
307 // The operation above brought left closer to zero.
308 DCHECK(abs(left) <= abs(x_left + y_left));
309 if (result_scale_decrease > 0) {
310 // At this point, the scale of the fractional part is either x_scale or y_scale,
311 // whichever is greater. We scale down the fractional part to result_scale here.
312 right = DecimalUtil::ScaleDownAndRound<int128_t>(
313 right, result_scale_decrease, round);
314 }
315
316 // Check that left and right have the same sign.
317 DCHECK(left == 0 || right == 0 || (left > 0) == (right > 0));
318 // It is possible that right gets rounded up after scaling down (and it would look like
319 // it overflowed). This does not need to be handled in a special way and will result
320 // in incrementing the whole part by one.
321 DCHECK(abs(right) <= DecimalUtil::GetScaleMultiplier<int128_t>(result_scale));
322
323 int128_t mult = DecimalUtil::GetScaleMultiplier<int128_t>(result_scale);
324 if (UNLIKELY(abs(left) > (MAX_UNSCALED_DECIMAL16 - abs(right)) / mult)) {
325 *overflow = true;
326 }
327 return DecimalUtil::SafeMultiply(left, mult, *overflow) + right;
328}
329
330}
331

Callers 1

AddMethod · 0.85

Calls 3

SeparateFractionalFunction · 0.85
maxFunction · 0.85
absFunction · 0.85

Tested by

no test coverage detected