use std::cmp::Ordering;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::{Product, Sum};
use std::ops::*;
use std::str::FromStr;
use collate::Collate;
use get_size::GetSize;
use get_size_derive::*;
use num::traits::Pow;
use safecast::*;
use super::class::*;
use super::{Error, Number, _Complex};
const ERR_COMPLEX_POWER: &str = "complex exponent is not yet supported";
macro_rules! fmt_debug {
    ($t:ty) => {
        impl fmt::Debug for $t {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                write!(f, "{} ({})", self, self.class())
            }
        }
    };
}
#[derive(Clone, Copy, Hash, Ord, PartialEq, PartialOrd)]
pub struct Boolean(bool);
impl GetSize for Boolean {
    fn get_size(&self) -> usize {
        1
    }
}
impl Boolean {
    fn as_radians(self) -> f32 {
        if self.0 {
            2. * std::f32::consts::PI
        } else {
            0.
        }
    }
}
impl NumberInstance for Boolean {
    type Abs = Self;
    type Exp = Float;
    type Log = Float;
    type Round = Self;
    type Class = BooleanType;
    fn class(&self) -> BooleanType {
        BooleanType
    }
    fn into_type(self, _dtype: BooleanType) -> Boolean {
        self
    }
    fn abs(self) -> Self {
        self
    }
    fn exp(self) -> Self::Exp {
        Float::cast_from(self).exp()
    }
    fn ln(self) -> Self::Log {
        Float::cast_from(self).ln()
    }
    fn log<N: NumberInstance>(self, base: N) -> Self::Log
    where
        Float: From<N>,
    {
        Float::cast_from(self).log(base)
    }
    fn pow(self, exp: Number) -> Self {
        if exp.cast_into() {
            self
        } else {
            self.class().one()
        }
    }
    fn and(self, other: Self) -> Self {
        Self(self.0 && other.0)
    }
    fn not(self) -> Self {
        Self(!self.0)
    }
    fn or(self, other: Self) -> Self {
        Self(self.0 || other.0)
    }
    fn round(self) -> Self::Round {
        self
    }
    fn xor(self, other: Self) -> Self {
        Self(self.0 ^ other.0)
    }
}
impl RealInstance for Boolean {
    const ONE: Self = Boolean(true);
    const ZERO: Self = Boolean(false);
}
impl Default for Boolean {
    fn default() -> Boolean {
        Self(false)
    }
}
impl From<bool> for Boolean {
    fn from(b: bool) -> Boolean {
        Self(b)
    }
}
impl FromStr for Boolean {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        bool::from_str(s).map(Self::from).map_err(Error::new)
    }
}
impl From<Boolean> for bool {
    fn from(b: Boolean) -> bool {
        b.0
    }
}
impl From<&Boolean> for bool {
    fn from(b: &Boolean) -> bool {
        b.0
    }
}
impl Eq for Boolean {}
impl Add for Boolean {
    type Output = Self;
    fn add(self, other: Self) -> Self::Output {
        self.or(other)
    }
}
impl AddAssign for Boolean {
    fn add_assign(&mut self, other: Self) {
        self.0 |= other.0
    }
}
impl Rem for Boolean {
    type Output = Self;
    fn rem(self, other: Self) -> Self::Output {
        self - other
    }
}
impl RemAssign for Boolean {
    fn rem_assign(&mut self, other: Self) {
        *self -= other
    }
}
impl Sub for Boolean {
    type Output = Self;
    fn sub(self, other: Self) -> Self::Output {
        self.xor(other)
    }
}
impl SubAssign for Boolean {
    fn sub_assign(&mut self, other: Self) {
        self.0 ^= other.0
    }
}
impl Sum for Boolean {
    fn sum<I: Iterator<Item = Self>>(mut iter: I) -> Self {
        Self(iter.any(|b| b.0))
    }
}
impl Mul for Boolean {
    type Output = Self;
    fn mul(self, other: Self) -> Self {
        self.and(other)
    }
}
impl MulAssign for Boolean {
    fn mul_assign(&mut self, other: Self) {
        self.0 &= other.0
    }
}
impl Div for Boolean {
    type Output = Self;
    fn div(self, other: Self) -> Self::Output {
        if let Self(false) = other {
            panic!("divide by zero!")
        } else {
            self
        }
    }
}
impl DivAssign for Boolean {
    fn div_assign(&mut self, other: Self) {
        let div = *self / other;
        *self = div;
    }
}
impl Product for Boolean {
    fn product<I: Iterator<Item = Self>>(mut iter: I) -> Self {
        Self(iter.all(|b| b.0))
    }
}
macro_rules! trig_bool {
    ($fun:ident) => {
        fn $fun(self) -> Self::Out {
            self.as_radians().$fun().into()
        }
    };
}
impl Trigonometry for Boolean {
    type Out = Float;
    trig_bool! {asin}
    trig_bool! {sin}
    trig_bool! {sinh}
    trig_bool! {asinh}
    trig_bool! {acos}
    trig_bool! {cos}
    trig_bool! {cosh}
    trig_bool! {acosh}
    trig_bool! {atan}
    trig_bool! {tan}
    trig_bool! {tanh}
    trig_bool! {atanh}
}
impl CastFrom<Boolean> for u64 {
    fn cast_from(b: Boolean) -> u64 {
        UInt::from(b).into()
    }
}
fmt_debug!(Boolean);
impl fmt::Display for Boolean {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        fmt::Display::fmt(&self.0, f)
    }
}
#[derive(Clone, Copy)]
pub enum Complex {
    C32(_Complex<f32>),
    C64(_Complex<f64>),
}
impl GetSize for Complex {
    fn get_size(&self) -> usize {
        match self {
            Self::C32(c) => c.re.get_size() + c.im.get_size(),
            Self::C64(c) => c.re.get_size() + c.im.get_size(),
        }
    }
}
impl Complex {
    pub fn im(&self) -> Float {
        match self {
            Self::C32(c) => Float::F32(c.im),
            Self::C64(c) => Float::F64(c.im),
        }
    }
    pub fn re(&self) -> Float {
        match self {
            Self::C32(c) => Float::F32(c.re),
            Self::C64(c) => Float::F64(c.re),
        }
    }
}
impl NumberInstance for Complex {
    type Abs = Float;
    type Exp = Self;
    type Log = Self;
    type Round = Self;
    type Class = ComplexType;
    fn class(&self) -> ComplexType {
        match self {
            Self::C32(_) => ComplexType::C32,
            Self::C64(_) => ComplexType::C64,
        }
    }
    fn into_type(self, dtype: ComplexType) -> Complex {
        use ComplexType::*;
        match dtype {
            C32 => match self {
                Self::C64(c) => Self::C32(_Complex::new(c.re as f32, c.im as f32)),
                this => this,
            },
            C64 => match self {
                Self::C32(c) => Self::C64(_Complex::new(c.re as f64, c.im as f64)),
                this => this,
            },
            Complex => self,
        }
    }
    fn abs(self) -> Float {
        match self {
            Self::C32(c) => Float::F32(c.norm_sqr().sqrt()),
            Self::C64(c) => Float::F64(c.norm_sqr().sqrt()),
        }
    }
    fn exp(self) -> Self::Exp {
        match self {
            Self::C32(c) => Self::C32(c.exp()),
            Self::C64(c) => Self::C64(c.exp()),
        }
    }
    fn ln(self) -> Self::Log {
        match self {
            Self::C32(c) => c.ln().into(),
            Self::C64(c) => c.ln().into(),
        }
    }
    fn log<N: NumberInstance>(self, base: N) -> Self::Log
    where
        Float: From<N>,
    {
        match self {
            Self::C32(c) => c.log(Float::from(base).cast_into()).into(),
            Self::C64(c) => c.log(Float::from(base).cast_into()).into(),
        }
    }
    fn pow(self, exp: Number) -> Self {
        match self {
            Self::C64(this) => match exp {
                Number::Complex(exp) => unimplemented!("{}: {}", ERR_COMPLEX_POWER, exp),
                Number::Float(Float::F64(exp)) => Self::C64(this.pow(exp)),
                Number::Float(Float::F32(exp)) => Self::C64(this.pow(exp)),
                exp => Self::C64(this.pow(f64::cast_from(exp))),
            },
            Self::C32(this) => match exp {
                Number::Complex(exp) => unimplemented!("{}: {}", ERR_COMPLEX_POWER, exp),
                Number::Float(Float::F64(exp)) => {
                    let this = _Complex::<f64>::new(this.re.into(), this.im.into());
                    Self::C64(this.pow(exp))
                }
                Number::Float(Float::F32(exp)) => Self::C32(this.pow(exp)),
                exp => Self::C32(this.pow(f32::cast_from(exp))),
            },
        }
    }
    fn round(self) -> Self::Round {
        match self {
            Self::C32(c) => Self::C32(_Complex::new(c.re.round(), c.im.round())),
            Self::C64(c) => Self::C64(_Complex::new(c.re.round(), c.im.round())),
        }
    }
}
impl FloatInstance for Complex {
    fn is_infinite(&self) -> bool {
        match self {
            Self::C32(c) => c.im.is_infinite() || c.re.is_infinite(),
            Self::C64(c) => c.im.is_infinite() || c.re.is_infinite(),
        }
    }
    fn is_nan(&self) -> bool {
        match self {
            Self::C32(c) => c.im.is_nan() || c.re.is_nan(),
            Self::C64(c) => c.im.is_nan() || c.re.is_nan(),
        }
    }
}
impl From<[f32; 2]> for Complex {
    fn from(arr: [f32; 2]) -> Self {
        Self::C32(num::Complex::new(arr[0], arr[1]))
    }
}
impl From<[f64; 2]> for Complex {
    fn from(arr: [f64; 2]) -> Self {
        Self::C64(num::Complex::new(arr[0], arr[1]))
    }
}
impl<R, I> From<(R, I)> for Complex
where
    R: Into<f64>,
    I: Into<f64>,
{
    fn from(value: (R, I)) -> Self {
        let re = value.0.into();
        let im = value.1.into();
        Self::C64(num::Complex::new(re, im))
    }
}
impl CastFrom<Number> for Complex {
    fn cast_from(number: Number) -> Complex {
        use Number::*;
        match number {
            Number::Bool(b) => Self::from(b),
            Complex(c) => c,
            Float(f) => Self::from(f),
            Int(i) => Self::from(i),
            UInt(u) => Self::from(u),
        }
    }
}
impl CastFrom<Complex> for Boolean {
    fn cast_from(c: Complex) -> Self {
        match c {
            Complex::C32(c) if c.norm_sqr() == 0f32 => Self(false),
            Complex::C64(c) if c.norm_sqr() == 0f64 => Self(false),
            _ => Self(true),
        }
    }
}
impl CastFrom<Complex> for _Complex<f32> {
    fn cast_from(c: Complex) -> Self {
        match c {
            Complex::C32(c) => c,
            Complex::C64(_Complex { re, im }) => Self::new(re as f32, im as f32),
        }
    }
}
impl Add for Complex {
    type Output = Self;
    fn add(self, other: Complex) -> Self {
        match (self, other) {
            (Self::C32(l), Self::C32(r)) => Self::C32(l + r),
            (Self::C64(l), Self::C64(r)) => Self::C64(l + r),
            (Self::C64(l), r) => {
                let r: _Complex<f64> = r.into();
                Self::C64(l + r)
            }
            (l, r) => r + l,
        }
    }
}
impl AddAssign for Complex {
    fn add_assign(&mut self, other: Self) {
        let sum = *self + other;
        *self = sum;
    }
}
impl Rem for Complex {
    type Output = Self;
    fn rem(self, other: Self) -> Self::Output {
        match (self, other) {
            (Self::C32(l), Self::C32(r)) => Self::C32(l - r),
            (l, r) => {
                let l: _Complex<f64> = l.into();
                let r: _Complex<f64> = r.into();
                Self::C64(l % r)
            }
        }
    }
}
impl Sub for Complex {
    type Output = Self;
    fn sub(self, other: Complex) -> Self {
        match (self, other) {
            (Self::C32(l), Self::C32(r)) => Self::C32(l - r),
            (l, r) => {
                let l: _Complex<f64> = l.into();
                let r: _Complex<f64> = r.into();
                Self::C64(l - r)
            }
        }
    }
}
impl SubAssign for Complex {
    fn sub_assign(&mut self, other: Self) {
        let diff = *self - other;
        *self = diff;
    }
}
impl Sum for Complex {
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
        let mut sum = ComplexType::Complex.zero();
        for i in iter {
            sum = sum + i;
        }
        sum
    }
}
impl Mul for Complex {
    type Output = Self;
    fn mul(self, other: Complex) -> Self {
        match (self, other) {
            (Self::C32(l), Self::C32(r)) => Self::C32(l * r),
            (Self::C64(l), Self::C64(r)) => Self::C64(l * r),
            (Self::C64(l), r) => {
                let r: _Complex<f64> = r.into();
                Self::C64(l * r)
            }
            (l, r) => r * l,
        }
    }
}
impl MulAssign for Complex {
    fn mul_assign(&mut self, other: Self) {
        let product = *self * other;
        *self = product;
    }
}
impl Div for Complex {
    type Output = Self;
    fn div(self, other: Complex) -> Self {
        match (self, other) {
            (Self::C32(l), Self::C32(r)) => Self::C32(l / r),
            (Self::C64(l), Self::C64(r)) => Self::C64(l / r),
            (Self::C64(l), r) => {
                let r: _Complex<f64> = r.into();
                Self::C64(l / r)
            }
            (Self::C32(l), Self::C64(r)) => {
                let l = _Complex::<f64>::new(l.re as f64, l.im as f64);
                Self::C64(l / r)
            }
        }
    }
}
impl DivAssign for Complex {
    fn div_assign(&mut self, other: Self) {
        let div = *self / other;
        *self = div;
    }
}
impl Product for Complex {
    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
        let zero = ComplexType::Complex.zero();
        let mut product = ComplexType::Complex.one();
        for i in iter {
            if i == zero {
                return zero;
            }
            product = product * i;
        }
        product
    }
}
macro_rules! trig_complex {
    ($fun:ident) => {
        fn $fun(self) -> Self {
            match self {
                Complex::C32(c) => c.$fun().into(),
                Complex::C64(c) => c.$fun().into(),
            }
        }
    };
}
impl Trigonometry for Complex {
    type Out = Self;
    trig_complex! {asin}
    trig_complex! {sin}
    trig_complex! {sinh}
    trig_complex! {asinh}
    trig_complex! {acos}
    trig_complex! {cos}
    trig_complex! {cosh}
    trig_complex! {acosh}
    trig_complex! {atan}
    trig_complex! {tan}
    trig_complex! {tanh}
    trig_complex! {atanh}
}
impl PartialEq for Complex {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::C32(l), Self::C32(r)) => l.eq(r),
            (Self::C64(l), Self::C64(r)) => l.eq(r),
            (Self::C64(l), Self::C32(r)) => l.re as f32 == r.re && l.im as f32 == r.im,
            (l, r) => r.eq(l),
        }
    }
}
impl Eq for Complex {}
impl Hash for Complex {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            Self::C32(c) => {
                Float::F32(c.re).hash(state);
                Float::F32(c.im).hash(state);
            }
            Self::C64(c) => {
                Float::F64(c.re).hash(state);
                Float::F64(c.im).hash(state);
            }
        }
    }
}
impl Default for Complex {
    fn default() -> Complex {
        Complex::C32(_Complex::<f32>::default())
    }
}
impl From<Complex> for _Complex<f64> {
    fn from(c: Complex) -> Self {
        match c {
            Complex::C32(c) => Self::new(c.re as f64, c.im as f64),
            Complex::C64(c64) => c64,
        }
    }
}
impl From<Float> for Complex {
    fn from(f: Float) -> Self {
        match f {
            Float::F64(f) => Self::C64(_Complex::new(f, 0.0f64)),
            Float::F32(f) => Self::C32(_Complex::new(f, 0.0f32)),
        }
    }
}
impl From<Int> for Complex {
    fn from(i: Int) -> Self {
        match i {
            Int::I8(i) => Self::C32(_Complex::new(i as f32, 0.0f32)),
            Int::I64(i) => Self::C64(_Complex::new(i as f64, 0.0f64)),
            Int::I32(i) => Self::C32(_Complex::new(i as f32, 0.0f32)),
            Int::I16(i) => Self::C32(_Complex::new(i as f32, 0.0f32)),
        }
    }
}
impl From<UInt> for Complex {
    fn from(u: UInt) -> Self {
        match u {
            UInt::U64(u) => Self::C64(_Complex::new(u as f64, 0.0f64)),
            UInt::U32(u) => Self::C32(_Complex::new(u as f32, 0.0f32)),
            UInt::U16(u) => Self::C32(_Complex::new(u as f32, 0.0f32)),
            UInt::U8(u) => Self::C32(_Complex::new(u as f32, 0.0f32)),
        }
    }
}
impl From<Boolean> for Complex {
    fn from(b: Boolean) -> Self {
        match b {
            Boolean(true) => Self::C32(_Complex::new(1.0f32, 0.0f32)),
            Boolean(false) => Self::C32(_Complex::new(1.0f32, 0.0f32)),
        }
    }
}
impl From<_Complex<f32>> for Complex {
    fn from(c: _Complex<f32>) -> Self {
        Self::C32(c)
    }
}
impl From<_Complex<f64>> for Complex {
    fn from(c: _Complex<f64>) -> Self {
        Self::C64(c)
    }
}
impl FromStr for Complex {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        num::Complex::<f64>::from_str(s)
            .map(Self::from)
            .map_err(Error::new)
    }
}
impl From<Complex> for (Float, Float) {
    fn from(n: Complex) -> Self {
        match n {
            Complex::C32(n) => (Float::F32(n.re), Float::F32(n.im)),
            Complex::C64(n) => (Float::F64(n.re), Float::F64(n.im)),
        }
    }
}
impl From<Complex> for [Float; 2] {
    fn from(n: Complex) -> Self {
        match n {
            Complex::C32(n) => [Float::F32(n.re), Float::F32(n.im)],
            Complex::C64(n) => [Float::F64(n.re), Float::F64(n.im)],
        }
    }
}
fmt_debug!(Complex);
impl fmt::Display for Complex {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Complex::C32(c) => fmt::Display::fmt(c, f),
            Complex::C64(c) => fmt::Display::fmt(c, f),
        }
    }
}
#[derive(Copy, Clone, Default, Eq, PartialEq)]
pub struct ComplexCollator {
    float: FloatCollator,
}
impl Collate for ComplexCollator {
    type Value = Complex;
    fn cmp(&self, left: &Self::Value, right: &Self::Value) -> Ordering {
        self.float.cmp(&left.abs(), &right.abs())
    }
}
#[derive(Clone, Copy, GetSize)]
pub enum Float {
    F32(f32),
    F64(f64),
}
impl NumberInstance for Float {
    type Abs = Float;
    type Exp = Self;
    type Log = Self;
    type Round = Int;
    type Class = FloatType;
    fn class(&self) -> FloatType {
        match self {
            Self::F32(_) => FloatType::F32,
            Self::F64(_) => FloatType::F64,
        }
    }
    fn into_type(self, dtype: FloatType) -> Float {
        use FloatType::*;
        match dtype {
            F32 => match self {
                Self::F64(f) => Self::F32(f as f32),
                this => this,
            },
            F64 => match self {
                Self::F32(f) => Self::F64(f as f64),
                this => this,
            },
            Float => self,
        }
    }
    fn abs(self) -> Float {
        match self {
            Self::F32(f) => Self::F32(f.abs()),
            Self::F64(f) => Self::F64(f.abs()),
        }
    }
    fn exp(self) -> Self::Exp {
        match self {
            Self::F32(f) => Self::F32(f.exp()),
            Self::F64(f) => Self::F64(f.exp()),
        }
    }
    fn ln(self) -> Self::Log {
        match self {
            Self::F32(f) => f.ln().into(),
            Self::F64(f) => f.ln().into(),
        }
    }
    fn log<N: NumberInstance>(self, base: N) -> Self::Log
    where
        Float: From<N>,
    {
        match self {
            Self::F32(f) => f.log(Float::from(base).cast_into()).into(),
            Self::F64(f) => f.log(Float::from(base).cast_into()).into(),
        }
    }
    fn pow(self, exp: Number) -> Self {
        match self {
            Self::F64(this) => match exp {
                Number::Complex(exp) => unimplemented!("{}: {}", ERR_COMPLEX_POWER, exp),
                exp => this.pow(f64::cast_from(exp)).into(),
            },
            Self::F32(this) => match exp {
                Number::Complex(exp) => unimplemented!("{}: {}", ERR_COMPLEX_POWER, exp),
                Number::Float(Float::F64(exp)) => Self::F64(f64::from(self).pow(exp)),
                exp => this.pow(f32::cast_from(exp)).into(),
            },
        }
    }
    fn round(self) -> Self::Round {
        match self {
            Self::F32(f) => (f.round() as i32).into(),
            Self::F64(f) => (f.round() as i64).into(),
        }
    }
}
impl RealInstance for Float {
    const ONE: Self = Float::F32(1.);
    const ZERO: Self = Float::F32(0.);
}
impl FloatInstance for Float {
    fn is_infinite(&self) -> bool {
        match self {
            Self::F32(f) => f.is_infinite(),
            Self::F64(f) => f.is_infinite(),
        }
    }
    fn is_nan(&self) -> bool {
        match self {
            Self::F32(f) => f.is_nan(),
            Self::F64(f) => f.is_nan(),
        }
    }
}
impl Eq for Float {}
impl Add for Float {
    type Output = Self;
    fn add(self, other: Float) -> Self {
        match (self, other) {
            (Self::F32(l), Self::F32(r)) => Self::F32(l + r),
            (Self::F64(l), Self::F64(r)) => Self::F64(l + r),
            (Self::F64(l), Self::F32(r)) => Self::F64(l + r as f64),
            (l, r) => r + l,
        }
    }
}
impl AddAssign for Float {
    fn add_assign(&mut self, other: Self) {
        let sum = *self + other;
        *self = sum;
    }
}
impl Sub for Float {
    type Output = Self;
    fn sub(self, other: Float) -> Self {
        match (self, other) {
            (Self::F32(l), Self::F32(r)) => Self::F32(l - r),
            (l, r) => {
                let l: f64 = l.into();
                let r: f64 = r.into();
                Self::F64(l - r)
            }
        }
    }
}
impl SubAssign for Float {
    fn sub_assign(&mut self, other: Self) {
        let diff = *self - other;
        *self = diff;
    }
}
impl Sum for Float {
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
        let mut sum = FloatType::Float.zero();
        for i in iter {
            sum = sum + i;
        }
        sum
    }
}
impl Rem for Float {
    type Output = Self;
    fn rem(self, other: Self) -> Self::Output {
        match (self, other) {
            (Self::F64(l), Self::F64(r)) => Self::F64(l % r),
            (Self::F32(l), Self::F32(r)) => Self::F32(l % r),
            (Self::F64(l), Self::F32(r)) => Self::F64(l % r as f64),
            (Self::F32(l), Self::F64(r)) => Self::F64(l as f64 % r),
        }
    }
}
impl RemAssign for Float {
    fn rem_assign(&mut self, other: Self) {
        let rem = *self % other;
        *self = rem;
    }
}
impl Mul for Float {
    type Output = Self;
    fn mul(self, other: Float) -> Self {
        match (self, other) {
            (Self::F32(l), Self::F32(r)) => Self::F32(l * r),
            (Self::F64(l), Self::F64(r)) => Self::F64(l * r),
            (Self::F64(l), Self::F32(r)) => Self::F64(l * r as f64),
            (l, r) => r * l,
        }
    }
}
impl MulAssign for Float {
    fn mul_assign(&mut self, other: Self) {
        let product = *self * other;
        *self = product;
    }
}
impl Div for Float {
    type Output = Self;
    fn div(self, other: Self) -> Self::Output {
        match (self, other) {
            (Self::F32(l), Self::F32(r)) => Self::F32(l / r),
            (Self::F64(l), Self::F64(r)) => Self::F64(l / r),
            (Self::F32(l), Self::F64(r)) => Self::F64((l as f64) / r),
            (Self::F64(l), Self::F32(r)) => Self::F64(l / (r as f64)),
        }
    }
}
impl DivAssign for Float {
    fn div_assign(&mut self, other: Self) {
        let div = *self / other;
        *self = div;
    }
}
impl Product for Float {
    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
        let zero = FloatType::Float.zero();
        let mut product = FloatType::Float.one();
        for i in iter {
            if i == zero {
                return zero;
            }
            product = product * i;
        }
        product
    }
}
macro_rules! trig_float {
    ($fun:ident) => {
        fn $fun(self) -> Self {
            match self {
                Float::F32(f) => f.$fun().into(),
                Float::F64(f) => f.$fun().into(),
            }
        }
    };
}
impl Trigonometry for Float {
    type Out = Self;
    trig_float! {asin}
    trig_float! {sin}
    trig_float! {sinh}
    trig_float! {asinh}
    trig_float! {acos}
    trig_float! {cos}
    trig_float! {cosh}
    trig_float! {acosh}
    trig_float! {atan}
    trig_float! {tan}
    trig_float! {tanh}
    trig_float! {atanh}
}
impl Hash for Float {
    fn hash<H: Hasher>(&self, state: &mut H) {
        match self {
            Self::F32(f) => f.to_be_bytes().hash(state),
            Self::F64(f) => f.to_be_bytes().hash(state),
        }
    }
}
impl PartialEq for Float {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::F32(l), Self::F32(r)) => l.eq(r),
            (Self::F64(l), Self::F64(r)) => l.eq(r),
            (Self::F64(l), Self::F32(r)) => (*l as f32).eq(r),
            (l, r) => r.eq(l),
        }
    }
}
impl PartialOrd for Float {
    fn partial_cmp(&self, other: &Float) -> Option<Ordering> {
        match (self, other) {
            (Float::F32(l), Float::F32(r)) => l.partial_cmp(r),
            (Float::F64(l), Float::F64(r)) => l.partial_cmp(r),
            (l, r) => f64::from(*l).partial_cmp(&f64::from(*r)),
        }
    }
}
impl Default for Float {
    fn default() -> Float {
        Float::F32(f32::default())
    }
}
impl From<Boolean> for Float {
    fn from(b: Boolean) -> Self {
        match b {
            Boolean(true) => Self::F32(1.0f32),
            Boolean(false) => Self::F32(0.0f32),
        }
    }
}
impl From<f32> for Float {
    fn from(f: f32) -> Self {
        Self::F32(f)
    }
}
impl From<f64> for Float {
    fn from(f: f64) -> Self {
        Self::F64(f)
    }
}
impl From<Int> for Float {
    fn from(i: Int) -> Self {
        match i {
            Int::I8(i) => Self::F32(i as f32),
            Int::I64(i) => Self::F64(i as f64),
            Int::I32(i) => Self::F32(i as f32),
            Int::I16(i) => Self::F32(i as f32),
        }
    }
}
impl From<UInt> for Float {
    fn from(u: UInt) -> Self {
        match u {
            UInt::U64(u) => Self::F64(u as f64),
            UInt::U32(u) => Self::F32(u as f32),
            UInt::U16(u) => Self::F32(u as f32),
            UInt::U8(u) => Self::F32(u as f32),
        }
    }
}
impl FromStr for Float {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        f64::from_str(s).map(Self::from).map_err(Error::new)
    }
}
impl CastFrom<Complex> for Float {
    fn cast_from(c: Complex) -> Float {
        use Complex::*;
        match c {
            C32(c) => Self::F32(c.re),
            C64(c) => Self::F64(c.re),
        }
    }
}
impl CastFrom<Float> for Boolean {
    fn cast_from(f: Float) -> Boolean {
        use Float::*;
        let b = match f {
            F32(f) if f == 0f32 => false,
            F64(f) if f == 0f64 => false,
            _ => true,
        };
        Boolean(b)
    }
}
impl CastFrom<Float> for f32 {
    fn cast_from(f: Float) -> f32 {
        match f {
            Float::F32(f) => f,
            Float::F64(f) => f as f32,
        }
    }
}
impl From<Float> for f64 {
    fn from(f: Float) -> f64 {
        match f {
            Float::F32(f) => f as f64,
            Float::F64(f) => f,
        }
    }
}
fmt_debug!(Float);
impl fmt::Display for Float {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Float::F32(n) => fmt::Display::fmt(n, f),
            Float::F64(n) => fmt::Display::fmt(n, f),
        }
    }
}
#[derive(Copy, Clone, Default, Eq, PartialEq)]
struct F32Collator;
impl Collate for F32Collator {
    type Value = f32;
    fn cmp(&self, left: &f32, right: &f32) -> Ordering {
        if left == right {
            Ordering::Equal
        } else {
            left.total_cmp(right)
        }
    }
}
#[derive(Copy, Clone, Default, Eq, PartialEq)]
struct F64Collator;
impl Collate for F64Collator {
    type Value = f64;
    fn cmp(&self, left: &f64, right: &f64) -> Ordering {
        if left == right {
            Ordering::Equal
        } else {
            left.total_cmp(right)
        }
    }
}
#[derive(Copy, Clone, Default, Eq, PartialEq)]
pub struct FloatCollator {
    f32: F32Collator,
    f64: F64Collator,
}
impl Collate for FloatCollator {
    type Value = Float;
    fn cmp(&self, left: &Self::Value, right: &Self::Value) -> Ordering {
        if let Some(order) = left.partial_cmp(right) {
            order
        } else {
            match (left, right) {
                (Float::F32(l), Float::F32(r)) => self.f32.cmp(l.into(), r.into()),
                (Float::F64(l), Float::F64(r)) => self.f64.cmp(l.into(), r.into()),
                (l, r) => self.f64.cmp(&(*l).cast_into(), &(*r).cast_into()),
            }
        }
    }
}
#[derive(Clone, Copy, Hash, GetSize)]
pub enum Int {
    I8(i8),
    I16(i16),
    I32(i32),
    I64(i64),
}
impl NumberInstance for Int {
    type Abs = Self;
    type Exp = Float;
    type Log = Float;
    type Round = Self;
    type Class = IntType;
    fn class(&self) -> IntType {
        match self {
            Self::I8(_) => IntType::I8,
            Self::I16(_) => IntType::I16,
            Self::I32(_) => IntType::I32,
            Self::I64(_) => IntType::I64,
        }
    }
    fn into_type(self, dtype: IntType) -> Int {
        use IntType::*;
        match dtype {
            I8 => match self {
                Self::I16(i) => Self::I8(i as i8),
                Self::I32(i) => Self::I8(i as i8),
                Self::I64(i) => Self::I8(i as i8),
                this => this,
            },
            I16 => match self {
                Self::I8(i) => Self::I16(i as i16),
                Self::I32(i) => Self::I16(i as i16),
                Self::I64(i) => Self::I16(i as i16),
                this => this,
            },
            I32 => match self {
                Self::I8(i) => Self::I32(i as i32),
                Self::I16(i) => Self::I32(i as i32),
                Self::I64(i) => Self::I32(i as i32),
                this => this,
            },
            I64 => match self {
                Self::I8(i) => Self::I64(i as i64),
                Self::I16(i) => Self::I64(i as i64),
                Self::I32(i) => Self::I64(i as i64),
                this => this,
            },
            Int => self,
        }
    }
    fn abs(self) -> Self {
        match self {
            Self::I8(i) => Int::I8(i.abs()),
            Self::I16(i) => Int::I16(i.abs()),
            Self::I32(i) => Int::I32(i.abs()),
            Self::I64(i) => Int::I64(i.abs()),
        }
    }
    fn exp(self) -> Self::Exp {
        Float::from(self).exp()
    }
    fn ln(self) -> Self::Log {
        Float::from(self).ln()
    }
    fn log<N: NumberInstance>(self, base: N) -> Self::Log
    where
        Float: From<N>,
    {
        let this: Float = self.into();
        this.log(base)
    }
    fn pow(self, exp: Number) -> Self {
        if exp < exp.class().zero() {
            return self.class().zero();
        }
        match self {
            Self::I8(this) => Self::I8(this.pow(exp.cast_into())),
            Self::I16(this) => Self::I16(this.pow(exp.cast_into())),
            Self::I32(this) => Self::I32(this.pow(exp.cast_into())),
            Self::I64(this) => Self::I64(this.pow(exp.cast_into())),
        }
    }
    fn round(self) -> Self::Round {
        self
    }
}
impl RealInstance for Int {
    const ONE: Self = Int::I8(1);
    const ZERO: Self = Int::I8(0);
}
impl CastFrom<Complex> for Int {
    fn cast_from(c: Complex) -> Int {
        use Complex::*;
        match c {
            C32(c) => Self::I32(c.re as i32),
            C64(c) => Self::I64(c.re as i64),
        }
    }
}
impl CastFrom<Float> for Int {
    fn cast_from(f: Float) -> Int {
        use Float::*;
        match f {
            F32(f) => Self::I32(f as i32),
            F64(f) => Self::I64(f as i64),
        }
    }
}
impl CastFrom<Int> for Boolean {
    fn cast_from(i: Int) -> Boolean {
        use Int::*;
        let b = match i {
            I16(i) if i == 0i16 => false,
            I32(i) if i == 0i32 => false,
            I64(i) if i == 0i64 => false,
            _ => true,
        };
        Boolean(b)
    }
}
impl CastFrom<Int> for i8 {
    fn cast_from(i: Int) -> i8 {
        match i {
            Int::I8(i) => i,
            Int::I16(i) => i as i8,
            Int::I32(i) => i as i8,
            Int::I64(i) => i as i8,
        }
    }
}
impl CastFrom<Int> for i16 {
    fn cast_from(i: Int) -> i16 {
        match i {
            Int::I8(i) => i as i16,
            Int::I16(i) => i,
            Int::I32(i) => i as i16,
            Int::I64(i) => i as i16,
        }
    }
}
impl CastFrom<Int> for i32 {
    fn cast_from(i: Int) -> i32 {
        match i {
            Int::I8(i) => i as i32,
            Int::I16(i) => i as i32,
            Int::I32(i) => i,
            Int::I64(i) => i as i32,
        }
    }
}
impl Eq for Int {}
impl Add for Int {
    type Output = Self;
    fn add(self, other: Int) -> Self {
        match (self, other) {
            (Self::I64(l), Self::I64(r)) => Self::I64(l + r),
            (Self::I64(l), Self::I32(r)) => Self::I64(l + r as i64),
            (Self::I64(l), Self::I16(r)) => Self::I64(l + r as i64),
            (Self::I64(l), Self::I8(r)) => Self::I64(l + r as i64),
            (Self::I32(l), Self::I32(r)) => Self::I32(l + r),
            (Self::I32(l), Self::I16(r)) => Self::I32(l + r as i32),
            (Self::I32(l), Self::I8(r)) => Self::I32(l + r as i32),
            (Self::I16(l), Self::I16(r)) => Self::I16(l + r),
            (Self::I16(l), Self::I8(r)) => Self::I16(l + r as i16),
            (Self::I8(l), Self::I8(r)) => Self::I8(l + r),
            (l, r) => r + l,
        }
    }
}
impl AddAssign for Int {
    fn add_assign(&mut self, other: Self) {
        let sum = *self + other;
        *self = sum;
    }
}
impl Rem for Int {
    type Output = Self;
    fn rem(self, other: Self) -> Self::Output {
        match (self, other) {
            (Self::I64(l), Self::I64(r)) => Self::I64(l % r),
            (Self::I64(l), Self::I32(r)) => Self::I64(l % r as i64),
            (Self::I64(l), Self::I16(r)) => Self::I64(l % r as i64),
            (Self::I64(l), Self::I8(r)) => Self::I64(l % r as i64),
            (Self::I32(l), Self::I64(r)) => Self::I64(l as i64 % r),
            (Self::I32(l), Self::I32(r)) => Self::I32(l % r),
            (Self::I32(l), Self::I16(r)) => Self::I32(l % r as i32),
            (Self::I32(l), Self::I8(r)) => Self::I32(l % r as i32),
            (Self::I16(l), Self::I64(r)) => Self::I64(l as i64 % r),
            (Self::I16(l), Self::I32(r)) => Self::I32(l as i32 % r),
            (Self::I16(l), Self::I16(r)) => Self::I16(l % r),
            (Self::I16(l), Self::I8(r)) => Self::I16(l % r as i16),
            (Self::I8(l), Self::I64(r)) => Self::I64(l as i64 % r),
            (Self::I8(l), Self::I32(r)) => Self::I32(l as i32 % r),
            (Self::I8(l), Self::I16(r)) => Self::I16(l as i16 % r),
            (Self::I8(l), Self::I8(r)) => Self::I8(l % r),
        }
    }
}
impl RemAssign for Int {
    fn rem_assign(&mut self, other: Self) {
        let rem = *self % other;
        *self = rem;
    }
}
impl Sub for Int {
    type Output = Self;
    fn sub(self, other: Int) -> Self {
        match (self, other) {
            (Self::I64(l), Self::I64(r)) => Self::I64(l - r),
            (Self::I64(l), Self::I32(r)) => Self::I64(l - r as i64),
            (Self::I64(l), Self::I16(r)) => Self::I64(l - r as i64),
            (Self::I64(l), Self::I8(r)) => Self::I64(l - r as i64),
            (Self::I32(l), Self::I64(r)) => Self::I64(l as i64 - r),
            (Self::I32(l), Self::I32(r)) => Self::I32(l - r),
            (Self::I32(l), Self::I16(r)) => Self::I32(l - r as i32),
            (Self::I32(l), Self::I8(r)) => Self::I32(l - r as i32),
            (Self::I16(l), Self::I64(r)) => Self::I64(l as i64 - r),
            (Self::I16(l), Self::I32(r)) => Self::I32(l as i32 - r),
            (Self::I16(l), Self::I16(r)) => Self::I16(l - r),
            (Self::I16(l), Self::I8(r)) => Self::I16(l - r as i16),
            (Self::I8(l), Self::I64(r)) => Self::I64(l as i64 - r),
            (Self::I8(l), Self::I32(r)) => Self::I32(l as i32 - r),
            (Self::I8(l), Self::I16(r)) => Self::I16(l as i16 - r),
            (Self::I8(l), Self::I8(r)) => Self::I8(l - r),
        }
    }
}
impl SubAssign for Int {
    fn sub_assign(&mut self, other: Self) {
        let diff = *self - other;
        *self = diff;
    }
}
impl Sum for Int {
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
        let mut sum = IntType::Int.zero();
        for i in iter {
            sum = sum + i;
        }
        sum
    }
}
impl Mul for Int {
    type Output = Self;
    fn mul(self, other: Int) -> Self {
        match (self, other) {
            (Self::I64(l), Self::I64(r)) => Self::I64(l * r),
            (Self::I64(l), Self::I32(r)) => Self::I64(l * r as i64),
            (Self::I64(l), Self::I16(r)) => Self::I64(l * r as i64),
            (Self::I32(l), Self::I32(r)) => Self::I32(l * r),
            (Self::I32(l), Self::I16(r)) => Self::I32(l * r as i32),
            (Self::I16(l), Self::I16(r)) => Self::I16(l * r),
            (l, r) => r * l,
        }
    }
}
impl MulAssign for Int {
    fn mul_assign(&mut self, other: Self) {
        let product = *self * other;
        *self = product;
    }
}
impl Div for Int {
    type Output = Self;
    fn div(self, other: Int) -> Self {
        match (self, other) {
            (Self::I64(l), Self::I64(r)) => Self::I64(l / r),
            (Self::I64(l), Self::I32(r)) => Self::I64(l / r as i64),
            (Self::I64(l), Self::I16(r)) => Self::I64(l / r as i64),
            (Self::I64(l), Self::I8(r)) => Self::I64(l / r as i64),
            (Self::I32(l), Self::I64(r)) => Self::I64(l as i64 / r),
            (Self::I32(l), Self::I32(r)) => Self::I32(l / r),
            (Self::I32(l), Self::I16(r)) => Self::I32(l / r as i32),
            (Self::I32(l), Self::I8(r)) => Self::I32(l / r as i32),
            (Self::I16(l), Self::I64(r)) => Self::I64(l as i64 / r),
            (Self::I16(l), Self::I32(r)) => Self::I32(l as i32 / r),
            (Self::I16(l), Self::I16(r)) => Self::I16(l / r),
            (Self::I16(l), Self::I8(r)) => Self::I16(l / r as i16),
            (Self::I8(l), Self::I64(r)) => Self::I64(l as i64 / r),
            (Self::I8(l), Self::I32(r)) => Self::I32(l as i32 / r),
            (Self::I8(l), Self::I16(r)) => Self::I16(l as i16 / r),
            (Self::I8(l), Self::I8(r)) => Self::I8(l / r),
        }
    }
}
impl DivAssign for Int {
    fn div_assign(&mut self, other: Self) {
        let div = *self / other;
        *self = div;
    }
}
impl Product for Int {
    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
        let zero = IntType::Int.zero();
        let mut product = IntType::Int.one();
        for i in iter {
            if i == zero {
                return zero;
            }
            product = product * i;
        }
        product
    }
}
macro_rules! trig_int {
    ($fun:ident) => {
        fn $fun(self) -> Self::Out {
            match self {
                Self::I8(i) => (i as f32).$fun().into(),
                Self::I16(i) => (i as f32).$fun().into(),
                Self::I32(i) => (i as f32).$fun().into(),
                Self::I64(i) => (i as f64).$fun().into(),
            }
        }
    };
}
impl Trigonometry for Int {
    type Out = Float;
    trig_int! {asin}
    trig_int! {sin}
    trig_int! {sinh}
    trig_int! {asinh}
    trig_int! {acos}
    trig_int! {cos}
    trig_int! {cosh}
    trig_int! {acosh}
    trig_int! {atan}
    trig_int! {tan}
    trig_int! {tanh}
    trig_int! {atanh}
}
impl PartialEq for Int {
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::I16(l), Self::I16(r)) => l.eq(r),
            (Self::I32(l), Self::I32(r)) => l.eq(r),
            (Self::I64(l), Self::I64(r)) => l.eq(r),
            (Self::I64(l), r) => l.eq(&i64::from(*r)),
            (l, r) => i64::from(*l).eq(&i64::from(*r)),
        }
    }
}
impl PartialOrd for Int {
    fn partial_cmp(&self, other: &Int) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for Int {
    fn cmp(&self, other: &Self) -> Ordering {
        match (self, other) {
            (Int::I8(l), Int::I8(r)) => l.cmp(r),
            (Int::I16(l), Int::I16(r)) => l.cmp(r),
            (Int::I32(l), Int::I32(r)) => l.cmp(r),
            (Int::I64(l), Int::I64(r)) => l.cmp(r),
            (l, r) => i64::from(*l).cmp(&i64::from(*r)),
        }
    }
}
impl Default for Int {
    fn default() -> Int {
        Int::I16(i16::default())
    }
}
impl From<i8> for Int {
    fn from(i: i8) -> Int {
        Int::I8(i)
    }
}
impl From<i16> for Int {
    fn from(i: i16) -> Int {
        Int::I16(i)
    }
}
impl From<i32> for Int {
    fn from(i: i32) -> Int {
        Int::I32(i)
    }
}
impl From<i64> for Int {
    fn from(i: i64) -> Int {
        Int::I64(i)
    }
}
impl From<UInt> for Int {
    fn from(u: UInt) -> Int {
        match u {
            UInt::U64(u) => Int::I64(u as i64),
            UInt::U32(u) => Int::I32(u as i32),
            UInt::U16(u) => Int::I16(u as i16),
            UInt::U8(u) => Int::I16(u as i16),
        }
    }
}
impl From<Boolean> for Int {
    fn from(b: Boolean) -> Int {
        match b {
            Boolean(true) => Int::I16(1),
            Boolean(false) => Int::I16(0),
        }
    }
}
impl From<Int> for i64 {
    fn from(i: Int) -> i64 {
        match i {
            Int::I8(i) => i as i64,
            Int::I16(i) => i as i64,
            Int::I32(i) => i as i64,
            Int::I64(i) => i,
        }
    }
}
impl FromStr for Int {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        i64::from_str(s).map(Self::from).map_err(Error::new)
    }
}
fmt_debug!(Int);
impl fmt::Display for Int {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Int::I8(i) => fmt::Display::fmt(i, f),
            Int::I16(i) => fmt::Display::fmt(i, f),
            Int::I32(i) => fmt::Display::fmt(i, f),
            Int::I64(i) => fmt::Display::fmt(i, f),
        }
    }
}
#[derive(Clone, Copy, Hash, GetSize)]
pub enum UInt {
    U8(u8),
    U16(u16),
    U32(u32),
    U64(u64),
}
impl NumberInstance for UInt {
    type Abs = Self;
    type Exp = Float;
    type Log = Float;
    type Round = Self;
    type Class = UIntType;
    fn class(&self) -> UIntType {
        match self {
            Self::U8(_) => UIntType::U8,
            Self::U16(_) => UIntType::U16,
            Self::U32(_) => UIntType::U32,
            Self::U64(_) => UIntType::U64,
        }
    }
    fn into_type(self, dtype: UIntType) -> UInt {
        use UIntType::*;
        match dtype {
            U8 => match self {
                Self::U16(u) => Self::U8(u as u8),
                Self::U32(u) => Self::U8(u as u8),
                Self::U64(u) => Self::U8(u as u8),
                this => this,
            },
            U16 => match self {
                Self::U8(u) => Self::U16(u as u16),
                Self::U32(u) => Self::U16(u as u16),
                Self::U64(u) => Self::U16(u as u16),
                this => this,
            },
            U32 => match self {
                Self::U8(u) => Self::U32(u as u32),
                Self::U16(u) => Self::U32(u as u32),
                Self::U64(u) => Self::U32(u as u32),
                this => this,
            },
            U64 => match self {
                Self::U8(u) => Self::U64(u as u64),
                Self::U16(u) => Self::U64(u as u64),
                Self::U32(u) => Self::U64(u as u64),
                this => this,
            },
            UInt => self,
        }
    }
    fn abs(self) -> UInt {
        self
    }
    fn exp(self) -> Self::Exp {
        Float::from(self).exp()
    }
    fn ln(self) -> Self::Log {
        Float::from(self).ln()
    }
    fn log<N: NumberInstance>(self, base: N) -> Self::Log
    where
        Float: From<N>,
    {
        let this: Float = self.into();
        this.log(base)
    }
    fn pow(self, exp: Number) -> Self {
        if exp < Number::from(0) {
            return self.class().zero();
        }
        match self {
            Self::U8(this) => Self::U8(this.pow(exp.cast_into())),
            Self::U16(this) => Self::U16(this.pow(exp.cast_into())),
            Self::U32(this) => Self::U32(this.pow(exp.cast_into())),
            Self::U64(this) => Self::U64(this.pow(exp.cast_into())),
        }
    }
    fn round(self) -> Self::Round {
        self
    }
}
impl RealInstance for UInt {
    const ONE: Self = UInt::U8(1);
    const ZERO: Self = UInt::U8(0);
}
impl CastFrom<Complex> for UInt {
    fn cast_from(c: Complex) -> UInt {
        use Complex::*;
        match c {
            C32(c) => Self::U32(c.re as u32),
            C64(c) => Self::U64(c.re as u64),
        }
    }
}
impl CastFrom<Float> for UInt {
    fn cast_from(f: Float) -> UInt {
        use Float::*;
        match f {
            F32(f) => Self::U32(f as u32),
            F64(f) => Self::U64(f as u64),
        }
    }
}
impl CastFrom<Int> for UInt {
    fn cast_from(i: Int) -> UInt {
        use Int::*;
        match i {
            I8(i) => Self::U8(i as u8),
            I16(i) => Self::U16(i as u16),
            I32(i) => Self::U32(i as u32),
            I64(i) => Self::U64(i as u64),
        }
    }
}
impl CastFrom<UInt> for bool {
    fn cast_from(u: UInt) -> bool {
        use UInt::*;
        match u {
            U8(u) if u == 0u8 => false,
            U16(u) if u == 0u16 => false,
            U32(u) if u == 0u32 => false,
            U64(u) if u == 0u64 => false,
            _ => true,
        }
    }
}
impl CastFrom<UInt> for u8 {
    fn cast_from(u: UInt) -> u8 {
        use UInt::*;
        match u {
            U8(u) => u,
            U16(u) => u as u8,
            U32(u) => u as u8,
            U64(u) => u as u8,
        }
    }
}
impl CastFrom<UInt> for u16 {
    fn cast_from(u: UInt) -> u16 {
        use UInt::*;
        match u {
            U8(u) => u as u16,
            U16(u) => u,
            U32(u) => u as u16,
            U64(u) => u as u16,
        }
    }
}
impl CastFrom<UInt> for u32 {
    fn cast_from(u: UInt) -> u32 {
        use UInt::*;
        match u {
            U8(u) => u as u32,
            U16(u) => u as u32,
            U32(u) => u,
            U64(u) => u as u32,
        }
    }
}
impl Add for UInt {
    type Output = Self;
    fn add(self, other: UInt) -> Self {
        match (self, other) {
            (UInt::U64(l), UInt::U64(r)) => UInt::U64(l + r),
            (UInt::U64(l), UInt::U32(r)) => UInt::U64(l + r as u64),
            (UInt::U64(l), UInt::U16(r)) => UInt::U64(l + r as u64),
            (UInt::U64(l), UInt::U8(r)) => UInt::U64(l + r as u64),
            (UInt::U32(l), UInt::U32(r)) => UInt::U32(l + r),
            (UInt::U32(l), UInt::U16(r)) => UInt::U32(l + r as u32),
            (UInt::U32(l), UInt::U8(r)) => UInt::U32(l + r as u32),
            (UInt::U16(l), UInt::U16(r)) => UInt::U16(l + r),
            (UInt::U16(l), UInt::U8(r)) => UInt::U16(l + r as u16),
            (UInt::U8(l), UInt::U8(r)) => UInt::U8(l + r),
            (l, r) => r + l,
        }
    }
}
impl AddAssign for UInt {
    fn add_assign(&mut self, other: Self) {
        let sum = *self + other;
        *self = sum;
    }
}
impl Rem for UInt {
    type Output = Self;
    fn rem(self, other: Self) -> Self::Output {
        match (self, other) {
            (UInt::U64(l), UInt::U64(r)) => UInt::U64(l % r),
            (UInt::U64(l), UInt::U32(r)) => UInt::U64(l % r as u64),
            (UInt::U64(l), UInt::U16(r)) => UInt::U64(l % r as u64),
            (UInt::U64(l), UInt::U8(r)) => UInt::U64(l % r as u64),
            (UInt::U32(l), UInt::U32(r)) => UInt::U32(l % r),
            (UInt::U32(l), UInt::U16(r)) => UInt::U32(l % r as u32),
            (UInt::U32(l), UInt::U8(r)) => UInt::U32(l % r as u32),
            (UInt::U16(l), UInt::U16(r)) => UInt::U16(l % r),
            (UInt::U16(l), UInt::U8(r)) => UInt::U16(l % r as u16),
            (UInt::U8(l), UInt::U8(r)) => UInt::U8(l % r),
            (UInt::U8(l), UInt::U16(r)) => UInt::U16(l as u16 % r),
            (UInt::U8(l), UInt::U32(r)) => UInt::U32(l as u32 % r),
            (UInt::U8(l), UInt::U64(r)) => UInt::U64(l as u64 % r),
            (UInt::U16(l), r) => {
                let r: u64 = r.into();
                UInt::U16(l % r as u16)
            }
            (UInt::U32(l), r) => {
                let r: u64 = r.into();
                UInt::U32(l % r as u32)
            }
        }
    }
}
impl Sub for UInt {
    type Output = Self;
    fn sub(self, other: UInt) -> Self {
        match (self, other) {
            (UInt::U64(l), UInt::U64(r)) => UInt::U64(l - r),
            (UInt::U64(l), UInt::U32(r)) => UInt::U64(l - r as u64),
            (UInt::U64(l), UInt::U16(r)) => UInt::U64(l - r as u64),
            (UInt::U64(l), UInt::U8(r)) => UInt::U64(l - r as u64),
            (UInt::U32(l), UInt::U32(r)) => UInt::U32(l - r),
            (UInt::U32(l), UInt::U16(r)) => UInt::U32(l - r as u32),
            (UInt::U32(l), UInt::U8(r)) => UInt::U32(l - r as u32),
            (UInt::U16(l), UInt::U16(r)) => UInt::U16(l - r),
            (UInt::U16(l), UInt::U8(r)) => UInt::U16(l - r as u16),
            (UInt::U8(l), UInt::U8(r)) => UInt::U8(l - r),
            (UInt::U8(l), UInt::U16(r)) => UInt::U16(l as u16 - r),
            (UInt::U8(l), UInt::U32(r)) => UInt::U32(l as u32 - r),
            (UInt::U8(l), UInt::U64(r)) => UInt::U64(l as u64 - r),
            (UInt::U16(l), r) => {
                let r: u64 = r.into();
                UInt::U16(l - r as u16)
            }
            (UInt::U32(l), r) => {
                let r: u64 = r.into();
                UInt::U32(l - r as u32)
            }
        }
    }
}
impl SubAssign for UInt {
    fn sub_assign(&mut self, other: Self) {
        let diff = *self - other;
        *self = diff;
    }
}
impl Sum for UInt {
    fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
        let mut sum = UIntType::UInt.zero();
        for i in iter {
            sum = sum + i;
        }
        sum
    }
}
impl Mul for UInt {
    type Output = Self;
    fn mul(self, other: UInt) -> Self {
        match (self, other) {
            (UInt::U64(l), UInt::U64(r)) => UInt::U64(l * r),
            (UInt::U64(l), UInt::U32(r)) => UInt::U64(l * r as u64),
            (UInt::U64(l), UInt::U16(r)) => UInt::U64(l * r as u64),
            (UInt::U64(l), UInt::U8(r)) => UInt::U64(l * r as u64),
            (UInt::U32(l), UInt::U32(r)) => UInt::U32(l * r),
            (UInt::U32(l), UInt::U16(r)) => UInt::U32(l * r as u32),
            (UInt::U32(l), UInt::U8(r)) => UInt::U32(l * r as u32),
            (UInt::U16(l), UInt::U16(r)) => UInt::U16(l * r),
            (UInt::U16(l), UInt::U8(r)) => UInt::U16(l * r as u16),
            (UInt::U8(l), UInt::U8(r)) => UInt::U8(l * r),
            (l, r) => r * l,
        }
    }
}
impl MulAssign for UInt {
    fn mul_assign(&mut self, other: Self) {
        let product = *self * other;
        *self = product;
    }
}
impl Div for UInt {
    type Output = Self;
    fn div(self, other: UInt) -> Self {
        match (self, other) {
            (UInt::U64(l), UInt::U64(r)) => UInt::U64(l / r),
            (UInt::U64(l), UInt::U32(r)) => UInt::U64(l / r as u64),
            (UInt::U64(l), UInt::U16(r)) => UInt::U64(l / r as u64),
            (UInt::U64(l), UInt::U8(r)) => UInt::U64(l / r as u64),
            (UInt::U32(l), UInt::U64(r)) => UInt::U64(l as u64 / r),
            (UInt::U32(l), UInt::U32(r)) => UInt::U32(l / r),
            (UInt::U32(l), UInt::U16(r)) => UInt::U32(l / r as u32),
            (UInt::U32(l), UInt::U8(r)) => UInt::U32(l / r as u32),
            (UInt::U16(l), UInt::U64(r)) => UInt::U64(l as u64 / r),
            (UInt::U16(l), UInt::U32(r)) => UInt::U32(l as u32 / r),
            (UInt::U16(l), UInt::U16(r)) => UInt::U16(l / r),
            (UInt::U16(l), UInt::U8(r)) => UInt::U16(l / r as u16),
            (UInt::U8(l), UInt::U64(r)) => UInt::U64(l as u64 / r),
            (UInt::U8(l), UInt::U32(r)) => UInt::U32(l as u32 / r),
            (UInt::U8(l), UInt::U16(r)) => UInt::U16(l as u16 / r),
            (UInt::U8(l), UInt::U8(r)) => UInt::U8(l / r),
        }
    }
}
impl DivAssign for UInt {
    fn div_assign(&mut self, other: Self) {
        let div = *self / other;
        *self = div;
    }
}
impl Product for UInt {
    fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
        let zero = UIntType::UInt.zero();
        let mut product = UIntType::UInt.one();
        for i in iter {
            if i == zero {
                return zero;
            }
            product = product * i;
        }
        product
    }
}
macro_rules! trig_uint {
    ($fun:ident) => {
        fn $fun(self) -> Self::Out {
            match self {
                Self::U8(u) => (u as f32).$fun().into(),
                Self::U16(u) => (u as f32).$fun().into(),
                Self::U32(u) => (u as f32).$fun().into(),
                Self::U64(u) => (u as f64).$fun().into(),
            }
        }
    };
}
impl Trigonometry for UInt {
    type Out = Float;
    trig_uint! {asin}
    trig_uint! {sin}
    trig_uint! {sinh}
    trig_uint! {asinh}
    trig_uint! {acos}
    trig_uint! {cos}
    trig_uint! {cosh}
    trig_uint! {acosh}
    trig_uint! {atan}
    trig_uint! {tan}
    trig_uint! {tanh}
    trig_uint! {atanh}
}
impl Eq for UInt {}
impl PartialEq for UInt {
    fn eq(&self, other: &UInt) -> bool {
        match (self, other) {
            (Self::U8(l), Self::U8(r)) => l.eq(r),
            (Self::U16(l), Self::U16(r)) => l.eq(r),
            (Self::U32(l), Self::U32(r)) => l.eq(r),
            (Self::U64(l), Self::U64(r)) => l.eq(r),
            (l, r) => u64::from(*l).eq(&u64::from(*r)),
        }
    }
}
impl PartialOrd for UInt {
    fn partial_cmp(&self, other: &UInt) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}
impl Ord for UInt {
    fn cmp(&self, other: &UInt) -> Ordering {
        match (self, other) {
            (Self::U8(l), Self::U8(r)) => l.cmp(r),
            (Self::U16(l), Self::U16(r)) => l.cmp(r),
            (Self::U32(l), Self::U32(r)) => l.cmp(r),
            (Self::U64(l), Self::U64(r)) => l.cmp(r),
            (l, r) => u64::from(*l).cmp(&u64::from(*r)),
        }
    }
}
impl Default for UInt {
    fn default() -> UInt {
        UInt::U8(u8::default())
    }
}
impl From<Boolean> for UInt {
    fn from(b: Boolean) -> UInt {
        match b {
            Boolean(true) => UInt::U8(1),
            Boolean(false) => UInt::U8(0),
        }
    }
}
impl From<u8> for UInt {
    fn from(u: u8) -> UInt {
        UInt::U8(u)
    }
}
impl From<u16> for UInt {
    fn from(u: u16) -> UInt {
        UInt::U16(u)
    }
}
impl From<u32> for UInt {
    fn from(u: u32) -> UInt {
        UInt::U32(u)
    }
}
impl From<u64> for UInt {
    fn from(u: u64) -> UInt {
        UInt::U64(u)
    }
}
impl From<UInt> for u64 {
    fn from(u: UInt) -> u64 {
        match u {
            UInt::U64(u) => u,
            UInt::U32(u) => u as u64,
            UInt::U16(u) => u as u64,
            UInt::U8(u) => u as u64,
        }
    }
}
impl From<UInt> for usize {
    fn from(u: UInt) -> usize {
        match u {
            UInt::U64(u) => u as usize,
            UInt::U32(u) => u as usize,
            UInt::U16(u) => u as usize,
            UInt::U8(u) => u as usize,
        }
    }
}
impl FromStr for UInt {
    type Err = Error;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        u64::from_str(s).map(Self::from).map_err(Error::new)
    }
}
fmt_debug!(UInt);
impl fmt::Display for UInt {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            UInt::U8(u) => fmt::Display::fmt(u, f),
            UInt::U16(u) => fmt::Display::fmt(u, f),
            UInt::U32(u) => fmt::Display::fmt(u, f),
            UInt::U64(u) => fmt::Display::fmt(u, f),
        }
    }
}