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.
| 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. |
| 279 | inline 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 |
no test coverage detected