Right shift positive `x` by positive `bits`, rounded half to even
| 1314 | |
| 1315 | // Right shift positive `x` by positive `bits`, rounded half to even |
| 1316 | static Decimal256 RoundedRightShift(Decimal256 x, int bits) { |
| 1317 | if (bits == 0) { |
| 1318 | return x; |
| 1319 | } |
| 1320 | const int cross_word_shift = bits / 64; |
| 1321 | if (cross_word_shift >= Decimal256::kNumWords) { |
| 1322 | return Decimal256(); |
| 1323 | } |
| 1324 | const uint32_t in_word_shift = bits % 64; |
| 1325 | const auto array_le = x.little_endian_array(); |
| 1326 | Decimal256::WordArray shifted_le{}; |
| 1327 | uint64_t shifted_out = 0; |
| 1328 | // Iterate from LSW to MSW |
| 1329 | for (int i = 0; i < cross_word_shift; ++i) { |
| 1330 | // Retain the information that non-zero bits were shifted out. |
| 1331 | // This is important for half-to-even rounding. |
| 1332 | shifted_out = (shifted_out > 0) | array_le[i]; |
| 1333 | } |
| 1334 | if (in_word_shift != 0) { |
| 1335 | const uint64_t carry_bits = array_le[cross_word_shift] << (64 - in_word_shift); |
| 1336 | shifted_out = (shifted_out > 0) | (shifted_out >> in_word_shift) | carry_bits; |
| 1337 | } |
| 1338 | for (int i = cross_word_shift; i < Decimal256::kNumWords; ++i) { |
| 1339 | shifted_le[i - cross_word_shift] = array_le[i] >> in_word_shift; |
| 1340 | if (in_word_shift != 0 && i + 1 < Decimal256::kNumWords) { |
| 1341 | const uint64_t carry_bits = array_le[i + 1] << (64 - in_word_shift); |
| 1342 | shifted_le[i - cross_word_shift] |= carry_bits; |
| 1343 | } |
| 1344 | } |
| 1345 | auto result = Decimal256(Decimal256::LittleEndianArray, shifted_le); |
| 1346 | |
| 1347 | // We almost have our result, but now do the rounding. |
| 1348 | constexpr uint64_t kHalf = 0x8000000000000000ULL; |
| 1349 | if (shifted_out > kHalf) { |
| 1350 | // Strictly more than half => round up |
| 1351 | result += 1; |
| 1352 | } else if (shifted_out == kHalf) { |
| 1353 | // Exactly half => round to even |
| 1354 | if ((result.low_bits() & 1) != 0) { |
| 1355 | result += 1; |
| 1356 | } |
| 1357 | } else { |
| 1358 | // Strictly less than half => round down |
| 1359 | } |
| 1360 | return result; |
| 1361 | } |
| 1362 | |
| 1363 | template <typename Real> |
| 1364 | static Result<Decimal256> FromPositiveRealApprox(Real real, int32_t precision, |
nothing calls this directly
no test coverage detected