/ tests / fp / mantissa_util_tests.cpp
mantissa_util_tests.cpp
 1  /* This file is part of the dynarmic project.
 2   * Copyright (c) 2018 MerryMage
 3   * SPDX-License-Identifier: 0BSD
 4   */
 5  
 6  #include <tuple>
 7  #include <vector>
 8  
 9  #include <catch2/catch_test_macros.hpp>
10  #include <mcl/stdint.hpp>
11  
12  #include "../rand_int.h"
13  #include "dynarmic/common/fp/mantissa_util.h"
14  #include "dynarmic/common/safe_ops.h"
15  
16  using namespace Dynarmic;
17  using namespace Dynarmic::FP;
18  
19  TEST_CASE("ResidualErrorOnRightShift", "[fp]") {
20      const std::vector<std::tuple<u32, int, ResidualError>> test_cases{
21          {0x00000001, 1, ResidualError::Half},
22          {0x00000002, 1, ResidualError::Zero},
23          {0x00000001, 2, ResidualError::LessThanHalf},
24          {0x00000002, 2, ResidualError::Half},
25          {0x00000003, 2, ResidualError::GreaterThanHalf},
26          {0x00000004, 2, ResidualError::Zero},
27          {0x00000005, 2, ResidualError::LessThanHalf},
28          {0x00000006, 2, ResidualError::Half},
29          {0x00000007, 2, ResidualError::GreaterThanHalf},
30      };
31  
32      for (auto [mantissa, shift, expected_result] : test_cases) {
33          const ResidualError result = ResidualErrorOnRightShift(mantissa, shift);
34          REQUIRE(result == expected_result);
35      }
36  }
37  
38  TEST_CASE("ResidualErrorOnRightShift Randomized", "[fp]") {
39      for (size_t test = 0; test < 100000; test++) {
40          const u64 mantissa = mcl::bit::sign_extend<32, u64>(RandInt<u32>(0, 0xFFFFFFFF));
41          const int shift = RandInt<int>(-60, 60);
42  
43          const ResidualError result = ResidualErrorOnRightShift(mantissa, shift);
44  
45          const u64 calculated_error = Safe::ArithmeticShiftRightDouble(mantissa, u64(0), shift);
46          const ResidualError expected_result = [&] {
47              constexpr u64 half_error = 0x8000'0000'0000'0000ull;
48              if (calculated_error == 0) {
49                  return ResidualError::Zero;
50              }
51              if (calculated_error < half_error) {
52                  return ResidualError::LessThanHalf;
53              }
54              if (calculated_error == half_error) {
55                  return ResidualError::Half;
56              }
57              return ResidualError::GreaterThanHalf;
58          }();
59  
60          INFO(std::hex << "mantissa " << mantissa << " shift " << shift << " calculated_error " << calculated_error);
61          REQUIRE(result == expected_result);
62      }
63  }