@@ -502,19 +502,40 @@ impl PyInt {
502502 #[ pymethod( magic) ]
503503 fn round (
504504 zelf : PyRef < Self > ,
505- precision : OptionalArg < PyObjectRef > ,
505+ ndigits : OptionalArg < PyIntRef > ,
506506 vm : & VirtualMachine ,
507507 ) -> PyResult < PyRef < Self > > {
508- match precision {
509- OptionalArg :: Missing => ( ) ,
510- OptionalArg :: Present ( ref value) => {
511- // Only accept int type ndigits
512- let _ndigits = value. payload_if_subclass :: < PyInt > ( vm) . ok_or_else ( || {
513- vm. new_type_error ( format ! (
514- "'{}' object cannot be interpreted as an integer" ,
515- value. class( ) . name( )
516- ) )
517- } ) ?;
508+ if let OptionalArg :: Present ( ndigits) = ndigits {
509+ let ndigits = ndigits. as_bigint ( ) ;
510+ // round(12345, -2) == 12300
511+ // If precision >= 0, then any integer is already rounded correctly
512+ if let Some ( ndigits) = ndigits. neg ( ) . to_u32 ( ) {
513+ if ndigits > 0 {
514+ // Work with positive integers and negate at the end if necessary
515+ let sign = if zelf. value . is_negative ( ) {
516+ BigInt :: from ( -1 )
517+ } else {
518+ BigInt :: from ( 1 )
519+ } ;
520+ let value = zelf. value . abs ( ) ;
521+
522+ // Divide and multiply by the power of 10 to get the approximate answer
523+ let pow10 = BigInt :: from ( 10 ) . pow ( ndigits) ;
524+ let quotient = & value / & pow10;
525+ let rounded = & quotient * & pow10;
526+
527+ // Malachite division uses floor rounding, Python uses half-even
528+ let remainder = & value - & rounded;
529+ let halfpow10 = & pow10 / BigInt :: from ( 2 ) ;
530+ let correction =
531+ if remainder > halfpow10 || ( remainder == halfpow10 && quotient. is_odd ( ) ) {
532+ pow10
533+ } else {
534+ BigInt :: from ( 0 )
535+ } ;
536+ let rounded = ( rounded + correction) * sign;
537+ return Ok ( vm. ctx . new_int ( rounded) ) ;
538+ }
518539 }
519540 }
520541 Ok ( zelf)
0 commit comments