11using System ;
2+ using System . Diagnostics ;
3+ using System . Numerics ;
24using Xunit ;
35
46namespace Platform . Numbers . Tests
57{
68 public static class MathTests
79 {
10+ private static readonly TimeSpan ComputationTimeLimit = TimeSpan . FromSeconds ( 10 ) ;
11+
12+ /// <summary>
13+ /// Computes factorial of n using BigInteger so it never overflows.
14+ /// Returns null if computation exceeds the time limit.
15+ /// </summary>
16+ private static BigInteger ? ComputeFactorialWithTimeLimit ( ulong n )
17+ {
18+ var stopwatch = Stopwatch . StartNew ( ) ;
19+ BigInteger result = BigInteger . One ;
20+ for ( ulong i = 2 ; i <= n ; i ++ )
21+ {
22+ result *= i ;
23+ if ( stopwatch . Elapsed > ComputationTimeLimit )
24+ {
25+ return null ;
26+ }
27+ }
28+ return result ;
29+ }
30+
31+ /// <summary>
32+ /// Computes the nth Catalan number from scratch using the formula:
33+ /// C(n) = (2n)! / ((n+1)! * n!)
34+ /// Returns null if computation exceeds the time limit.
35+ /// </summary>
36+ private static BigInteger ? ComputeCatalanWithTimeLimit ( ulong n )
37+ {
38+ var twoNFact = ComputeFactorialWithTimeLimit ( 2 * n ) ;
39+ if ( twoNFact is null ) return null ;
40+
41+ var nPlusOneFact = ComputeFactorialWithTimeLimit ( n + 1 ) ;
42+ if ( nPlusOneFact is null ) return null ;
43+
44+ var nFact = ComputeFactorialWithTimeLimit ( n ) ;
45+ if ( nFact is null ) return null ;
46+
47+ return twoNFact / ( nPlusOneFact * nFact ) ;
48+ }
49+
850 [ Theory ]
951 [ InlineData ( 0ul , 1ul ) ]
1052 [ InlineData ( 1ul , 1ul ) ]
@@ -107,5 +149,46 @@ public static void MaximumConstantsTest()
107149 Assert . Equal ( 20ul , Math . MaximumFactorialNumber ) ;
108150 Assert . Equal ( 36ul , Math . MaximumCatalanIndex ) ;
109151 }
152+
153+ [ Fact ]
154+ public static void PrecalculatedFactorialsMatchComputedValues ( )
155+ {
156+ // Verify that every precalculated factorial constant in Math._factorials is actually
157+ // a correct factorial value, computed independently using BigInteger arithmetic.
158+ // Only computes values that finish within 10 seconds; larger values would need
159+ // verification via an external trusted resource (e.g. OEIS A000142: https://oeis.org/A000142).
160+ for ( ulong n = 0 ; n <= Math . MaximumFactorialNumber ; n ++ )
161+ {
162+ var computed = ComputeFactorialWithTimeLimit ( n ) ;
163+ if ( computed is null )
164+ {
165+ // Computation exceeded 10 seconds — skip and rely on external verification.
166+ continue ;
167+ }
168+ var precalculated = Math . Factorial < ulong > ( n ) ;
169+ Assert . Equal ( ( ulong ) computed , precalculated ) ;
170+ }
171+ }
172+
173+ [ Fact ]
174+ public static void PrecalculatedCatalansMatchComputedFactorials ( )
175+ {
176+ // Verify that every precalculated Catalan constant in Math._catalans is actually
177+ // a correct Catalan number, computed from scratch using the formula:
178+ // C(n) = (2n)! / ((n+1)! * n!)
179+ // Only computes values that finish within 10 seconds; larger values would need
180+ // verification via an external trusted resource (e.g. OEIS A000108: https://oeis.org/A000108).
181+ for ( ulong n = 0 ; n <= Math . MaximumCatalanIndex ; n ++ )
182+ {
183+ var computed = ComputeCatalanWithTimeLimit ( n ) ;
184+ if ( computed is null )
185+ {
186+ // Computation exceeded 10 seconds — skip and rely on external verification.
187+ continue ;
188+ }
189+ var precalculated = Math . Catalan < ulong > ( n ) ;
190+ Assert . Equal ( ( ulong ) computed , precalculated ) ;
191+ }
192+ }
110193 }
111194}
0 commit comments