gob/number/number.go

767 lines
15 KiB
Go
Raw Normal View History

2024-02-17 18:13:24 +00:00
package number
2024-02-21 09:12:59 +00:00
import (
"fmt"
"math/big"
"strings"
"gitea.zaclys.com/bvaudour/gob/option"
)
2024-02-17 18:13:24 +00:00
// 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 {
2024-02-21 09:12:59 +00:00
number rat
sign int
tpe NumberType
base uint
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
func (n *Number) get() (r *big.Rat, ok bool) {
return n.number.Get()
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
func (n *Number) rat() (r *big.Rat, ok bool) {
2024-02-21 13:23:18 +00:00
if r, ok = n.get(); ok {
2024-02-21 09:12:59 +00:00
r = new(big.Rat).Set(r)
if n.Sign() < 0 {
2024-02-21 13:23:18 +00:00
r.Neg(r)
2024-02-21 09:12:59 +00:00
}
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return
}
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
func (n *Number) format() Number {
n.base, n.sign, n.tpe = formatBase(n.base), signOf(n.sign), min(n.tpe, Fraction)
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
if nb, ok := n.get(); ok {
n.sign *= nb.Sign()
if n.tpe == Integer && !nb.IsInt() {
num, denom := nb.Num(), nb.Denom()
nb.SetInt(num.Quo(num, denom))
}
nb.Abs(nb)
} else {
n.tpe = Integer
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return *n
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
func (n Number) set(r *big.Rat, tpe NumberType, sign ...int) Number {
s := 1
if len(sign) > 0 {
s = sign[0]
}
out := Number{
base: n.Base(),
tpe: tpe,
sign: s,
number: option.Some(r),
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return out.format()
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// Clone crée une copie profonde du nombre.
func (n Number) Clone() Number {
2024-02-17 18:13:24 +00:00
out := Number{
2024-02-21 09:12:59 +00:00
sign: n.sign,
2024-02-17 18:13:24 +00:00
tpe: n.tpe,
base: n.base,
}
2024-02-21 09:12:59 +00:00
if nb, ok := n.get(); ok {
out.number = option.Some(new(big.Rat).Set(nb))
}
return out
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// Base retourne la base utilisée pour laffichage du nombre.
func (n Number) Base() uint { return n.base }
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
// Type retourne le type de nombre (entier, décimal, fraction ou scientifique).
func (n Number) Type() NumberType { return n.tpe }
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
// Sign retourne :
// - 0 si n = 0 ou NaN
// - 1 si n > 0
// - -1 si n < 0
func (n Number) Sign() int { return n.sign }
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
// ToBase convertit le nombre dans la base donnée.
func (n Number) ToBase(base uint) Number {
out := n.Clone()
out.base = formatBase(base)
return out
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// ToType convertit le nombre dans le type donné. La base est conservée, sauf si une base est fournie.
func (n Number) ToType(tpe NumberType, base ...uint) Number {
out := n.Clone()
out.tpe = tpe
out = out.format()
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
if len(base) > 0 {
return out.ToBase(base[0])
2024-02-17 18:13:24 +00:00
}
return out
}
2024-02-21 09:12:59 +00:00
// IsDefined retourne vrai si le nombre est défini.
func (n Number) IsDefined() bool { return n.number.IsDefined() }
// IsInt retourne vrai si le nombre est entier.
func (n Number) IsInt() bool {
nb, ok := n.get()
return ok && nb.IsInt()
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// IsInt64 retourne vrai si le nombre est convertible en int64.
func (n Number) IsInt64() bool {
nb, ok := n.get()
return ok && nb.IsInt() && nb.Num().IsInt64()
}
// IsUint64 retourne vrai si le nombre est convertible en uint64.
func (n Number) IsUint64() bool {
nb, ok := n.get()
return ok && nb.IsInt() && nb.Num().IsUint64()
}
// Is retourne vrai si n = i.
func (n Number) Is(i int64) bool {
if nb, ok := n.rat(); ok && nb.IsInt() {
2024-02-21 09:12:59 +00:00
num := nb.Num()
return num.IsInt64() && num.Int64() == i
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return false
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// IsUint retourne vrai si n = u.
func (n Number) IsUint(u uint64) bool {
if nb, ok := n.rat(); ok && nb.IsInt() {
2024-02-21 09:12:59 +00:00
num := nb.Num()
return num.IsUint64() && num.Uint64() == u
}
return false
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// IsFloat retourne vrai si n = f.
func (n Number) IsFloat(f float64) bool {
if nb, ok := n.rat(); ok {
2024-02-21 09:12:59 +00:00
nf, ok := nb.Float64()
return nf == f && ok
}
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
return false
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// IsNeg retourne vrai si n < 0.
func (n Number) IsNeg() bool { return n.Sign() < 0 }
// IsPos retourne vrai si n > 0.
func (n Number) IsPos() bool { return !n.IsNeg() }
// IsZero retourne vrai si n = 0.
func (n Number) IsZero() bool { return n.IsDefined() && n.Sign() == 0 }
// IsInf retourne vrai si n = +∞.
func (n Number) IsInf() bool { return !n.IsDefined() && n.Sign() > 0 }
// IsNegInf retourne vrai si n = -∞.
func (n Number) IsNegInf() bool { return !n.IsDefined() && n.Sign() < 0 }
// IsNan retourne vrai si n = NaN.
func (n Number) IsNan() bool { return !n.IsDefined() && n.Sign() == 0 }
// ToInt64 retourne le nombre converti en int64, et vrai si la conversion a réussi.
func (n Number) ToInt64() (i int64, ok bool) {
var nb *big.Rat
if nb, ok = n.rat(); ok {
2024-02-21 09:12:59 +00:00
if ok = nb.IsInt(); ok {
num := nb.Num()
if ok = num.IsInt64(); ok {
i = num.Int64()
}
}
}
return
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// ToUint64 retourne le nombre converti en uint64, et vrai si la conversion a réussi.
func (n Number) ToUint64() (u uint64, ok bool) {
var nb *big.Rat
if nb, ok = n.rat(); ok {
2024-02-21 09:12:59 +00:00
if ok = nb.IsInt(); ok {
num := nb.Num()
if ok = num.IsUint64(); ok {
u = num.Uint64()
}
}
}
return
2024-02-17 18:13:24 +00:00
}
// ToFloat retourne le nombre converti en flottant, et vrai si la conversion a réussi et est exacte.
func (n Number) ToFloat() (f float64, ok bool) {
var nb *big.Rat
if nb, ok = n.rat(); ok {
f, ok = nb.Float64()
}
return
}
2024-02-21 09:12:59 +00:00
// IsEven retourne vrai si n est entier et pair.
func (n Number) IsEven() bool {
if nb, ok := n.get(); ok {
return nb.IsInt() && nb.Num().Bit(0) == 0
}
return false
}
// IsOdd retourne vrai si n est entier et impair.
func (n Number) IsOdd() bool {
if nb, ok := n.get(); ok {
return nb.IsInt() && nb.Num().Bit(0) != 0
}
return false
2024-02-17 18:13:24 +00:00
}
// Num retourne le numérateur.
func (n Number) Num() Number {
2024-02-21 09:12:59 +00:00
if n.Sign() == 0 {
return IntOf(0, n.Base())
} else if nb, ok := n.rat(); ok {
return IntOf0(nb.Num(), n.Base())
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return IntOf(n.Sign(), n.Base())
2024-02-17 18:13:24 +00:00
}
// Denom retourne le dénominateur.
func (n Number) Denom() Number {
2024-02-21 09:12:59 +00:00
if nb, ok := n.get(); ok {
return IntOf0(nb.Denom(), n.Base())
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return IntOf(0, n.Base())
}
// NumDenom retourne le numérateur et le dénominateur.
func (n Number) NumDenom() (Number, Number) { return n.Num(), n.Denom() }
// Neg retourne -n.
func (n Number) Neg() Number {
out := n.Clone()
out.sign = -out.sign
return out
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// Abs retourne |n|.
func (n Number) Abs() Number {
out := n.Clone()
out.sign = abs(out.sign)
return out
2024-02-17 18:13:24 +00:00
}
// Cmp retourne :
2024-02-21 09:12:59 +00:00
// - 1 si n1 > n2
2024-02-17 18:13:24 +00:00
// - -1 si n1 < n2
2024-02-21 09:12:59 +00:00
// - 0 si n1 = n2
// - 2 ou -2 si les nombres ne sont pas comparables (ie. n1 = NaN ou n2 = NaN)
2024-02-17 18:13:24 +00:00
func (n1 Number) Cmp(n2 Number) int {
2024-02-21 09:12:59 +00:00
if n1.IsNan() {
if n2.IsNan() {
return 0
}
return -2
} else if n2.IsNan() {
return 2
} else if nb1, ok := n1.rat(); ok {
if nb2, ok := n2.rat(); ok {
return nb1.Cmp(nb2)
}
return -n2.Sign()
} else if n2.IsDefined() {
return n1.Sign()
}
return compare(n1.Sign(), n2.Sign())
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// Eq retourne vrai si n1 = n2.
2024-02-17 18:13:24 +00:00
func (n1 Number) Eq(n2 Number) bool { return n1.Cmp(n2) == 0 }
2024-02-21 09:12:59 +00:00
// Ne retourne vrai si n1 ≠ n2.
2024-02-17 18:13:24 +00:00
func (n1 Number) Ne(n2 Number) bool { return n1.Cmp(n2) != 0 }
2024-02-21 09:12:59 +00:00
// Gt retourne vrai si n1 > n2.
2024-02-17 18:13:24 +00:00
func (n1 Number) Gt(n2 Number) bool { return n1.Cmp(n2) > 0 }
2024-02-21 09:12:59 +00:00
// Lt retourne vrai si n1 < n2.
2024-02-17 18:13:24 +00:00
func (n1 Number) Lt(n2 Number) bool { return n1.Cmp(n2) < 0 }
2024-02-21 09:12:59 +00:00
// Ge retourne vrai si n1 ≥ n2.
2024-02-17 18:13:24 +00:00
func (n1 Number) Ge(n2 Number) bool { return n1.Cmp(n2) >= 0 }
2024-02-21 09:12:59 +00:00
// Le retourne vrai si n1 ≤ n2.
2024-02-17 18:13:24 +00:00
func (n1 Number) Le(n2 Number) bool { return n1.Cmp(n2) <= 0 }
// Add retourne n1 + n2.
func (n1 Number) Add(n2 Number) Number {
2024-02-21 09:12:59 +00:00
if r1, ok := n1.rat(); ok {
if r2, ok := n2.rat(); ok {
return n1.set(new(big.Rat).Add(r1, r2), max(n1.Type(), n2.Type()))
}
return n2.Clone()
} else if n2.IsDefined() || n1.Sign() == n2.Sign() {
return Undefined(n1.Sign())
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return Nan()
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// Sub retourne n1 n2.
func (n1 Number) Sub(n2 Number) Number { return n1.Add(n2.Neg()) }
2024-02-17 18:13:24 +00:00
// Inc retourne n + 1.
2024-02-21 09:12:59 +00:00
func (n Number) Inc() Number { return n.Add(One()) }
2024-02-17 18:13:24 +00:00
// Dec retourne n 1.
2024-02-21 09:12:59 +00:00
func (n Number) Dec() Number { return n.Sub(One()) }
2024-02-17 18:13:24 +00:00
// Mul retourne n1 × n2.
func (n1 Number) Mul(n2 Number) Number {
2024-02-21 09:12:59 +00:00
s := n1.Sign() * n2.Sign()
if nb1, ok := n1.get(); ok {
if nb2, ok := n2.get(); ok {
return n1.set(new(big.Rat).Mul(nb1, nb2), max(n1.Type(), n2.Type()), s)
}
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return Undefined(s)
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// Div retourne n1 / n2 (division exacte).
2024-02-17 18:13:24 +00:00
func (n1 Number) Div(n2 Number) Number {
2024-02-21 09:12:59 +00:00
s := n1.Sign() * n2.Sign()
if nb1, ok := n1.get(); ok {
if nb2, ok := n2.get(); ok {
if nb2.IsInt() && nb2.Num().IsInt64() && nb2.Num().Int64() == 0 {
return Nan()
}
t := max(n1.Type(), n2.Type())
result := new(big.Rat).Quo(nb1, nb2)
if t == Integer && !result.IsInt() {
t = Decimal
}
return n1.set(result, t, s)
}
return Undefined(s)
} else if n2.IsDefined() {
return Undefined(s)
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return Nan()
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// inv retourne 1/n.
func (n Number) Inv() Number { return IntOf(1, n.Base()).Div(n) }
2024-02-17 18:13:24 +00:00
// Quo retourne n1 ÷ n2 (division entière).
func (n1 Number) Quo(n2 Number) Number {
2024-02-21 09:12:59 +00:00
if nb1, ok := n1.rat(); ok {
if nb2, ok := n2.rat(); ok {
if nb2.IsInt() && nb2.Num().IsInt64() && nb2.Num().Int64() == 0 {
return Nan()
}
q := new(big.Rat).Quo(nb1, nb2)
return IntOf0(new(big.Int).Quo(q.Num(), q.Denom()), n1.Base())
}
return Undefined(n1.Sign() * n2.Sign())
} else if n2.IsDefined() {
return Undefined(n1.Sign() * n2.Sign())
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return Nan()
}
// QuoRem retourne q et r tels que n1 = q×n2 + r où q est entier.
func (n1 Number) QuoRem(n2 Number) (q, r Number) {
q = n1.Quo(n2)
r = n1.Sub(n2.Mul(q))
return
2024-02-17 18:13:24 +00:00
}
// Rem retourne n1 % n2.
func (n1 Number) Rem(n2 Number) Number {
2024-02-21 09:12:59 +00:00
_, r := n1.QuoRem(n2)
return r
}
func (n Number) pow(p int64) (out Number) {
inv := p < 0
p = abs(p)
switch {
case p == 0:
if n.IsNan() {
return Nan()
}
return IntOf(1, n.Base())
case p == 1:
out = n.Clone()
case p == 2:
out = n.Square()
case p&1 == 0:
out = n.Square().pow(p >> 1)
default:
out = n.Square().pow(p >> 1).Mul(n)
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
if inv {
out = out.Inv()
}
return
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
func (n Number) optimize(precision Number) (out Number) {
out = n
if n.Denom().Gt(precision) {
out = n.Num().Mul(precision).Quo(n.Denom()).Div(precision).ToType(n.Type())
}
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
return
}
func (n Number) sqrt(s uint64) (out Number) {
if n.IsNan() || s < 2 || (s&1 == 0 && n.IsNeg()) {
return Nan()
} else if !n.IsDefined() {
return n.Clone()
}
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
s0 := IntOf(s)
s1 := s0.Dec()
precision := pow[uint, uint](n.Base())
deltaMax := precision.Inv()
heron := func(partial Number) Number {
return ((partial.Mul(s1)).Add(n.Div(partial.pow(int64(s - 1))))).Div(s0).optimize(precision)
}
out = n
for {
tmp := heron(out)
if out.Eq(tmp) {
break
} else if (tmp.Sub(out)).Abs().Lt(deltaMax) {
out = tmp
break
}
out = tmp
}
if n.Type() == Integer && out.IsInt() {
out = out.ToType(Integer)
}
return
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// Pow retourne n1 ^ n2.
func (n1 Number) Pow(n2 Number) Number {
if !n2.IsDefined() {
return Nan()
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
p2, s2 := n2.NumDenom()
p, pok := p2.ToInt64()
s, sok := s2.ToUint64()
if !pok || !sok {
return Nan()
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
out := n1.pow(p)
if s > 1 {
out = out.sqrt(s)
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return out
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// Square retourne n².
func (n Number) Square() Number { return n.Mul(n) }
// Sqrtn retourne la racine n2ième de n1.
func (n1 Number) Sqrtn(n2 Number) Number {
s, ok := n2.ToUint64()
if !ok {
2024-02-17 18:13:24 +00:00
return Nan()
2024-02-21 09:12:59 +00:00
}
return n1.sqrt(s)
}
// Sqrt retourne la racine carrée de n.
func (n Number) Sqrt() Number { return n.Sqrtn(Two()) }
func (n Number) lsh(s uint64) Number {
if nb, ok := n.rat(); ok {
num, denom := nb.Num(), nb.Denom()
return FracOf0(new(big.Int).Lsh(num, uint(s)), denom, n.Base()).ToType(n.Type())
}
return n.Clone()
}
func (n Number) rsh(s uint64) Number {
if nb, ok := n.rat(); ok {
t := n.Type()
if t == Integer {
return IntOf0(new(big.Int).Rsh(nb.Num(), uint(s)), n.Base())
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return FracOf0(nb.Num(), new(big.Int).Lsh(nb.Denom(), uint(s)), n.Base()).ToType(t)
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return n.Clone()
2024-02-17 18:13:24 +00:00
}
// Lsh retourne n1 << n2.
func (n1 Number) Lsh(n2 Number) Number {
2024-02-21 09:12:59 +00:00
if s, ok := n2.ToUint64(); ok {
return n1.lsh(s)
2024-02-17 18:13:24 +00:00
}
return Nan()
}
2024-02-21 09:12:59 +00:00
// Rsh retourne n1 >> n2.
2024-02-17 18:13:24 +00:00
func (n1 Number) Rsh(n2 Number) Number {
2024-02-21 09:12:59 +00:00
if s, ok := n2.ToUint64(); ok {
return n1.rsh(s)
2024-02-17 18:13:24 +00:00
}
return Nan()
}
2024-02-21 09:12:59 +00:00
// Len retourne le nombre de chiffre de n si n est entier ou -1 sinon.
2024-02-17 18:13:24 +00:00
func (n Number) Len() int {
2024-02-21 09:12:59 +00:00
if nb, ok := n.get(); ok {
if !nb.IsInt() {
return -1
}
num := nb.Num()
if num.IsInt64() && num.Int64() == 0 {
return 1
}
s := num.Text(int(n.Base()))
return len(s)
}
return -1
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// Bit retourne le n2ième chiffre de n1 si n est entier, ou -1 sinon.
// Le n° de bit commence à 0 à partir de la droite.
2024-02-17 18:13:24 +00:00
func (n1 Number) Bit(n2 Number) int {
2024-02-21 09:12:59 +00:00
b, ok := n2.ToUint64()
if !ok || !n1.IsInt() {
return -1
}
out := n1
if b > 0 {
out = n1.Quo(pow(n1.Base(), b))
}
out = out.Rem(IntOf(n1.Base()))
if result, ok := out.ToInt64(); ok {
return int(result)
2024-02-17 18:13:24 +00:00
}
return -1
}
2024-02-21 09:12:59 +00:00
// Fact retourne n!.
func (n Number) Fact() Number {
switch {
case n.IsInf():
return Inf()
case !n.IsInt() || n.IsNeg():
2024-02-17 18:13:24 +00:00
return Nan()
2024-02-21 09:12:59 +00:00
default:
out := One(n.Base())
for e := Two(); e.Le(n); e = e.Inc() {
out = out.Mul(e)
2024-02-21 09:12:59 +00:00
}
return out
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
}
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
func (n Number) text() string {
if nb, ok := n.get(); ok {
return nb.Num().Text(int(n.Base()))
}
return ""
}
func (n Number) undefinedString() string {
switch n.Sign() {
case -1:
return "-∞"
case +1:
return "+∞"
default:
return "NaN"
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
}
func (n Number) intString() (out string) {
out = n.text()
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
if n.Sign() < 0 {
out = fmt.Sprintf("-%s", out)
}
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
if base := n.Base(); base != 10 {
out = fmt.Sprintf("(%d)%s", base, out)
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
return
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
func (n Number) fracString() string {
num, denom := n.NumDenom()
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
return fmt.Sprintf("%s/%s", num.intString(), denom.intString())
}
func (n Number) decString() (out string) {
base, sign := n.Base(), n.Sign()
num, denom := n.NumDenom()
precision := pow[uint, uint](base)
num = num.Abs().Mul(precision)
q := num.Quo(denom)
out = "0"
if num.Ge(denom) {
out = q.text()
}
p := int(FloatingPrecision)
if len(out) < p {
out = fmt.Sprintf("%s%s", strings.Repeat("0", p), out)
}
dot := len(out) - p
out = fmt.Sprintf("%s.%s", out[:dot], out[dot:])
for out[0] == '0' {
out = out[1:]
}
2024-02-21 09:12:59 +00:00
if !FixedPrecision {
l := len(out) - 1
for out[l] == '0' {
out, l = out[:l], l-1
2024-02-17 18:13:24 +00:00
}
}
if out == "." {
out = "0."
2024-02-21 09:12:59 +00:00
}
2024-02-17 18:13:24 +00:00
2024-02-21 09:12:59 +00:00
if sign < 0 {
out = fmt.Sprintf("-%s", out)
} else if q.IsZero() && sign > 0 {
out = fmt.Sprintf("+%s", out)
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
if base != 10 {
out = fmt.Sprintf("(%d)%s", base, out)
}
return
}
func (n Number) sciString() (out string) {
base, sign := n.Base(), n.Sign()
var exponent int
tmp := n
if !n.IsZero() {
num, denom := n.Abs().NumDenom()
nl, dl := num.Len(), denom.Len()
exponent = nl - dl
nBase := IntOf(base)
if exponent > 0 {
denom = denom.Mul(nBase.pow(int64(exponent)))
} else if exponent < 0 {
num = num.Mul(nBase.pow(int64(-exponent)))
}
if num.Lt(denom) {
exponent--
num = num.Mul(nBase)
}
tmp = num.Div(denom)
}
if sign < 0 {
tmp = tmp.Neg()
}
signExponent := ""
if exponent > 0 {
signExponent = "+"
}
out = tmp.decString()
if base == 10 {
return fmt.Sprintf("%sE%s%d", out, signExponent, exponent)
}
return fmt.Sprintf("%s×%d^%s%d", out, base, signExponent, exponent)
2024-02-17 18:13:24 +00:00
}
2024-02-21 09:12:59 +00:00
// String retourne la représentation du nombre sous forme de chaîne de caractères.
func (n Number) String() string {
if !n.IsDefined() {
return n.undefinedString()
}
switch n.Type() {
case Integer:
return n.intString()
case Fraction:
return n.fracString()
case Scientific:
return n.sciString()
default:
return n.decString()
}
2024-02-17 18:13:24 +00:00
}