1
1
use crate :: Error ;
2
2
// use std::f64::consts::PI;
3
3
4
-
5
4
// Import C library functions properly
6
5
unsafe extern "C" {
7
6
fn exp ( x : f64 ) -> f64 ;
@@ -197,7 +196,7 @@ pub fn tgamma(x: f64) -> Result<f64, Error> {
197
196
let lanczos = lanczos_sum ( absx) ;
198
197
let mut r = term3 / lanczos;
199
198
r -= z * r;
200
-
199
+
201
200
if absx < 140.0 {
202
201
unsafe { r / pow ( y, absx - 0.5 ) }
203
202
} else {
@@ -211,7 +210,7 @@ pub fn tgamma(x: f64) -> Result<f64, Error> {
211
210
let exp_y = unsafe { exp ( y) } ;
212
211
let mut r = lanczos / exp_y;
213
212
r += z * r;
214
-
213
+
215
214
if absx < 140.0 {
216
215
unsafe { r * pow ( y, absx - 0.5 ) }
217
216
} else {
@@ -261,19 +260,19 @@ pub fn lgamma(x: f64) -> Result<f64, Error> {
261
260
// Using C's math functions through libc to match CPython
262
261
let lanczos_sum_val = lanczos_sum ( absx) ;
263
262
let log_lanczos = unsafe { log ( lanczos_sum_val) } ;
264
-
263
+
265
264
// Subtract lanczos_g as a separate step
266
265
let mut r = log_lanczos - LANCZOS_G ;
267
-
266
+
268
267
// Calculate (absx - 0.5) term
269
268
let factor = absx - 0.5 ;
270
-
269
+
271
270
// Calculate log term
272
271
let log_term = unsafe { log ( absx + LANCZOS_G - 0.5 ) } ;
273
-
272
+
274
273
// Calculate the multiplication and subtraction
275
274
let step2 = factor * ( log_term - 1.0 ) ;
276
-
275
+
277
276
// Combine the results
278
277
r += step2;
279
278
@@ -283,11 +282,11 @@ pub fn lgamma(x: f64) -> Result<f64, Error> {
283
282
let abs_sinpi = unsafe { fabs ( sinpi_val) } ;
284
283
let log_abs_sinpi = unsafe { log ( abs_sinpi) } ;
285
284
let log_absx = unsafe { log ( absx) } ;
286
-
285
+
287
286
// Combine in exactly the same order as CPython
288
287
r = LOG_PI - log_abs_sinpi - log_absx - r;
289
288
}
290
-
289
+
291
290
if r. is_infinite ( ) {
292
291
return Err ( Error :: ERANGE ) ;
293
292
}
@@ -328,9 +327,73 @@ mod tests {
328
327
}
329
328
}
330
329
330
+ #[ test]
331
+ fn test_literal ( ) {
332
+ // Verify single constants
333
+ assert_eq ! ( PI , 3.141592653589793238462643383279502884197 ) ;
334
+ assert_eq ! ( LOG_PI , 1.144729885849400174143427351353058711647 ) ;
335
+ assert_eq ! ( LANCZOS_G , 6.024680040776729583740234375 ) ;
336
+ assert_eq ! ( LANCZOS_G_MINUS_HALF , 5.524680040776729583740234375 ) ;
337
+
338
+ // Verify LANCZOS_NUM_COEFFS
339
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 0 ] , 23531376880.410759 ) ;
340
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 1 ] , 42919803642.649101 ) ;
341
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 2 ] , 35711959237.355667 ) ;
342
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 3 ] , 17921034426.037209 ) ;
343
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 4 ] , 6039542586.3520279 ) ;
344
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 5 ] , 1439720407.3117216 ) ;
345
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 6 ] , 248874557.86205417 ) ;
346
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 7 ] , 31426415.585400194 ) ;
347
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 8 ] , 2876370.6289353725 ) ;
348
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 9 ] , 186056.26539522348 ) ;
349
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 10 ] , 8071.6720023658163 ) ;
350
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 11 ] , 210.82427775157936 ) ;
351
+ assert_eq ! ( LANCZOS_NUM_COEFFS [ 12 ] , 2.5066282746310002 ) ;
352
+
353
+ // Verify LANCZOS_DEN_COEFFS
354
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 0 ] , 0.0 ) ;
355
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 1 ] , 39916800.0 ) ;
356
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 2 ] , 120543840.0 ) ;
357
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 3 ] , 150917976.0 ) ;
358
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 4 ] , 105258076.0 ) ;
359
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 5 ] , 45995730.0 ) ;
360
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 6 ] , 13339535.0 ) ;
361
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 7 ] , 2637558.0 ) ;
362
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 8 ] , 357423.0 ) ;
363
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 9 ] , 32670.0 ) ;
364
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 10 ] , 1925.0 ) ;
365
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 11 ] , 66.0 ) ;
366
+ assert_eq ! ( LANCZOS_DEN_COEFFS [ 12 ] , 1.0 ) ;
367
+
368
+ // Verify GAMMA_INTEGRAL
369
+ assert_eq ! ( GAMMA_INTEGRAL [ 0 ] , 1.0 ) ;
370
+ assert_eq ! ( GAMMA_INTEGRAL [ 1 ] , 1.0 ) ;
371
+ assert_eq ! ( GAMMA_INTEGRAL [ 2 ] , 2.0 ) ;
372
+ assert_eq ! ( GAMMA_INTEGRAL [ 3 ] , 6.0 ) ;
373
+ assert_eq ! ( GAMMA_INTEGRAL [ 4 ] , 24.0 ) ;
374
+ assert_eq ! ( GAMMA_INTEGRAL [ 5 ] , 120.0 ) ;
375
+ assert_eq ! ( GAMMA_INTEGRAL [ 6 ] , 720.0 ) ;
376
+ assert_eq ! ( GAMMA_INTEGRAL [ 7 ] , 5040.0 ) ;
377
+ assert_eq ! ( GAMMA_INTEGRAL [ 8 ] , 40320.0 ) ;
378
+ assert_eq ! ( GAMMA_INTEGRAL [ 9 ] , 362880.0 ) ;
379
+ assert_eq ! ( GAMMA_INTEGRAL [ 10 ] , 3628800.0 ) ;
380
+ assert_eq ! ( GAMMA_INTEGRAL [ 11 ] , 39916800.0 ) ;
381
+ assert_eq ! ( GAMMA_INTEGRAL [ 12 ] , 479001600.0 ) ;
382
+ assert_eq ! ( GAMMA_INTEGRAL [ 13 ] , 6227020800.0 ) ;
383
+ assert_eq ! ( GAMMA_INTEGRAL [ 14 ] , 87178291200.0 ) ;
384
+ assert_eq ! ( GAMMA_INTEGRAL [ 15 ] , 1307674368000.0 ) ;
385
+ assert_eq ! ( GAMMA_INTEGRAL [ 16 ] , 20922789888000.0 ) ;
386
+ assert_eq ! ( GAMMA_INTEGRAL [ 17 ] , 355687428096000.0 ) ;
387
+ assert_eq ! ( GAMMA_INTEGRAL [ 18 ] , 6402373705728000.0 ) ;
388
+ assert_eq ! ( GAMMA_INTEGRAL [ 19 ] , 1.21645100408832e+17 ) ;
389
+ assert_eq ! ( GAMMA_INTEGRAL [ 20 ] , 2.43290200817664e+18 ) ;
390
+ assert_eq ! ( GAMMA_INTEGRAL [ 21 ] , 5.109094217170944e+19 ) ;
391
+ assert_eq ! ( GAMMA_INTEGRAL [ 22 ] , 1.1240007277776077e+21 ) ;
392
+ }
393
+
331
394
#[ test]
332
395
fn test_specific_lgamma_value ( ) {
333
- let x = - 3.8510064710745118 ;
396
+ let x = 0.003585187864492183 ;
334
397
let rs_lgamma = lgamma ( x) . unwrap ( ) ;
335
398
336
399
pyo3:: prepare_freethreaded_python ( ) ;
@@ -385,6 +448,42 @@ mod tests {
385
448
}
386
449
387
450
proptest ! {
451
+ #[ test]
452
+ fn test_sinpi( x: f64 ) {
453
+ if !x. is_finite( ) {
454
+ return Ok ( ( ) ) ;
455
+ }
456
+ eprintln!( "x = {x}" ) ;
457
+
458
+ pyo3:: prepare_freethreaded_python( ) ;
459
+ Python :: with_gil( |py| {
460
+ // Create Python function for comparing sinpi
461
+ let py_code = PyModule :: from_code(
462
+ py,
463
+ c"import math\n def sinpi(x): return math.sin(math.pi * x)" ,
464
+ c"" ,
465
+ c"" ,
466
+ )
467
+ . unwrap( ) ;
468
+
469
+ // Get results from both implementations
470
+ let rs_sinpi = m_sinpi( x) ;
471
+ let py_sinpi = py_code
472
+ . getattr( "sinpi" )
473
+ . unwrap( )
474
+ . call1( ( x, ) )
475
+ . unwrap( )
476
+ . extract:: <f64 >( )
477
+ . unwrap( ) ;
478
+
479
+ // Check if they're close enough
480
+ // Get bit representation for detailed comparison
481
+ let rs_bits = unsafe { std:: mem:: transmute:: <f64 , i64 >( rs_sinpi) } ;
482
+ let py_bits = unsafe { std:: mem:: transmute:: <f64 , i64 >( py_sinpi) } ;
483
+ assert_eq!( rs_bits, py_bits) ;
484
+ } ) ;
485
+ }
486
+
388
487
#[ test]
389
488
fn test_tgamma( x: f64 ) {
390
489
let rs_gamma = tgamma( x) ;
0 commit comments