@@ -9,9 +9,9 @@ use statrs::function::gamma::{gamma, ln_gamma};
99use num_bigint:: BigInt ;
1010use num_traits:: { One , Zero } ;
1111
12- use crate :: function:: OptionalArg ;
12+ use crate :: function:: { OptionalArg , PyFuncArgs } ;
1313use crate :: obj:: objfloat:: { self , IntoPyFloat , PyFloatRef } ;
14- use crate :: obj:: objint:: { self , PyIntRef } ;
14+ use crate :: obj:: objint:: { self , PyInt , PyIntRef } ;
1515use crate :: obj:: objtype;
1616use crate :: pyobject:: { Either , PyObjectRef , PyResult , TypeProtocol } ;
1717use crate :: vm:: VirtualMachine ;
@@ -272,9 +272,55 @@ fn math_ldexp(
272272 Ok ( value * ( 2_f64 ) . powf ( objint:: try_float ( i. as_bigint ( ) , vm) ?) )
273273}
274274
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 > {
276322 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 ( ) )
278324}
279325
280326fn math_factorial ( value : PyIntRef , vm : & VirtualMachine ) -> PyResult < BigInt > {
@@ -436,6 +482,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
436482
437483 // Gcd function
438484 "gcd" => ctx. new_function( math_gcd) ,
485+ "lcm" => ctx. new_function( math_lcm) ,
439486
440487 // Factorial function
441488 "factorial" => ctx. new_function( math_factorial) ,
0 commit comments