-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMathsTest.bb
More file actions
201 lines (174 loc) · 6.23 KB
/
Copy pathMathsTest.bb
File metadata and controls
201 lines (174 loc) · 6.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
Strict
EnableGC
; --- Arithmetic operators (compiler codegen) ---
Test AdditionTest()
Assert( 1 + 1 = 2 )
End Test
Test SubtractionTest()
Assert( 2 - 1 = 1 )
End Test
Test MultiplicationTest()
Assert( 2 * 2 = 4 )
End Test
Test DivisionTest()
Assert( 4 / 2 = 2 )
End Test
; --- Math library (bbmath.cpp) ---
; Float helper: Assert takes a bool, and exact float equality is fragile, so
; compare within a small epsilon. Avoids Abs() to keep the type unambiguous.
Function FloatClose%( a#, b# )
Local d# = a - b
If d < 0.0 Then d = -d
Return ( d < 0.0001 )
End Function
; Guard helpers for the scientific-notation tests below: names begin with 'e' but
; are NOT valid float exponents ([eE][+-]?<digit>), so the lexer must treat them as
; identifiers, never swallow them into a preceding float literal.
Function e#()
Return 0.0
End Function
Function identExp#()
Return 0.0
End Function
; Trig is DEGREE-based in Blitz (Sin(90)=1, not Sin(pi/2)). This is a deliberate,
; non-obvious contract; pin it so a future "fix" to radians is caught.
Test testDegreeTrig()
Assert( FloatClose( Sin(0.0), 0.0 ) )
Assert( FloatClose( Sin(90.0), 1.0 ) )
Assert( FloatClose( Sin(30.0), 0.5 ) )
Assert( FloatClose( Cos(0.0), 1.0 ) )
Assert( FloatClose( Cos(90.0), 0.0 ) )
Assert( FloatClose( Tan(45.0), 1.0 ) )
End Test
Test testInverseTrig()
Assert( FloatClose( ASin(1.0), 90.0 ) )
Assert( FloatClose( ACos(0.0), 90.0 ) )
Assert( FloatClose( ATan(1.0), 45.0 ) )
Assert( FloatClose( ATan2(1.0, 1.0), 45.0 ) )
End Test
Test testSqrFloorCeil()
Assert( FloatClose( Sqr(9.0), 3.0 ) )
Assert( FloatClose( Sqr(2.0), 1.41421 ) )
Assert( Floor(2.7) = 2 )
Assert( Floor(-2.1) = -3 )
Assert( Ceil(2.1) = 3 )
Assert( Ceil(-2.9) = -2 )
End Test
Test testExpLog()
Assert( FloatClose( Exp(0.0), 1.0 ) )
Assert( FloatClose( Log(1.0), 0.0 ) )
Assert( FloatClose( Log10(1000.0), 3.0 ) )
End Test
; --- Deterministic PRNG (bbmath.cpp Lehmer LCG) ---
; Seeding makes the stream reproducible. rcce2 and seeded games depend on this.
Test testSeedRndReproducible()
SeedRnd( 1234 )
Local a1 = Rand( 1, 1000000 )
Local a2 = Rand( 1, 1000000 )
Local a3 = Rand( 1, 1000000 )
SeedRnd( 1234 )
Assert( Rand( 1, 1000000 ) = a1 )
Assert( Rand( 1, 1000000 ) = a2 )
Assert( Rand( 1, 1000000 ) = a3 )
End Test
; Frozen literals captured from the Windows build. The integer LCG is
; bit-reproducible across platforms, so these also serve as a cross-platform
; contract: any algorithm/seed drift changes them.
Test testRandKnownSequence()
SeedRnd( 1234 )
Assert( Rand( 1, 1000000 ) = 911355 )
Assert( Rand( 1, 1000000 ) = 624215 )
Assert( Rand( 1, 1000000 ) = 759072 )
End Test
; SeedRnd masks to 0x7fffffff and maps seed 0 to state 1, so SeedRnd(0) and
; SeedRnd(1) produce the same stream.
Test testSeedRndZeroMapsToOne()
SeedRnd( 0 )
Local a = Rand( 1, 1000000 )
SeedRnd( 1 )
Assert( Rand( 1, 1000000 ) = a )
End Test
; Rand is inclusive on both ends and swaps reversed arguments.
Test testRandRangeAndSwap()
Assert( Rand( 5, 5 ) = 5 )
SeedRnd( 42 )
Local i, ok = True
For i = 1 To 500
Local r = Rand( 6, 1 ) ; reversed args -> normalized to [1,6]
If r < 1 Or r > 6 Then ok = False
Next
Assert( ok )
End Test
; Rnd returns a float strictly within its range; Rnd(0,1) in (0,1).
Test testRndRange()
SeedRnd( 99 )
Local i, ok = True
For i = 1 To 500
Local r# = Rnd( 0.0, 1.0 )
If r# <= 0.0 Or r# >= 1.0 Then ok = False
Next
Assert( ok )
End Test
; Pin Rnd's float path determinism directly (not just transitively via Rand):
; the same seed must reproduce the same float draws. Exact float equality is
; valid here because it's bit-identical operations from an identical state.
Test testRndReproducible()
SeedRnd( 314 )
Local b1# = Rnd( 0.0, 1.0 )
Local b2# = Rnd( -5.0, 5.0 )
SeedRnd( 314 )
Assert( Rnd( 0.0, 1.0 ) = b1# )
Assert( Rnd( -5.0, 5.0 ) = b2# )
End Test
; RndSeed reports the current generator state; after the same seed + draws it is
; reproducible.
Test testRndSeedState()
SeedRnd( 7777 )
Rand( 1, 100 ) : Rand( 1, 100 )
Local s1 = RndSeed()
SeedRnd( 7777 )
Rand( 1, 100 ) : Rand( 1, 100 )
Assert( RndSeed() = s1 )
End Test
; --- Scientific-notation (exponent) float literals ---
; The lexer must recognize [eE][+-]?<digit> as a float exponent. Pin the canonical
; forms AND the conservative guard: a bare 'e' with no valid exponent digit must
; NOT be swallowed into the literal. Value conversion is via atof(), so a literal
; that spans the exponent is already evaluated correctly.
Test testSciNotationBasic()
Assert( FloatClose( 1.5e3, 1500.0 ) )
Assert( FloatClose( 2.0e-3, 0.002 ) )
Assert( FloatClose( 1.0e+2, 100.0 ) )
End Test
; The riskiest paths: no decimal point ("no-dot" promotion to float) and leading
; dot. 1e6 must be a FLOAT (1000000.0), not an int.
Test testSciNotationNoDotAndLeadingDot()
Assert( FloatClose( 1e6, 1000000.0 ) )
Assert( FloatClose( .5e2, 50.0 ) )
Local v# = 1e6
Assert( FloatClose( v, 1000000.0 ) )
End Test
; Exponent literals must compose in arithmetic expressions, not just standalone.
Test testSciNotationArithmetic()
Assert( FloatClose( 2.0e-3 * 1000.0, 2.0 ) )
Assert( FloatClose( 1.5e3 + 2.5e3, 4000.0 ) )
Assert( FloatClose( 1e2 / 4.0, 25.0 ) )
End Test
; A very large exponent must compile and yield a huge positive float. FloatClose's
; 0.0001 absolute tolerance is meaningless at 1e30 (float granularity there is
; ~1e23), so assert by magnitude/relationship instead of epsilon-equality.
Test testSciNotationLargeMagnitude()
Local big# = 1.0e30
Assert( big > 1.0e29 )
Assert( big > 999999.0 )
Assert( FloatClose( big / 1.0e30, 1.0 ) )
End Test
; CONSERVATIVE GUARD: 'e' not followed by [+-]?<digit> must tokenize as the float
; followed by a separate identifier. e() and identExp() return 0.0, so the sums
; must equal 1.0; if the lexer greedily ate a bad 'e' the program would fail to
; compile instead.
Test testSciNotationConservativeGuard()
Assert( FloatClose( 1.0 + e(), 1.0 ) )
Assert( FloatClose( 1.0 + identExp(), 1.0 ) )
Assert( FloatClose( 1.0e1, 10.0 ) )
End Test