@@ -502,19 +502,40 @@ impl PyInt {
502
502
#[ pymethod( magic) ]
503
503
fn round (
504
504
zelf : PyRef < Self > ,
505
- precision : OptionalArg < PyObjectRef > ,
505
+ ndigits : OptionalArg < PyIntRef > ,
506
506
vm : & VirtualMachine ,
507
507
) -> 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
+ }
518
539
}
519
540
}
520
541
Ok ( zelf)
0 commit comments