| 813 | |
| 814 | #[pyfunction] |
| 815 | fn perm( |
| 816 | n: ArgIndex, |
| 817 | k: OptionalArg<Option<ArgIndex>>, |
| 818 | vm: &VirtualMachine, |
| 819 | ) -> PyResult<BigInt> { |
| 820 | let n_int = n.into_int_ref(); |
| 821 | let n_big = n_int.as_bigint(); |
| 822 | |
| 823 | if n_big.is_negative() { |
| 824 | return Err(vm.new_value_error("n must be a non-negative integer")); |
| 825 | } |
| 826 | |
| 827 | // k = None means k = n (factorial) |
| 828 | let k_int = k.flatten().map(|k| k.into_int_ref()); |
| 829 | let k_big: Option<&BigInt> = k_int.as_ref().map(|k| k.as_bigint()); |
| 830 | |
| 831 | if let Some(k_val) = k_big { |
| 832 | if k_val.is_negative() { |
| 833 | return Err(vm.new_value_error("k must be a non-negative integer")); |
| 834 | } |
| 835 | if k_val > n_big { |
| 836 | return Ok(BigInt::from(0u8)); |
| 837 | } |
| 838 | } |
| 839 | |
| 840 | // Convert k to u64 (required by pymath) |
| 841 | let ki: u64 = match k_big { |
| 842 | None => match n_big.to_u64() { |
| 843 | Some(n) => n, |
| 844 | None => { |
| 845 | return Err(vm.new_overflow_error(format!("n must not exceed {}", u64::MAX))); |
| 846 | } |
| 847 | }, |
| 848 | Some(k_val) => match k_val.to_u64() { |
| 849 | Some(k) => k, |
| 850 | None => { |
| 851 | return Err(vm.new_overflow_error(format!("k must not exceed {}", u64::MAX))); |
| 852 | } |
| 853 | }, |
| 854 | }; |
| 855 | |
| 856 | // Fast path: n fits in i64 |
| 857 | if let Some(ni) = n_big.to_i64() |
| 858 | && ni >= 0 |
| 859 | && ki > 1 |
| 860 | { |
| 861 | let result = pymath::math::integer::perm(ni, Some(ki as i64)) |
| 862 | .map_err(|_| vm.new_value_error("perm() error"))?; |
| 863 | return Ok(result.into()); |
| 864 | } |
| 865 | |
| 866 | // BigInt path: use perm_bigint |
| 867 | let result = pymath::math::perm_bigint(n_big, ki); |
| 868 | Ok(result.into()) |
| 869 | } |
| 870 | |
| 871 | #[pyfunction] |
| 872 | fn comb(n: ArgIndex, k: ArgIndex, vm: &VirtualMachine) -> PyResult<BigInt> { |