| 332 | template<typename T> |
| 333 | template<typename RESULT_T> |
| 334 | inline DecimalValue<RESULT_T> DecimalValue<T>::Add(int this_scale, |
| 335 | const DecimalValue& other, int other_scale, int result_precision, int result_scale, |
| 336 | bool round, bool* overflow) const { |
| 337 | |
| 338 | if (sizeof(RESULT_T) < 16 || result_precision < 38) { |
| 339 | // The following check is guaranteed by the frontend. |
| 340 | DCHECK_EQ(result_scale, std::max(this_scale, other_scale)); |
| 341 | RESULT_T x = 0; |
| 342 | RESULT_T y = 0; |
| 343 | AdjustToSameScale(*this, this_scale, other, other_scale, result_precision, &x, &y); |
| 344 | return DecimalValue<RESULT_T>(x + y); |
| 345 | } |
| 346 | |
| 347 | // Compute how many leading zeros x and y would have after one of them gets scaled |
| 348 | // up to match the scale of the other one. |
| 349 | int min_lz = detail::MinLeadingZeros( |
| 350 | abs(value()), this_scale, abs(other.value()), other_scale); |
| 351 | int result_scale_decrease = std::max( |
| 352 | this_scale - result_scale, other_scale - result_scale); |
| 353 | DCHECK_GE(result_scale_decrease, 0); |
| 354 | |
| 355 | const int MIN_LZ = 3; |
| 356 | if (min_lz >= MIN_LZ) { |
| 357 | // If both numbers have at least MIN_LZ leading zeros, we can add them directly |
| 358 | // without the risk of overflow. |
| 359 | // We want the result to have at least 2 leading zeros, which ensures that it fits |
| 360 | // into the maximum decimal because 2^126 - 1 < 10^38 - 1. If both x and y have at |
| 361 | // least 3 leading zeros, then we are guaranteed that the result will have at lest 2 |
| 362 | // leading zeros. |
| 363 | RESULT_T x = 0; |
| 364 | RESULT_T y = 0; |
| 365 | AdjustToSameScale(*this, this_scale, other, other_scale, result_precision, &x, &y); |
| 366 | DCHECK(abs(x) <= MAX_UNSCALED_DECIMAL16 - abs(y)); |
| 367 | x += y; |
| 368 | if (result_scale_decrease > 0) { |
| 369 | // After first adjusting x and y to the same scale and adding them together, we now |
| 370 | // need scale down the result to result_scale. |
| 371 | x = DecimalUtil::ScaleDownAndRound<RESULT_T>(x, result_scale_decrease, round); |
| 372 | } |
| 373 | return DecimalValue<RESULT_T>(x); |
| 374 | } |
| 375 | |
| 376 | // If both numbers cannot be added directly, we have to resort to a more complex |
| 377 | // and slower algorithm. |
| 378 | int128_t x = value(); |
| 379 | int128_t y = other.value(); |
| 380 | int128_t result; |
| 381 | |
| 382 | if (x >= 0 && y >= 0) { |
| 383 | result = detail::AddLarge( |
| 384 | x, this_scale, y, other_scale, result_scale, round, overflow); |
| 385 | } else if (x <= 0 && y <= 0) { |
| 386 | result = -detail::AddLarge( |
| 387 | -x, this_scale, -y, other_scale, result_scale, round, overflow); |
| 388 | } else { |
| 389 | result = detail::SubtractLarge( |
| 390 | x, this_scale, y, other_scale, result_scale, round, overflow); |
| 391 | } |
nothing calls this directly
no test coverage detected