MathEx.cs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using System.Runtime.CompilerServices;
  2. #if NET6_0_OR_GREATER
  3. using System.Numerics;
  4. #endif
  5. namespace Lua;
  6. 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. var 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. {
  57. d += d;
  58. }
  59. else
  60. {
  61. // Not zero and finite.
  62. e = exp - 1022;
  63. if (exp == 0)
  64. {
  65. // Subnormal, scale d so that it is in [1, 2).
  66. d *= BitConverter.Int64BitsToDouble(0x4350000000000000L); // 2^54
  67. bits = BitConverter.DoubleToInt64Bits(d);
  68. exp = (int)((bits & DBL_EXP_MASK) >> DBL_MANT_BITS);
  69. e = exp - 1022 - 54;
  70. }
  71. // Set exponent to -1 so that d is in [0.5, 1).
  72. d = BitConverter.Int64BitsToDouble((bits & DBL_EXP_CLR_MASK) | 0x3fe0000000000000L);
  73. }
  74. return (d, e);
  75. }
  76. public static (int i, double f) Modf(double d)
  77. {
  78. return ((int)Math.Truncate(d), d % 1.0);
  79. }
  80. /// <summary>Returns the smallest power of two greater than or equal to the input.</summary>
  81. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  82. public static int NextPowerOfTwo(int x)
  83. {
  84. #if NET6_0_OR_GREATER
  85. if (x <= 0)
  86. {
  87. return 0;
  88. }
  89. return (int)BitOperations.RoundUpToPowerOf2((uint)x);
  90. #else
  91. if (x <= 0) return 0;
  92. x -= 1;
  93. x |= x >> 1;
  94. x |= x >> 2;
  95. x |= x >> 4;
  96. x |= x >> 8;
  97. x |= x >> 16;
  98. return x + 1;
  99. #endif
  100. }
  101. }