@@ -9,9 +9,9 @@ use statrs::function::gamma::{gamma, ln_gamma};
9
9
use num_bigint:: BigInt ;
10
10
use num_traits:: { One , Zero } ;
11
11
12
- use crate :: function:: OptionalArg ;
12
+ use crate :: function:: { OptionalArg , PyFuncArgs } ;
13
13
use crate :: obj:: objfloat:: { self , IntoPyFloat , PyFloatRef } ;
14
- use crate :: obj:: objint:: { self , PyIntRef } ;
14
+ use crate :: obj:: objint:: { self , PyInt , PyIntRef } ;
15
15
use crate :: obj:: objtype;
16
16
use crate :: pyobject:: { Either , PyObjectRef , PyResult , TypeProtocol } ;
17
17
use crate :: vm:: VirtualMachine ;
@@ -272,9 +272,55 @@ fn math_ldexp(
272
272
Ok ( value * ( 2_f64 ) . powf ( objint:: try_float ( i. as_bigint ( ) , vm) ?) )
273
273
}
274
274
275
- fn math_gcd ( a : PyIntRef , b : PyIntRef ) -> BigInt {
275
+ fn math_perf_arb_len_int_op < F > (
276
+ args : PyFuncArgs ,
277
+ vm : & VirtualMachine ,
278
+ op : F ,
279
+ default : BigInt ,
280
+ ) -> PyResult < BigInt >
281
+ where
282
+ F : Fn ( & BigInt , & PyInt ) -> BigInt ,
283
+ {
284
+ if !args. kwargs . is_empty ( ) {
285
+ Err ( vm. new_type_error ( "Takes no keyword arguments" . to_owned ( ) ) )
286
+ } else if args. args . is_empty ( ) {
287
+ Ok ( default)
288
+ } else if args. args . len ( ) == 1 {
289
+ let a: PyObjectRef = args. args [ 0 ] . clone ( ) ;
290
+ if let Some ( aa) = a. payload_if_subclass :: < PyInt > ( vm) {
291
+ let res = op ( aa. as_bigint ( ) , aa) ;
292
+ Ok ( res)
293
+ } else {
294
+ Err ( vm. new_type_error ( "Only integer arguments are supported" . to_owned ( ) ) )
295
+ }
296
+ } else {
297
+ let a = args. args [ 0 ] . clone ( ) ;
298
+ if let Some ( aa) = a. payload_if_subclass :: < PyInt > ( vm) {
299
+ let mut res = aa. as_bigint ( ) . clone ( ) ;
300
+ for b in args. args [ 1 ..] . iter ( ) {
301
+ if let Some ( bb) = b. payload_if_subclass :: < PyInt > ( vm) {
302
+ res = op ( & res, bb) ;
303
+ } else {
304
+ return Err (
305
+ vm. new_type_error ( "Only integer arguments are supported" . to_owned ( ) )
306
+ ) ;
307
+ }
308
+ }
309
+ Ok ( res)
310
+ } else {
311
+ Err ( vm. new_type_error ( "Only integer arguments are supported" . to_owned ( ) ) )
312
+ }
313
+ }
314
+ }
315
+
316
+ fn math_gcd ( args : PyFuncArgs , vm : & VirtualMachine ) -> PyResult < BigInt > {
317
+ use num_integer:: Integer ;
318
+ math_perf_arb_len_int_op ( args, vm, |x, y| x. gcd ( y. as_bigint ( ) ) , BigInt :: zero ( ) )
319
+ }
320
+
321
+ fn math_lcm ( args : PyFuncArgs , vm : & VirtualMachine ) -> PyResult < BigInt > {
276
322
use num_integer:: Integer ;
277
- a . as_bigint ( ) . gcd ( b . as_bigint ( ) )
323
+ math_perf_arb_len_int_op ( args , vm , |x , y| x . lcm ( y . as_bigint ( ) ) , BigInt :: one ( ) )
278
324
}
279
325
280
326
fn math_factorial ( value : PyIntRef , vm : & VirtualMachine ) -> PyResult < BigInt > {
@@ -436,6 +482,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
436
482
437
483
// Gcd function
438
484
"gcd" => ctx. new_function( math_gcd) ,
485
+ "lcm" => ctx. new_function( math_lcm) ,
439
486
440
487
// Factorial function
441
488
"factorial" => ctx. new_function( math_factorial) ,
0 commit comments