package number // NumberType représente le type d’un nombre. type NumberType uint const ( Integer NumberType = iota Scientific Decimal Fraction ) // Number représente un nombre. type Number struct { atom tpe NumberType base uint } // Undefined retourne un nombre indéfini, signé : // - si sign < 0, retourne -∞ // - si sign > 0, retourne +∞ // - sinon, retourne NaN func Undefined(sign int) Number { return Number{ base: 10, tpe: Integer, atom: undefined(sign), } } // Nan retourne NaN. func Nan() Number { return Undefined(0) } // Inf retourne +∞. func Inf() Number { return Undefined(1) } // NegInf retourne -∞. func NegInf() Number { return Undefined(-1) } // Int retourne un nombre à partir d’un entier, et éventuellement une base. func Int[N integer](n N, base ...uint) Number { return Number{ base: formatBase(base...), tpe: Integer, atom: entire(n, 1), } } // Zero retourne le nombre 0. func Zero(base ...uint) Number { return Int(0, base...) } // One retourne le nombre 1. func One(base ...uint) Number { return Int(1, base...) } // Two retourne le nombre 2. func Two(base ...uint) Number { return Int(2, base...) } // Float retourne un nombre à partir d’un flottant, et éventuellement, une base. func Float[N ~float32 | ~float64](n N, base ...uint) Number { return Number{ base: formatBase(base...), tpe: Decimal, atom: decimal(n, 1), } } // Frac retourne un nombre à partir du numérateur, du dénominateur, et éventuellement, une base. func Frac[N integer](num N, denom N, base ...uint) Number { return Number{ base: formatBase(base...), tpe: Fraction, atom: frac(num, denom, 1), } } func (n Number) set(a atom, format ...bool) Number { out := Number{ atom: a, tpe: n.tpe, base: n.base, } return out.format(format...) } func (n *Number) format(formatAtom ...bool) Number { if len(formatAtom) > 0 && formatAtom[0] { n.atom.format() } n.base = formatBase(n.base) if !n.IsDefined() { n.base = 10 n.tpe = Integer } else if n.tpe == Integer && !n.isInt() { n.setInt() } return *n } func (n Number) clone(format ...bool) Number { out := Number{ atom: n.atom.clone(format...), tpe: n.tpe, base: n.base, } if len(format) > 0 && format[0] { return out.format() } return out } // Type retourne le type de nombre. func (n Number) Type() NumberType { return n.tpe } // ToType convertit le nombre au type donné. func (n Number) ToType(t NumberType) Number { out := n.clone() switch t { case Integer, Decimal, Fraction, Scientific: out.tpe = t default: out.tpe = Decimal } return out.format(true) } // Base retourne la base du nombre. func (n Number) Base() uint { return n.base } // ToBase convertit le nombre dans la base donnée. func (n Number) ToBase(base uint) Number { out := n.clone(true) out.base = formatBase(base) return out } // Neg retourne -n. func (n Number) Neg() Number { return n.set(n.neg()) } // Abs retourne |n|. func (n Number) Abs() Number { return n.set(n.abs()) } // IsInt retourne vrai si le nombre est entier. func (n Number) IsInt() bool { return n.isInt() } // Num retourne le numérateur. func (n Number) Num() Number { out := Number{ atom: n.num(), base: n.base, tpe: Integer, } return out.format() } // Denom retourne le dénominateur. func (n Number) Denom() Number { out := Number{ atom: n.denom(), base: n.base, tpe: Integer, } return out.format() } // Num retourne le numérateur et le dénominateur. func (n Number) NumDenom() (Number, Number) { return n.Num(), n.Denom() } // Cmp retourne : // - -1 si n1 < n2 // - +1 si n1 > n2 // - 0 sinon. func (n1 Number) Cmp(n2 Number) int { return n1.cmp(n2.atom) } func (n1 Number) Eq(n2 Number) bool { return n1.Cmp(n2) == 0 } func (n1 Number) Ne(n2 Number) bool { return n1.Cmp(n2) != 0 } func (n1 Number) Gt(n2 Number) bool { return n1.Cmp(n2) > 0 } func (n1 Number) Lt(n2 Number) bool { return n1.Cmp(n2) < 0 } func (n1 Number) Ge(n2 Number) bool { return n1.Cmp(n2) >= 0 } func (n1 Number) Le(n2 Number) bool { return n1.Cmp(n2) <= 0 } // Add retourne n1 + n2. func (n1 Number) Add(n2 Number) Number { out := Number{ base: n1.base, tpe: max(n1.tpe, n2.tpe), atom: n1.add(n2.atom), } return out.format() } // Sub retourne n1 - n2. func (n1 Number) Sub(n2 Number) Number { out := Number{ base: n1.base, tpe: max(n1.tpe, n2.tpe), atom: n1.sub(n2.atom), } return out.format() } // Inc retourne n + 1. func (n Number) Inc() Number { return n.Add(One()) } // Dec retourne n − 1. func (n Number) Dec() Number { return n.Sub(One()) } // Mul retourne n1 × n2. func (n1 Number) Mul(n2 Number) Number { out := Number{ base: n1.base, tpe: max(n1.tpe, n2.tpe), atom: n1.mul(n2.atom), } return out.format() } // Div retourne n1 ÷ n2 (division exacte). func (n1 Number) Div(n2 Number) Number { out := Number{ base: n1.base, tpe: max(n1.tpe, n2.tpe), atom: n1.div(n2.atom), } return out.format() } // Quo retourne n1 ÷ n2 (division entière). func (n1 Number) Quo(n2 Number) Number { out := Number{ base: n1.base, tpe: Integer, atom: n1.quo(n2.atom), } return out.format() } // Rem retourne n1 % n2. func (n1 Number) Rem(n2 Number) Number { out := Number{ base: n1.base, tpe: max(n1.tpe, n2.tpe), atom: n1.rem(n2.atom), } return out.format() } // QuoRem retourne la division entière et le reste. func (n1 Number) QuoRem(n2 Number) (q, r Number) { q.base, r.base = n1.base, n1.base q.tpe, r.tpe = Integer, max(n1.tpe, n2.tpe) q.atom, r.atom = n1.quoRem(n2.atom) return q.format(), r.format() } // Inv retourne 1 ÷ n. func (n Number) Inv() Number { t := n.tpe if t == Integer { t = Fraction } out := Number{ tpe: t, base: n.base, atom: n.inv(), } if n.tpe == Integer && out.IsInt() { out.tpe = Integer } return out.format() } // Fact retourne n!. func (n Number) Fact() Number { switch { case n.IsInf(): return Inf() case !n.IsInt() || n.IsNeg(): return Nan() default: out := One(n.base) for e := Two(); e.Le(n); e = e.Inc() { out.Mul(e) } return out } } // Lsh retourne n1 << n2. func (n1 Number) Lsh(n2 Number) Number { if n2.IsNeg() { return n1.Rsh(n2.Abs()) } if n, ok := n2.toInt64(); ok && n >= 0 { return n1.set(n1.lsh(uint(n)), true) } return Nan() } // Rsh retourne n1 << n2. func (n1 Number) Rsh(n2 Number) Number { if n2.IsNeg() { return n1.Lsh(n2.Abs()) } if n, ok := n2.toInt64(); ok && n >= 0 { return n1.set(n1.rsh(uint(n)), true) } return Nan() } // Len retourne le nombre de chiffre d’un nombre entier (ou -1 s’il n’est pas entier) func (n Number) Len() int { return n.len(n.base) } // Bit retourne le chiffre à la position n2 (en partant de 0) // d’un nombre entier (ou -1 si n1 ou n2 n’est pas entier). func (n1 Number) Bit(n2 Number) int { if n, ok := n2.toInt64(); ok && n >= 0 { return n1.bit(uint64(n), n1.base) } return -1 } // Pow retourne n1 ^ n2. func (n1 Number) Pow(n2 Number) Number { if !n2.IsDefined() { return Nan() } p, s := n2.NumDenom() if !p.isInt64() || !s.isInt64() { n2 = n2.set(n2.optimize(pow(n2.base, FloatingPrecision))) p, s = n2.NumDenom() if !p.isInt64() || !s.isInt64() { return Nan() } } if p0, ok := p.toInt64(); ok { if s0, ok := s.toInt64(); ok && s0 > 0 { inv := p0 < 0 if inv { p0 = -p0 } out := Number{ tpe: n1.tpe, base: n1.base, atom: n1.pow(uint64(p0)).sqrtn(uint64(s0), n1.base), } if inv { out.atom = out.atom.inv() } if n1.tpe == Integer && !out.isInt() { out.tpe = Decimal } return out.format() } } return Nan() } // Sqrtn retourne la racine n2ième de n1. func (n1 Number) Sqrtn(n2 Number) Number { if n, ok := n2.toInt64(); ok && n > 0 { out := Number{ tpe: n1.tpe, base: n1.base, atom: n1.sqrtn(uint64(n), n1.base), } if n1.tpe == Integer && !out.isInt() { out.tpe = Decimal } return out.format() } return Nan() } // Sqrt retourne la racine carrée de n. func (n Number) Sqrt() Number { return n.Sqrtn(Int(2)) }