FloatUtils.h 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // Copyright 2018 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #pragma once
  4. #include <array>
  5. #include <bit>
  6. #include <limits>
  7. #include "Common/CommonTypes.h"
  8. namespace Common
  9. {
  10. template <typename T>
  11. constexpr T SNANConstant()
  12. {
  13. return std::numeric_limits<T>::signaling_NaN();
  14. }
  15. // The most significant bit of the fraction is an is-quiet bit on all architectures we care about.
  16. static constexpr u64 DOUBLE_QBIT = 0x0008000000000000ULL;
  17. static constexpr u64 DOUBLE_SIGN = 0x8000000000000000ULL;
  18. static constexpr u64 DOUBLE_EXP = 0x7FF0000000000000ULL;
  19. static constexpr u64 DOUBLE_FRAC = 0x000FFFFFFFFFFFFFULL;
  20. static constexpr u64 DOUBLE_ZERO = 0x0000000000000000ULL;
  21. static constexpr int DOUBLE_EXP_WIDTH = 11;
  22. static constexpr int DOUBLE_FRAC_WIDTH = 52;
  23. static constexpr u32 FLOAT_SIGN = 0x80000000;
  24. static constexpr u32 FLOAT_EXP = 0x7F800000;
  25. static constexpr u32 FLOAT_FRAC = 0x007FFFFF;
  26. static constexpr u32 FLOAT_ZERO = 0x00000000;
  27. static constexpr int FLOAT_EXP_WIDTH = 8;
  28. static constexpr int FLOAT_FRAC_WIDTH = 23;
  29. inline bool IsQNAN(double d)
  30. {
  31. const u64 i = std::bit_cast<u64>(d);
  32. return ((i & DOUBLE_EXP) == DOUBLE_EXP) && ((i & DOUBLE_QBIT) == DOUBLE_QBIT);
  33. }
  34. inline bool IsSNAN(double d)
  35. {
  36. const u64 i = std::bit_cast<u64>(d);
  37. return ((i & DOUBLE_EXP) == DOUBLE_EXP) && ((i & DOUBLE_FRAC) != DOUBLE_ZERO) &&
  38. ((i & DOUBLE_QBIT) == DOUBLE_ZERO);
  39. }
  40. inline float FlushToZero(float f)
  41. {
  42. u32 i = std::bit_cast<u32>(f);
  43. if ((i & FLOAT_EXP) == 0)
  44. {
  45. // Turn into signed zero
  46. i &= FLOAT_SIGN;
  47. }
  48. return std::bit_cast<float>(i);
  49. }
  50. inline double FlushToZero(double d)
  51. {
  52. u64 i = std::bit_cast<u64>(d);
  53. if ((i & DOUBLE_EXP) == 0)
  54. {
  55. // Turn into signed zero
  56. i &= DOUBLE_SIGN;
  57. }
  58. return std::bit_cast<double>(i);
  59. }
  60. enum PPCFpClass
  61. {
  62. PPC_FPCLASS_QNAN = 0x11,
  63. PPC_FPCLASS_NINF = 0x9,
  64. PPC_FPCLASS_NN = 0x8,
  65. PPC_FPCLASS_ND = 0x18,
  66. PPC_FPCLASS_NZ = 0x12,
  67. PPC_FPCLASS_PZ = 0x2,
  68. PPC_FPCLASS_PD = 0x14,
  69. PPC_FPCLASS_PN = 0x4,
  70. PPC_FPCLASS_PINF = 0x5,
  71. };
  72. // Uses PowerPC conventions for the return value, so it can be easily
  73. // used directly in CPU emulation.
  74. u32 ClassifyDouble(double dvalue);
  75. u32 ClassifyFloat(float fvalue);
  76. struct BaseAndDec
  77. {
  78. int m_base;
  79. int m_dec;
  80. };
  81. extern const std::array<BaseAndDec, 32> frsqrte_expected;
  82. extern const std::array<BaseAndDec, 32> fres_expected;
  83. // PowerPC approximation algorithms
  84. double ApproximateReciprocalSquareRoot(double val);
  85. double ApproximateReciprocal(double val);
  86. } // namespace Common