MathEx.cs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. using System.Runtime.CompilerServices;
  2. #if NET6_0_OR_GREATER
  3. using System.Numerics;
  4. #endif
  5. namespace Lua;
  6. internal static class MathEx
  7. {
  8. const ulong PositiveInfinityBits = 0x7FF0_0000_0000_0000;
  9. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  10. public static bool IsInteger(double d)
  11. {
  12. #if NET8_0_OR_GREATER
  13. return double.IsInteger(d);
  14. #else
  15. return IsFinite(d) && (d == Math.Truncate(d));
  16. #endif
  17. }
  18. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  19. public static unsafe bool IsFinite(double d)
  20. {
  21. #if NET6_0_OR_GREATER
  22. ulong bits = BitConverter.DoubleToUInt64Bits(d);
  23. #else
  24. ulong bits = BitCast<double, ulong>(d);
  25. #endif
  26. return (~bits & PositiveInfinityBits) != 0;
  27. }
  28. #if !NET6_0_OR_GREATER
  29. unsafe static TTo BitCast<TFrom, TTo>(TFrom source)
  30. {
  31. return Unsafe.ReadUnaligned<TTo>(ref Unsafe.As<TFrom, byte>(ref source));
  32. }
  33. #endif
  34. public const int ArrayMexLength = 0x7FFFFFC7;
  35. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  36. public static int NewArrayCapacity(int size)
  37. {
  38. var newSize = unchecked(size * 2);
  39. if ((uint)newSize > ArrayMexLength)
  40. {
  41. newSize = ArrayMexLength;
  42. }
  43. return newSize;
  44. }
  45. const long DBL_EXP_MASK = 0x7ff0000000000000L;
  46. const int DBL_MANT_BITS = 52;
  47. const long DBL_SGN_MASK = -1 - 0x7fffffffffffffffL;
  48. const long DBL_MANT_MASK = 0x000fffffffffffffL;
  49. const long DBL_EXP_CLR_MASK = DBL_SGN_MASK | DBL_MANT_MASK;
  50. public static (double m, int e) Frexp(double d)
  51. {
  52. var bits = BitConverter.DoubleToInt64Bits(d);
  53. var exp = (int)((bits & DBL_EXP_MASK) >> DBL_MANT_BITS);
  54. var e = 0;
  55. if (exp == 0x7ff || d == 0D)
  56. d += d;
  57. else
  58. {
  59. // Not zero and finite.
  60. e = exp - 1022;
  61. if (exp == 0)
  62. {
  63. // Subnormal, scale d so that it is in [1, 2).
  64. d *= BitConverter.Int64BitsToDouble(0x4350000000000000L); // 2^54
  65. bits = BitConverter.DoubleToInt64Bits(d);
  66. exp = (int)((bits & DBL_EXP_MASK) >> DBL_MANT_BITS);
  67. e = exp - 1022 - 54;
  68. }
  69. // Set exponent to -1 so that d is in [0.5, 1).
  70. d = BitConverter.Int64BitsToDouble((bits & DBL_EXP_CLR_MASK) | 0x3fe0000000000000L);
  71. }
  72. return (d, e);
  73. }
  74. public static (int i, double f) Modf(double d)
  75. {
  76. return ((int)Math.Truncate(d), d % 1.0);
  77. }
  78. /// <summary>Returns the smallest power of two greater than or equal to the input.</summary>
  79. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  80. public static int NextPowerOfTwo(int x)
  81. {
  82. #if NET6_0_OR_GREATER
  83. if (x <= 0) return 0;
  84. return (int)BitOperations.RoundUpToPowerOf2((uint)x);
  85. #else
  86. if (x <= 0) return 0;
  87. x -= 1;
  88. x |= x >> 1;
  89. x |= x >> 2;
  90. x |= x >> 4;
  91. x |= x >> 8;
  92. x |= x >> 16;
  93. return x + 1;
  94. #endif
  95. }
  96. }