use num_bigint::BigInt;
use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
pub(crate) fn big_sign(b: &BigInt) -> Ordering {
match b.sign() {
num_bigint::Sign::Minus => Ordering::Less,
num_bigint::Sign::NoSign => Ordering::Equal,
num_bigint::Sign::Plus => Ordering::Greater,
}
}
pub(crate) fn big_gcd(a: &BigInt, b: &BigInt) -> BigInt {
use num_integer::Integer as _;
a.gcd(b)
}
#[derive(Clone, Debug, PartialEq, Eq)]
enum Repr {
Small(i64),
Big(Box<BigInt>),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Integer(Repr);
impl Integer {
pub const fn zero() -> Self {
Integer(Repr::Small(0))
}
pub const fn one() -> Self {
Integer(Repr::Small(1))
}
pub const fn from_i64(v: i64) -> Self {
Integer(Repr::Small(v))
}
pub fn parse(s: &str) -> Option<Self> {
if let Ok(v) = s.parse::<i64>() {
return Some(Integer(Repr::Small(v)));
}
BigInt::parse_bytes(s.as_bytes(), 10).map(Self::from_big)
}
pub fn is_zero(&self) -> bool {
matches!(self.0, Repr::Small(0))
}
pub fn is_one(&self) -> bool {
matches!(self.0, Repr::Small(1))
}
pub fn is_negative(&self) -> bool {
self.sign() < 0
}
pub fn sign(&self) -> i32 {
match &self.0 {
Repr::Small(v) => v.signum() as i32,
Repr::Big(b) => match big_sign(b) {
Ordering::Less => -1,
Ordering::Equal => 0,
Ordering::Greater => 1,
},
}
}
pub fn to_i64(&self) -> Option<i64> {
match &self.0 {
Repr::Small(v) => Some(*v),
Repr::Big(_) => None,
}
}
pub fn to_u64(&self) -> Option<u64> {
match &self.0 {
Repr::Small(v) if *v >= 0 => Some(*v as u64),
Repr::Small(_) => None,
Repr::Big(b) => u64::try_from(b.as_ref()).ok(),
}
}
pub fn from_u64(v: u64) -> Self {
match i64::try_from(v) {
Ok(s) => Integer(Repr::Small(s)),
Err(_) => Integer(Repr::Big(Box::new(BigInt::from(v)))),
}
}
pub fn bit_len(&self) -> u64 {
match &self.0 {
Repr::Small(v) => {
let m = v.unsigned_abs();
(u64::BITS - m.leading_zeros()) as u64
}
Repr::Big(b) => b.bits(),
}
}
pub fn abs(&self) -> Self {
match &self.0 {
Repr::Small(v) => match v.checked_abs() {
Some(a) => Integer(Repr::Small(a)),
None => Self::from_big(-self.as_big()),
},
Repr::Big(b) => match big_sign(b) {
Ordering::Less => Self::from_big(-(b.as_ref().clone())),
_ => self.clone(),
},
}
}
pub fn neg(&self) -> Self {
match &self.0 {
Repr::Small(v) => match v.checked_neg() {
Some(n) => Integer(Repr::Small(n)),
None => Self::from_big(-self.as_big()),
},
Repr::Big(b) => Self::from_big(-(**b).clone()),
}
}
pub fn add(&self, other: &Self) -> Self {
if let (Repr::Small(a), Repr::Small(b)) = (&self.0, &other.0) {
if let Some(s) = a.checked_add(*b) {
return Integer(Repr::Small(s));
}
}
Self::from_big(self.as_big() + other.as_big())
}
pub fn sub(&self, other: &Self) -> Self {
if let (Repr::Small(a), Repr::Small(b)) = (&self.0, &other.0) {
if let Some(s) = a.checked_sub(*b) {
return Integer(Repr::Small(s));
}
}
Self::from_big(self.as_big() - other.as_big())
}
pub fn mul(&self, other: &Self) -> Self {
if let (Repr::Small(a), Repr::Small(b)) = (&self.0, &other.0) {
if let Some(p) = a.checked_mul(*b) {
return Integer(Repr::Small(p));
}
}
Self::from_big(self.as_big() * other.as_big())
}
pub fn pow(&self, exp: u32) -> Self {
if let Repr::Small(v) = &self.0 {
if let Some(p) = v.checked_pow(exp) {
return Integer(Repr::Small(p));
}
}
Self::from_big(self.as_big().pow(exp))
}
pub fn gcd(&self, other: &Self) -> Self {
if let (Repr::Small(a), Repr::Small(b)) = (&self.0, &other.0) {
Integer(Repr::Small(
gcd_u64(a.unsigned_abs(), b.unsigned_abs()) as i64
))
} else {
Self::from_big(big_gcd(&self.as_big(), &other.as_big()))
}
}
pub fn div_exact(&self, divisor: &Self) -> Self {
Self::from_big(self.as_big() / divisor.as_big())
}
fn from_big(b: BigInt) -> Self {
match i64::try_from(&b) {
Ok(v) => Integer(Repr::Small(v)),
Err(_) => Integer(Repr::Big(Box::new(b))),
}
}
pub fn from_bigint(b: BigInt) -> Self {
Self::from_big(b)
}
fn as_big(&self) -> BigInt {
match &self.0 {
Repr::Small(v) => BigInt::from(*v),
Repr::Big(b) => (**b).clone(),
}
}
pub fn to_bigint(&self) -> BigInt {
self.as_big()
}
}
pub(crate) fn gcd_u64(mut a: u64, mut b: u64) -> u64 {
while b != 0 {
let r = a % b;
a = b;
b = r;
}
a
}
impl Ord for Integer {
fn cmp(&self, other: &Self) -> Ordering {
match (&self.0, &other.0) {
(Repr::Small(a), Repr::Small(b)) => a.cmp(b),
(Repr::Big(a), Repr::Big(b)) => a.cmp(b),
(_, Repr::Big(b)) => big_sign(b).reverse(),
(Repr::Big(a), Repr::Small(_)) => big_sign(a),
}
}
}
impl PartialOrd for Integer {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Hash for Integer {
fn hash<H: Hasher>(&self, state: &mut H) {
match &self.0 {
Repr::Small(v) => state.write_i64(*v),
Repr::Big(b) => b.hash(state),
}
}
}
impl fmt::Display for Integer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match &self.0 {
Repr::Small(v) => write!(f, "{v}"),
Repr::Big(b) => write!(f, "{b}"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn 小数路径与规范形() {
assert_eq!(
Integer::from_i64(2).add(&Integer::from_i64(3)),
Integer::from_i64(5)
);
assert!(!Integer::from_i64(5).is_one());
let big = Integer::from_i64(i64::MAX).add(&Integer::one());
assert_eq!(big.to_string(), "9223372036854775808");
assert_eq!(big.sub(&Integer::one()), Integer::from_i64(i64::MAX));
}
#[test]
fn i64_min_边界() {
let m = Integer::from_i64(i64::MIN);
assert_eq!(m.abs().to_string(), "9223372036854775808");
assert_eq!(m.neg().to_string(), "9223372036854775808");
assert_eq!(m.mul(&Integer::from_i64(1)), m);
assert!(m.is_negative());
assert!(m.cmp(&Integer::from_i64(i64::MAX)) == Ordering::Less);
}
#[test]
fn 跨表示序与相等() {
let big = Integer::parse("9223372036854775808").unwrap();
assert_eq!(big, Integer::parse("9223372036854775808").unwrap());
assert!(Integer::from_i64(-1).cmp(&big) == Ordering::Less);
assert!(big.cmp(&Integer::from_i64(i64::MAX)) == Ordering::Greater);
let neg_big = big.neg();
assert_eq!(neg_big.cmp(&Integer::from_i64(i64::MIN)), Ordering::Equal);
let below_min = Integer::parse("-9223372036854775809").unwrap();
assert_eq!(below_min.cmp(&Integer::from_i64(i64::MIN)), Ordering::Less);
}
#[test]
fn 幂与位数() {
assert_eq!(Integer::from_i64(2).pow(10).to_string(), "1024");
assert_eq!(
Integer::from_i64(2).pow(100).to_string(),
"1267650600228229401496703205376"
);
assert_eq!(Integer::from_i64(0).bit_len(), 0);
assert_eq!(Integer::from_i64(255).bit_len(), 8);
assert_eq!(
Integer::parse("1267650600228229401496703205376")
.unwrap()
.bit_len(),
101
);
}
#[test]
fn 最大公约数() {
assert_eq!(
Integer::from_i64(12).gcd(&Integer::from_i64(18)),
Integer::from_i64(6)
);
assert_eq!(
Integer::from_i64(0).gcd(&Integer::from_i64(5)),
Integer::from_i64(5)
);
let big = Integer::parse("1000000007").unwrap();
assert_eq!(big.gcd(&Integer::from_i64(3)), Integer::one());
}
}