(&self, other: PyObjectRef, modulus: PyObjectRef, vm: &VirtualMachine)
| 395 | } |
| 396 | |
| 397 | fn modpow(&self, other: PyObjectRef, modulus: PyObjectRef, vm: &VirtualMachine) -> PyResult { |
| 398 | let modulus = match modulus.downcast_ref::<Self>() { |
| 399 | Some(val) => val.as_bigint(), |
| 400 | None => return Ok(vm.ctx.not_implemented()), |
| 401 | }; |
| 402 | if modulus.is_zero() { |
| 403 | return Err(vm.new_value_error("pow() 3rd argument cannot be 0")); |
| 404 | } |
| 405 | |
| 406 | self.general_op( |
| 407 | other, |
| 408 | |a, b| { |
| 409 | let i = if b.is_negative() { |
| 410 | // modular multiplicative inverse |
| 411 | // based on rust-num/num-integer#10, should hopefully be published soon |
| 412 | fn normalize(a: BigInt, n: &BigInt) -> BigInt { |
| 413 | let a = a % n; |
| 414 | if a.is_negative() { a + n } else { a } |
| 415 | } |
| 416 | fn inverse(a: BigInt, n: &BigInt) -> Option<BigInt> { |
| 417 | let ExtendedGcd { gcd, x: c, .. } = a.extended_gcd(n); |
| 418 | if gcd.is_one() { |
| 419 | Some(normalize(c, n)) |
| 420 | } else { |
| 421 | None |
| 422 | } |
| 423 | } |
| 424 | let a = inverse(a % modulus, modulus).ok_or_else(|| { |
| 425 | vm.new_value_error("base is not invertible for the given modulus") |
| 426 | })?; |
| 427 | let b = -b; |
| 428 | a.modpow(&b, modulus) |
| 429 | } else { |
| 430 | a.modpow(b, modulus) |
| 431 | }; |
| 432 | Ok(vm.ctx.new_int(i).into()) |
| 433 | }, |
| 434 | vm, |
| 435 | ) |
| 436 | } |
| 437 | |
| 438 | #[pymethod] |
| 439 | fn __round__( |
no test coverage detected