gob/number/number.go

427 lines
7.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package number
// NumberType représente le type dun 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 dun 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 dun 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 dun nombre entier (ou -1 sil nest pas entier)
func (n Number) Len() int {
return n.len(n.base)
}
// Bit retourne le chiffre à la position n2 (en partant de 0)
// dun nombre entier (ou -1 si n1 ou n2 nest 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))
}