|
2 | 2 |
|
3 | 3 | namespace Lua.Tests; |
4 | 4 |
|
5 | | -public class MathematicsLibraryReviewTests |
| 5 | +public class MathematicsLibraryTests |
6 | 6 | { |
7 | 7 | static LuaState CreateState() |
8 | 8 | { |
@@ -66,31 +66,61 @@ public async Task AngleConversionsAndFrexpPreserveBothZeroSigns() |
66 | 66 | Assert.That(values[1].Read<double>(), Is.Zero); |
67 | 67 | } |
68 | 68 | } |
69 | | -} |
70 | 69 |
|
71 | | -public class FrexpReconstructionTests |
72 | | -{ |
73 | | - [Test] |
74 | | - public void FiniteValuesNormalizeAndReconstructBitExactly() |
| 70 | + [TestCase(-0.0)] |
| 71 | + [TestCase(-1d)] |
| 72 | + [TestCase(-1.5)] |
| 73 | + [TestCase(1e20)] |
| 74 | + [TestCase(-1e20)] |
| 75 | + [TestCase(double.Epsilon)] |
| 76 | + [TestCase(-double.Epsilon)] |
| 77 | + [TestCase(double.PositiveInfinity)] |
| 78 | + [TestCase(double.NegativeInfinity)] |
| 79 | + [TestCase(double.NaN)] |
| 80 | + public async Task ModfKeepsDoubleRangeAndSignedFractionalZero(double number) |
75 | 81 | { |
76 | | - var random = new Random(0x52); |
77 | | - for (var i = 0; i < 4096; i++) |
| 82 | + using var state = CreateState(); |
| 83 | + var values = await state.CallAsync( |
| 84 | + state.Environment["math"].Read<LuaTable>()["modf"], |
| 85 | + [number] |
| 86 | + ); |
| 87 | + var integral = values[0].Read<double>(); |
| 88 | + var fraction = values[1].Read<double>(); |
| 89 | + if (double.IsNaN(number)) |
78 | 90 | { |
79 | | - var bits = random.NextInt64(long.MinValue, long.MaxValue); |
80 | | - if ((i & 1) == 0) |
81 | | - bits &= unchecked((long)0x800fffffffffffff); // Include subnormals. |
82 | | - var input = BitConverter.Int64BitsToDouble(bits); |
83 | | - if (!double.IsFinite(input)) |
84 | | - continue; |
85 | | - var (mantissa, exponent) = MathEx.Frexp(input); |
86 | | - if (input == 0) |
87 | | - Assert.That(exponent, Is.Zero); |
88 | | - else |
89 | | - Assert.That(Math.Abs(mantissa), Is.GreaterThanOrEqualTo(0.5).And.LessThan(1)); |
| 91 | + Assert.That(double.IsNaN(integral) && double.IsNaN(fraction), Is.True); |
| 92 | + return; |
| 93 | + } |
| 94 | + Assert.That( |
| 95 | + BitConverter.DoubleToInt64Bits(integral), |
| 96 | + Is.EqualTo(BitConverter.DoubleToInt64Bits(Math.Truncate(number))) |
| 97 | + ); |
| 98 | + if (double.IsInfinity(number) || number == Math.Truncate(number)) |
90 | 99 | Assert.That( |
91 | | - BitConverter.DoubleToInt64Bits(Math.ScaleB(mantissa, exponent)), |
92 | | - Is.EqualTo(bits) |
| 100 | + BitConverter.DoubleToInt64Bits(fraction), |
| 101 | + Is.EqualTo(BitConverter.DoubleToInt64Bits(number) & long.MinValue) |
93 | 102 | ); |
94 | | - } |
| 103 | + else |
| 104 | + Assert.That(integral + fraction, Is.EqualTo(number)); |
| 105 | + } |
| 106 | + |
| 107 | + [Test] |
| 108 | + public async Task RandomSeedsAreNumericAndRepeatable() |
| 109 | + { |
| 110 | + using var state = CreateState(); |
| 111 | + await state.DoStringAsync( |
| 112 | + """ |
| 113 | + local function sequence(seed) |
| 114 | + math.randomseed(seed) |
| 115 | + local t={}; for i=1,8 do t[i]=math.random() end |
| 116 | + return table.concat(t,',') |
| 117 | + end |
| 118 | + assert(sequence(1)==sequence(1)) |
| 119 | + assert(sequence(1)~=sequence(2)) |
| 120 | + assert(sequence('1')==sequence(1)) |
| 121 | + assert(sequence(1.5)==sequence(2)) |
| 122 | + assert(sequence(1+2^32)==sequence(1)) |
| 123 | + """ |
| 124 | + ); |
95 | 125 | } |
96 | 126 | } |
0 commit comments