Compare commits

..

No commits in common. "5b437644bd67116d6b4360776bc2ea964270bcc3" and "c4029042e01957f38567ca887e9146a3e28c4992" have entirely different histories.

8 changed files with 1210 additions and 917 deletions

502
number/atom.go Normal file
View File

@ -0,0 +1,502 @@
package number
import (
"math/big"
"gitea.zaclys.com/bvaudour/gob/option"
)
type atom struct {
number option.Option[*big.Rat]
sign int
}
func undefined[S integer | float](sign S) atom {
out := atom{
sign: signOf(sign),
}
return out.format()
}
func rational[S integer | float](rat *big.Rat, sign ...S) atom {
s := 1
if len(sign) > 0 {
s = signOf(sign[0])
}
out := atom{
number: option.Some(rat),
sign: s,
}
return out.format()
}
func frac0[S integer | float](num, denom *big.Int, sign ...S) atom {
if denom.IsInt64() && denom.Int64() == 0 {
s := num.Sign()
if len(sign) > 0 {
s *= signOf(sign[0])
}
return undefined(s)
}
rat := new(big.Rat).SetFrac(num, denom)
return rational(rat, sign...)
}
func frac[N integer | float, S integer | float](num, denom N, sign ...S) atom {
if denom == 0 {
s := signOf(num)
if len(sign) > 0 {
s *= signOf(sign[0])
}
return undefined(s)
}
rat := new(big.Rat).SetFrac64(int64(num), int64(denom))
return rational(rat, sign...)
}
func entire0[S integer | float](n *big.Int, sign ...S) atom {
rat := new(big.Rat).SetInt(n)
return rational(rat, sign...)
}
func entire[N integer | float, S integer | float](n N, sign ...S) atom {
rat := new(big.Rat).SetInt64(int64(n))
return rational(rat, sign...)
}
func decimal[N integer | float, S integer | float](n N, sign ...S) atom {
rat := new(big.Rat).SetFloat64(float64(n))
return rational(rat, sign...)
}
func pow[B integer | float, P integer | float](base B, precision ...P) atom {
p := FloatingPrecision
if len(precision) > 0 {
p = uint64(precision[0])
}
a := entire(formatBase(base), 1)
return a.pow(p)
}
func (a atom) get() (*big.Rat, bool) {
return a.number.Get()
}
func (a *atom) format() atom {
if nb, ok := a.get(); ok {
a.sign *= nb.Sign()
nb.Abs(nb)
}
a.sign = signOf(a.sign)
return *a
}
func (a atom) clone(format ...bool) atom {
out := atom{
sign: a.sign,
}
if nb, ok := a.get(); ok {
out.number = option.Some(new(big.Rat).Set(nb))
}
if len(format) > 0 && format[0] {
return out.format()
}
return out
}
func (a atom) rat() (nb *big.Rat, ok bool) {
if nb, ok = a.get(); ok {
nb = new(big.Rat).Set(nb)
if a.sign < 0 {
nb.Neg(nb)
} else if a.sign == 0 {
nb.SetInt64(0)
}
}
return
}
func (a atom) Sign() int {
return a.sign
}
func (a atom) IsNeg() bool {
return a.Sign() < 0
}
func (a atom) IsPos() bool {
return !a.IsNeg()
}
func (a atom) IsZero() bool {
return a.Is(0)
}
func (a atom) neg() atom {
out := a.clone()
out.sign = -out.sign
return out.format()
}
func (a atom) abs() atom {
out := a.clone()
if out.sign < 0 {
out.sign = -out.sign
}
return out.format()
}
func (a atom) IsDefined() bool {
return a.number.IsDefined()
}
func (a atom) IsInf() bool {
return !a.IsDefined() && a.Sign() > 0
}
func (a atom) IsNegInf() bool {
return !a.IsDefined() && a.Sign() < 0
}
func (a atom) IsNan() bool {
return !a.IsDefined() && a.Sign() == 0
}
func (a atom) Is(i int64) bool {
if nb, ok := a.get(); ok {
return nb.IsInt() && nb.Num().Int64()*int64(a.Sign()) == i
}
return false
}
func (a atom) IsFloat(f float64) bool {
if nb, ok := a.get(); ok {
e, ok := nb.Float64()
return ok && e*float64(a.Sign()) == f
}
return false
}
func (a atom) isInt() bool {
if nb, ok := a.get(); ok {
return nb.IsInt()
}
return false
}
func (a atom) isInt64() bool {
if nb, ok := a.get(); ok {
return nb.IsInt() && nb.Num().IsInt64()
}
return false
}
func (a atom) toInt64() (n int64, ok bool) {
var nb *big.Rat
if nb, ok = a.get(); ok {
if nb.IsInt() {
if num := nb.Num(); num.IsInt64() {
n = num.Int64()
}
}
}
return
}
func (a *atom) setInt() atom {
if nb, ok := a.get(); ok {
nb.SetInt(new(big.Int).Quo(nb.Num(), nb.Denom()))
}
return a.format()
}
func (a atom) num() atom {
if a.Sign() == 0 {
return entire(0, 0)
} else if nb, ok := a.get(); ok {
return entire0(nb.Num(), a.Sign())
}
return entire(a.Sign(), 1)
}
func (a atom) denom() atom {
if nb, ok := a.get(); ok {
return entire0(nb.Denom(), 1)
}
return entire(0, 0)
}
func (a1 atom) cmp(a2 atom) int {
if a1.IsNan() {
if a2.IsNan() {
return 0
}
return -2
} else if a2.IsNan() {
return 2
} else if nb1, ok := a1.rat(); ok {
if nb2, ok := a2.rat(); ok {
return nb1.Cmp(nb2)
}
return -a2.Sign()
} else if a2.IsDefined() {
return a1.Sign()
}
return compare(a1.Sign(), a2.Sign())
}
func (a1 atom) add(a2 atom) atom {
if r1, ok := a1.rat(); ok {
if r2, ok := a2.rat(); ok {
return rational(new(big.Rat).Add(r1, r2), 1)
}
return a2.clone()
} else if a2.IsDefined() || a1.Sign() == a2.Sign() {
return undefined(a1.Sign())
}
return undefined(0)
}
func (a1 atom) sub(a2 atom) atom {
return a1.add(a2.neg())
}
func (a atom) inc() atom {
return a.add(entire(1, 1))
}
func (a atom) dec() atom {
return a.sub(entire(1, 1))
}
func (a1 atom) mul(a2 atom) atom {
s := a1.Sign() * a2.Sign()
if nb1, ok := a1.get(); ok {
if nb2, ok := a2.get(); ok {
return rational(new(big.Rat).Mul(nb1, nb2), s)
}
}
return undefined(s)
}
func (a1 atom) div(a2 atom) atom {
if nb1, ok := a1.get(); ok {
if nb2, ok := a2.get(); ok {
if nb2.IsInt() && nb2.Num().IsInt64() && nb2.Num().Int64() == 0 {
return undefined(0)
}
return rational(new(big.Rat).Quo(nb1, nb2), a1.Sign()*a2.Sign())
}
return undefined(a1.Sign() * a2.Sign())
} else if a2.IsDefined() {
return undefined(a1.Sign() * a2.Sign())
}
return undefined(0)
}
func (a1 atom) quo(a2 atom) atom {
if nb1, ok := a1.get(); ok {
if nb2, ok := a2.get(); ok {
if nb2.IsInt() && nb2.Num().IsInt64() && nb2.Num().Int64() == 0 {
return undefined(0)
}
n := new(big.Int).Mul(nb1.Num(), nb2.Num())
d := new(big.Int).Mul(nb1.Denom(), nb2.Denom())
return entire0(new(big.Int).Quo(n, d), a1.Sign()*a2.Sign())
}
return undefined(a1.Sign() * a2.Sign())
} else if a2.IsDefined() {
return undefined(a1.Sign() * a2.Sign())
}
return undefined(0)
}
func (a1 atom) quoRem(a2 atom) (q, r atom) {
q = a1.quo(a2)
r = a1.sub(a2.mul(q))
return
}
func (a1 atom) rem(a2 atom) atom {
_, r := a1.quoRem(a2)
return r
}
func (a atom) inv() atom {
if nb, ok := a.get(); ok {
n, d := nb.Num(), nb.Denom()
return frac0(d, n, a.Sign())
}
if a.Sign() == 0 {
return undefined(0)
}
return entire(0, 0)
}
func (a atom) pow(p uint64) atom {
switch {
case p == 0:
if a.IsNan() {
return undefined(0)
}
return entire(0, 0)
case p == 1:
return a.clone(true)
case p == 2:
return a.mul(a)
case p&1 == 0:
return a.mul(a).pow(p >> 1)
default:
return a.mul(a).pow(p >> 1).mul(a)
}
}
func (a atom) optimize(precision atom) atom {
if a.isInt() || !a.IsDefined() {
return a
}
n1, d1 := a.num().abs(), a.denom()
t := n1.mul(precision).quo(d1)
an := t.div(precision)
n2, d2 := an.num(), an.denom()
if n2.cmp(n1) < 0 || d2.cmp(d1) < 0 {
t.sign = a.sign
return t.format()
}
return a
}
func (a atom) heron(n uint64, tmp atom) atom {
n0 := entire(int64(n), 1)
n1 := n0.dec()
return ((tmp.mul(n1)).add(a.div(tmp.pow(n - 1)))).div(n0)
}
func (a atom) sqrtn(n uint64, base uint) atom {
switch {
case a.IsNan() || n < 2 || (a.IsNeg() && n&1 == 0):
return undefined(0)
case a.IsZero() || a.Is(1) || !a.IsDefined():
return a.clone(true)
default:
precision := pow(base, FloatingPrecision)
pi := precision.inv()
out := a.heron(n, a).optimize(precision)
for {
t := a.heron(n, out).optimize(precision)
if out.cmp(t) == 0 {
break
} else if out.sub(t).abs().cmp(pi) < 0 {
out = t
break
}
}
return out
}
}
func (a atom) IsEven() bool {
if nb, ok := a.get(); ok {
return nb.IsInt() && nb.Num().Bit(0) == 0
}
return false
}
func (a atom) IsOdd() bool {
if nb, ok := a.get(); ok {
return nb.IsInt() && nb.Num().Bit(0) != 0
}
return false
}
func (a atom) lsh(n uint) atom {
if nb, ok := a.get(); ok {
if nb.IsInt() {
num, denom := new(big.Int).Lsh(nb.Num(), n), nb.Denom()
return frac0(num, denom, a.Sign())
}
return a.mul(pow(2, n))
}
return undefined(a.Sign())
}
func (a atom) rsh(n uint) atom {
if nb, ok := a.get(); ok {
if nb.IsInt() {
num, denom := new(big.Int).Rsh(nb.Num(), n), nb.Denom()
return frac0(num, denom, a.Sign())
}
return a.div(pow(2, n))
}
return undefined(a.Sign())
}
func (a atom) len(base uint) int {
if nb, ok := a.get(); ok {
if !nb.IsInt() {
return -1
}
num := nb.Num()
if num.IsInt64() && num.Int64() == 0 {
return 1
}
s := num.Text(int(base))
return len(s)
}
return -1
}
func (a atom) bit(n uint64, base uint) int {
if !a.isInt() {
return -1
}
out := a
if n > 0 {
out = a.quo(pow(base, n))
}
out = out.rem(entire(base, 1))
if nb, ok := out.get(); ok {
return int(nb.Num().Int64())
}
return -1
}

View File

@ -7,56 +7,42 @@ import (
var ( var (
FloatingPrecision uint64 = 10 // Nombre de chiffres après la virgule pour un nombre décimal ou un nombre scientifique FloatingPrecision uint64 = 10 // Nombre de chiffres après la virgule pour un nombre décimal ou un nombre scientifique
FixedPrecision = false // Si vrai le nombre de chiffres après la virgule est fixe. FixedPrecision = false // Si vrai le nombre chiffre après la virgule est fixe.
) )
const ( const (
rSign = `(\+|-)` regSign = `\+|-`
rBSign = `(0|1)` regBSign = `0|1`
rNb2 = `(0|1)` regBase = `\(\d+\)`
rNb8 = `[0-7]` regBase2 = `B|b`
rNb10 = `\d` regBase8 = `O|o`
rNb16 = `[0-9a-fA-F]` regBase16 = `X|x`
rNbN = `[0-9a-zA-Z]` regNb = `[0-9a-zA-Z]`
rBase2 = `(B|b)` regNb2 = `0|1`
rBase8 = `(O|o)` regNb8 = `[0-7]`
rBase16 = `(X|x)` regNb10 = `\d`
rExp10 = `E|e` regNb16 = `[0-9a-fA-F]`
rExpN = `×\d+\^` regExp = `×\d+\^`
regExp10 = `E|e`
) )
var ( var (
rInt2 = fmt.Sprintf(`(%s)%s+`, rBase2, rNb2) regInt = regexp.MustCompile(fmt.Sprintf(`%s(%s)?%s+`, regBase, regSign, regNb))
rInt8 = fmt.Sprintf(`(%s)%s+`, rBase8, rNb8) regInt2 = regexp.MustCompile(fmt.Sprintf(`(%s)(%s)(%s)+`, regBSign, regBase2, regNb2))
rInt10 = fmt.Sprintf(`(%s)%s+`, rSign, rNb10) regInt8 = regexp.MustCompile(fmt.Sprintf(`(%s)(%s)(%s)+`, regBSign, regBase8, regNb8))
rInt16 = fmt.Sprintf(`(%s)%s+`, rBase8, rNb8) regInt10 = regexp.MustCompile(fmt.Sprintf(`(%s)?%s+`, regSign, regNb10))
rIntN = fmt.Sprintf(`\(%s+\)%s?%s+`, rNb10, rSign, rNbN) regInt16 = regexp.MustCompile(fmt.Sprintf(`(%s)(%s)(%s)+`, regBSign, regBase16, regNb16))
rIntB = fmt.Sprintf(`%s(%s|%s|%s)`, rBSign, rInt2, rInt8, rInt16)
rInt = fmt.Sprintf(`(%s|%s|%s)`, rInt10, rIntN, rIntB)
rDec2 = fmt.Sprintf(`(%s)(%s+\.%s*|\.%s+)`, rBase2, rNb2, rNb2, rNb2) regDec = regexp.MustCompile(fmt.Sprintf(`%s(%s)?(%s*\.%s+|%s+\.)`, regBase, regSign, regNb, regNb, regNb))
rDec8 = fmt.Sprintf(`(%s)(%s+\.%s*|\.%s+)`, rBase8, rNb8, rNb8, rNb8) regDec2 = regexp.MustCompile(fmt.Sprintf(`(%s)(%s)((%s)*\.(%s)+|(%s)+\.)`, regBSign, regBase2, regNb2, regNb2, regNb2))
rDec10 = fmt.Sprintf(`%s?(%s+\.%s*|\.%s+)`, rSign, rNb10, rNb10, rNb10) regDec8 = regexp.MustCompile(fmt.Sprintf(`(%s)(%s)((%s)*\.(%s)+|(%s)+\.)`, regBSign, regBase8, regNb8, regNb8, regNb8))
rDec16 = fmt.Sprintf(`(%s)(%s+\.%s*|\.%s+)`, rBase16, rNb16, rNb16, rNb16) regDec10 = regexp.MustCompile(fmt.Sprintf(`(%s)?(%s*\.%s+|%s+\.)`, regSign, regNb10, regNb10, regNb10))
rDecN = fmt.Sprintf(`\(%s+\)%s?(%s+\.%s*|\.%s+)`, rNb10, rSign, rNbN, rNbN, rNbN) regDec16 = regexp.MustCompile(fmt.Sprintf(`(%s)(%s)((%s)*\.(%s)+|(%s)+\.)`, regBSign, regBase16, regNb16, regNb16, regNb16))
rDecB = fmt.Sprintf(`%s(%s|%s|%s)`, rBSign, rDec2, rDec8, rDec16)
rDec = fmt.Sprintf(`(%s|%s|%s)`, rDec10, rDecN, rDecB) regFrac = regexp.MustCompile(fmt.Sprintf(`%s(%s)?%s+/(%s)?%s+`, regBase, regSign, regNb, regSign, regNb))
rExponent10 = fmt.Sprintf(`(%s|%s)(%s)%s?%s+`, rInt10, rDec10, rExp10, rSign, rNb10) regFrac10 = regexp.MustCompile(fmt.Sprintf(`(%s)?%s+/(%s)?%s+`, regSign, regNb10, regSign, regNb10))
rExponentN = fmt.Sprintf(`(%s|%s)%s%s?%s+`, rInt, rDec, rExpN, rSign, rNb10)
rAll10 = fmt.Sprintf(`(%s|%s)((%s)%s?%s+)?`, rInt10, rDec10, regExp10, rSign, rNb10) regSci = regexp.MustCompile(fmt.Sprintf(`%s(%s)?(%s*\.%s+|%s+\.?)%s(%s)?(%s)+`, regBase, regSign, regNb, regNb, regNb, regExp, regSign, regNb10))
rAllN = fmt.Sprintf(`(%s|%s)(%s%s?%s+)?`, rInt, rDec, rExpN, rSign, rNb10) regSci10Simple = regexp.MustCompile(fmt.Sprintf(`%s(%s)?(%s*\.%s+|%s+\.?)`, regSign, regNb10, regNb10, regNb10, regExp, regSign, regNb10))
rAll = fmt.Sprintf(`(%s|%s)`, rAll10, rAllN) regSci10 = regexp.MustCompile(fmt.Sprintf(`%s(%s)?(%s*\.%s+|%s+\.?)`, regSign, regNb10, regNb10, regNb10, regExp10, regSign, regNb10))
)
var (
regInt10 = regexp.MustCompile(fmt.Sprintf(`^%s$`, rInt10))
regIntN = regexp.MustCompile(fmt.Sprintf(`^%s$`, rIntN))
regIntB = regexp.MustCompile(fmt.Sprintf(`^%s$`, rIntB))
regDec = regexp.MustCompile(fmt.Sprintf(`^%s$`, rDec))
regExp10 = regexp.MustCompile(fmt.Sprintf(`^%s$`, rExponent10))
regExpN = regexp.MustCompile(fmt.Sprintf(`^%s$`, rExpN))
regFrac = regexp.MustCompile(fmt.Sprintf(`^%s/%s$`, rAll, rAll))
) )

View File

@ -9,109 +9,160 @@ import (
"gitea.zaclys.com/bvaudour/gob/option" "gitea.zaclys.com/bvaudour/gob/option"
) )
// Undefined retourne un nombre indéfini, signé : func undefinedString(sign int) string {
// - si sign < 0, retourne -∞ switch sign {
// - si sign > 0, retourne +∞ case -1:
// - sinon, retourne NaN return "-∞"
func Undefined[N integer | float](sign N) Number { case +1:
return Number{ return "+∞"
base: 10, default:
tpe: Integer, return "NaN"
sign: signOf(sign),
} }
} }
// Nan retourne NaN. func integerString(n *big.Int, base uint, sign int) string {
func Nan() Number { return Undefined(0) } out := n.Text(int(base))
// Inf retourne +∞. if sign < 0 {
func Inf() Number { return Undefined(1) } out = fmt.Sprintf("-%s", out)
// NegInf retourne -∞.
func NegInf() Number { return Undefined(-1) }
// IntOf0 retourne un nombre entier à partir dun entier, et éventuellement une base.
func IntOf0(i *big.Int, base ...uint) Number {
if i == nil {
return Nan()
} }
n := Number{ if base != 10 {
number: option.Some(new(big.Rat).SetInt(i)), out = fmt.Sprintf("(%d)%s", base, out)
sign: 1,
base: formatBase(base...),
tpe: Integer,
} }
return n.format() return out
} }
// IntOf retourne un nombre entier à partir dun entier, et éventuellement une base. func fractionString(n, d *big.Int, base uint, sign int) string {
func IntOf[N integer | float](i N, base ...uint) Number { out := fmt.Sprintf("%s/%s", n.Text(int(base)), d.Text(int(base)))
return IntOf0(new(big.Int).SetInt64(int64(i)), base...)
}
func pow[N integer | float, M integer | float](b N, p ...M) Number { if sign < 0 {
if len(p) > 0 { out = fmt.Sprintf("-%s", out)
return IntOf(b).pow(int64(p[0]))
}
return IntOf(b).pow(int64(FloatingPrecision))
}
// Zero retourne le nombre 0.
func Zero(base ...uint) Number { return IntOf(0, base...) }
// One retourne le nombre 1.
func One(base ...uint) Number { return IntOf(1, base...) }
// Two retourne le nombre 2.
func Two(base ...uint) Number { return IntOf(2, base...) }
// DecOf0 retourne un nombre décimal à partir dun rationnel.
func DecOf0(f *big.Rat, base ...uint) Number {
if f == nil {
return Nan()
} }
n := Number{ if base != 10 {
number: option.Some(new(big.Rat).Set(f)), out = fmt.Sprintf("(%d)%s", base, out)
sign: 1,
base: formatBase(base...),
tpe: Decimal,
} }
return n.format() return out
} }
// DecOf retourne un nombre décimal à partir dun flottant. func decimalString(n Number) string {
func DecOf[N integer | float](f float64, base ...uint) Number { base := n.Base()
return DecOf0(new(big.Rat).SetFloat64(float64(f))) num, denom := n.num(), n.denom()
} p := pow(base, FloatingPrecision)
num = num.mul(p)
q := num.quo(denom)
// FracOf0 retourne une fraction à partir dun numérateur et dun dénominateur entiers. out := "0"
func FracOf0(num, denom *big.Int, base ...uint) Number { if num.cmp(denom) >= 0 {
if num == nil || denom == nil { if qn, ok := q.get(); ok {
return Nan() out = qn.Num().Text(int(base))
} else {
return ""
}
} }
n := Number{ precision := int(FloatingPrecision)
number: option.Some(new(big.Rat).SetFrac(num, denom)), if len(out) < precision {
sign: 1, out = fmt.Sprintf("%s%s", strings.Repeat("0", precision), out)
base: formatBase(base...),
tpe: Fraction,
} }
return n.format() deltaPrecision := len(out) - precision
out = fmt.Sprintf("%s.%s", out[:deltaPrecision], out[deltaPrecision:])
if !FixedPrecision {
l := len(out) - 1
for out[l] == '0' {
out, l = out[:l], l-1
}
if out == "." {
out = "0."
}
}
if n.IsNeg() {
out = fmt.Sprintf("-%s", out)
} else if q.IsZero() && !n.IsZero() {
out = fmt.Sprintf("+%s", out)
}
if base != 10 {
out = fmt.Sprintf("(%d)%s", base, out)
}
return out
} }
// FracOf retourne une fraction à partir dun numérateur et dun dénominateur entiers. func scientificStsring(n Number) string {
func FracOf[N integer | float](num, denom N, base ...uint) Number { base := n.Base()
return FracOf0(new(big.Int).SetInt64(int64(num)), new(big.Int).SetInt64(int64(denom)), base...) var exponent int
tmp := n
if n.IsZero() {
num, denom := n.Abs().NumDenom()
nl, dl := num.Len(), denom.Len()
exponent := nl - dl
if exponent > 0 {
denom = denom.Mul(Number{
base: base,
tpe: Integer,
atom: pow(base, exponent),
})
} else if exponent < 0 {
num = num.Mul(Number{
base: base,
tpe: Integer,
atom: pow(base, -exponent),
})
}
if num.Lt(denom) {
exponent--
num.Mul(Int(base, base))
}
tmp = num.Div(denom)
}
out := decimalString(tmp)
signExponent := ""
if exponent > 0 {
signExponent = "+"
} else if exponent < 0 {
signExponent = "-"
}
if base == 10 {
return fmt.Sprintf("%sE%s%d", out, signExponent, exponent)
}
return fmt.Sprintf("%s×%d^%s%d", out, base, signExponent, exponent)
} }
func parseBaseN(str string) (next string, base option.Option[uint]) { // String retourne la représentation du nombre sous forme de chaîne de caractères.
func (n Number) String() string {
if nb, ok := n.get(); ok {
switch n.Type() {
case Integer:
return integerString(nb.Num(), n.Base(), n.Sign())
case Fraction:
return fractionString(nb.Num(), nb.Denom(), n.base, n.Sign())
case Scientific:
return scientificStsring(n)
default:
return decimalString(n)
}
}
return undefinedString(n.Sign())
}
func parseBase(str string) (next string, base option.Option[uint]) {
begin := strings.Index(str, "(") begin := strings.Index(str, "(")
end := strings.Index(str, ")") end := strings.Index(str, ")")
if begin > end || begin < 0 || end < 0 {
return
}
next = str[end+1:] next = str[end+1:]
if b, err := strconv.ParseUint(str[begin+1:end], 10, 64); err == nil && isBaseValid(b) { if b, err := strconv.ParseUint(str[begin+1:end], 10, 64); err == nil && isBaseValid(b) {
@ -120,7 +171,7 @@ func parseBaseN(str string) (next string, base option.Option[uint]) {
return return
} }
func parseBaseB(str string) (next string, base uint) { func parseBaseN(str string) (next string, base uint) {
next = str[1:] next = str[1:]
switch str[0] { switch str[0] {
case 'B', 'b': case 'B', 'b':
@ -134,7 +185,7 @@ func parseBaseB(str string) (next string, base uint) {
return return
} }
func parseSignN(str string) (next string, sign int) { func parseSign(str string) (next string, sign int) {
switch str[0] { switch str[0] {
case '-': case '-':
next, sign = str[1:], -1 next, sign = str[1:], -1
@ -147,7 +198,7 @@ func parseSignN(str string) (next string, sign int) {
return return
} }
func parseSignB(str string) (next string, sign int) { func parseSignN(str string) (next string, sign int) {
next, sign = str[1:], 1 next, sign = str[1:], 1
if str[0] == '1' { if str[0] == '1' {
sign = -1 sign = -1
@ -166,40 +217,226 @@ func parseNumber(str string, base uint) (n option.Option[*big.Int]) {
func setInt(str string, base uint, sign int) (n option.Option[Number]) { func setInt(str string, base uint, sign int) (n option.Option[Number]) {
if nb, ok := parseNumber(str, base).Get(); ok { if nb, ok := parseNumber(str, base).Get(); ok {
if sign < 0 { nn := Number{
nb.Neg(nb) base: base,
tpe: Integer,
atom: entire0(nb, sign),
} }
n = option.Some(IntOf0(nb, base)) n = option.Some(nn.format())
} }
return return
} }
func parseInt10(str string) (n option.Option[Number]) { func parseInt(str string) (n option.Option[Number]) {
next, sign := parseSignN(str) next, base := parseBase(str)
return setInt(next, 10, sign)
}
func parseIntB(str string) (n option.Option[Number]) {
next, sign := parseSignB(str)
next, base := parseBaseB(next)
return setInt(next, base, sign)
}
func parseIntN(str string) (n option.Option[Number]) {
next, base := parseBaseN(str)
if b, ok := base.Get(); ok { if b, ok := base.Get(); ok {
next, sign := parseSignN(next) next, sign := parseSign(next)
n = setInt(next, b, sign) n = setInt(next, b, sign)
} }
return return
} }
func parseInt10(str string) (n option.Option[Number]) {
next, sign := parseSign(str)
return setInt(next, 10, sign)
}
func parseIntN(str string) (n option.Option[Number]) {
next, sign := parseSignN(str)
next, base := parseBaseN(next)
return setInt(next, base, sign)
}
func setFrac(str string, base uint, sign int) (n option.Option[Number]) {
i := strings.Index(str, "/")
if i < 0 {
return
}
sNum, sDenom := str[:i], str[i:]
if num, ok := parseNumber(sNum, base).Get(); ok {
if denom, ok := parseNumber(sDenom, base).Get(); ok {
nn := Number{
base: base,
tpe: Fraction,
atom: frac0(num, denom, sign),
}
n = option.Some(nn.format())
}
}
return
}
func parseFrac(str string) (n option.Option[Number]) {
next, base := parseBase(str)
if b, ok := base.Get(); ok {
next, sign := parseSign(next)
n = setFrac(next, b, sign)
}
return
}
func parseFrac10(str string) (n option.Option[Number]) {
next, sign := parseSign(str)
return setFrac(next, 10, sign)
}
func parseDot(str string) (next string, dot int) {
i := strings.Index(str, ".")
if i >= 0 {
next = str[:i] + str[:i]
dot = len(next) - i
}
return
}
func setDec(str string, base uint, sign int) (n option.Option[Number]) {
next, dot := parseDot(str)
if num, ok := parseNumber(next, base).Get(); ok {
denom := pow(base, dot)
nn := Number{
base: base,
tpe: Decimal,
atom: entire0(num, sign).div(denom),
}
n = option.Some(nn.format())
}
return
}
func parseDec(str string) (n option.Option[Number]) {
next, base := parseBase(str)
if b, ok := base.Get(); ok {
next, sign := parseSign(next)
n = setDec(next, b, sign)
}
return
}
func parseDec10(str string) (n option.Option[Number]) {
next, sign := parseSign(str)
return setDec(next, 10, sign)
}
func parseDecN(str string) (n option.Option[Number]) {
next, sign := parseSignN(str)
next, base := parseBaseN(next)
return setDec(next, base, sign)
}
func parseExp(str string) (next string, baseExponent option.Option[int], exponent option.Option[int]) {
begin := strings.Index(str, "x")
end := strings.Index(str, "^")
if begin > end || begin < 0 || end < 0 {
return
}
sBase, sExponent := str[begin+1:end], str[end+1:]
if b, err := strconv.Atoi(sBase); err == nil && isBaseValid(b) {
if e, err := strconv.Atoi(sExponent); err == nil {
next, baseExponent, exponent = str[:begin], option.Some(b), option.Some(e)
}
}
return
}
func parseExp10(str string) (next string, exponent option.Option[int]) {
i := strings.Index(strings.ToLower(str), "e")
if i < 0 {
return
}
sExponent := str[i+1:]
if e, err := strconv.Atoi(sExponent); err == nil {
next, exponent = str[:i], option.Some(e)
}
return
}
func setSci(str string, base uint, sign, baseExponent, exponent int) (n option.Option[Number]) {
next, dot := parseDot(str)
if num, ok := parseNumber(next, base).Get(); ok {
denom := pow(base, dot)
nn := Number{
base: base,
tpe: Scientific,
atom: entire0(num, sign).div(denom),
}
if exponent > 0 {
nn.atom = nn.atom.mul(pow(baseExponent, exponent))
} else if exponent < 0 {
nn.atom = nn.atom.div(pow(baseExponent, -exponent))
}
n = option.Some(nn.format())
}
return
}
func parseSci(str string) (n option.Option[Number]) {
next, base := parseBase(str)
if b, ok := base.Get(); ok {
next, sign := parseSign(next)
next, be, e := parseExp(next)
if baseExponent, ok := be.Get(); ok {
if exponent, ok := e.Get(); ok {
n = setSci(next, b, sign, baseExponent, exponent)
}
}
}
return
}
func parseSci10(str string) (n option.Option[Number]) {
next, sign := parseSign(str)
next, be, e := parseExp(next)
if baseExponent, ok := be.Get(); ok {
if exponent, ok := e.Get(); ok {
n = setSci(next, 10, sign, baseExponent, exponent)
}
}
return
}
func parseSci10Simple(str string) (n option.Option[Number]) {
next, sign := parseSign(str)
next, e := parseExp10(next)
if exponent, ok := e.Get(); ok {
n = setSci(next, 10, sign, 10, exponent)
}
return
}
// Parse retourne un nombre à partir dune chaîne de caractères. // Parse retourne un nombre à partir dune chaîne de caractères.
func Parse(str string) (out option.Option[Number]) { func Parse(str string) option.Option[Number] {
switch str { switch str {
case "+∞", "<inf>", "<+inf>": case "+∞", "<inf>", "<+inf>":
return option.Some(Inf()) return option.Some(Inf())
@ -210,50 +447,33 @@ func Parse(str string) (out option.Option[Number]) {
} }
switch { switch {
case regInt.MatchString(str):
return parseInt(str)
case regInt10.MatchString(str): case regInt10.MatchString(str):
return parseInt10(str) return parseInt10(str)
case regIntB.MatchString(str): case regInt2.MatchString(str), regInt8.MatchString(str), regInt16.MatchString(str):
return parseIntB(str)
case regIntN.MatchString(str):
return parseIntN(str) return parseIntN(str)
case regDec.MatchString(str):
l := len(str)
i := strings.Index(str, ".")
dot := l - 1 - i
str = fmt.Sprintf("%s%s", str[:i], str[i+1:])
if n, ok := Parse(str).Get(); ok {
out = option.Some(n.Div(pow(n.Base(), dot)).ToType(Decimal))
}
case regExp10.MatchString(str):
i := strings.Index(strings.ToLower(str), "e")
if exponent, err := strconv.Atoi(str[i+1:]); err == nil {
if n, ok := Parse(str[:i]).Get(); ok {
out = option.Some(n.Mul(pow(10, exponent)).ToType(Scientific))
}
}
case regExpN.MatchString(str):
i, j := strings.Index(str, "×"), strings.Index(str, "^")
if expBase, err := strconv.ParseUint(str[i+1:j], 10, 64); err == nil && isBaseValid(expBase) {
if exponent, err := strconv.Atoi(str[j+1:]); err == nil {
if n, ok := Parse(str[:i]).Get(); ok {
out = option.Some(n.Mul(pow(expBase, exponent)).ToType(Scientific))
}
}
}
case regFrac.MatchString(str): case regFrac.MatchString(str):
i := strings.Index(str, "/") return parseFrac(str)
num, denom := Parse(str[:i]), Parse(str[i:]) case regFrac10.MatchString(str):
if n, ok := num.Get(); ok { return parseFrac10(str)
if d, ok := denom.Get(); ok { case regDec.MatchString(str):
out = option.Some(n.Div(d).ToType(Fraction)) return parseInt(str)
} case regDec10.MatchString(str):
} return parseInt10(str)
case regDec2.MatchString(str), regDec8.MatchString(str), regDec16.MatchString(str):
return parseIntN(str)
case regSci.MatchString(str):
return parseSci(str)
case regSci10.MatchString(str):
return parseSci10(str)
case regSci10Simple.MatchString(str):
return parseSci10Simple(str)
} }
return return option.None[Number]()
} }
// ParseBool retourne 1 si vrai, et 0 sinon.
func ParseBool(b bool) Number { func ParseBool(b bool) Number {
if b { if b {
return One() return One()
@ -261,5 +481,6 @@ func ParseBool(b bool) Number {
return Zero() return Zero()
} }
// ToBool retourne vrai si le nombre nest ni NaN ni 0. func ToBool(n Number) bool {
func ToBool(n Number) bool { return n.Sign() != 0 } return !n.IsZero() && !n.IsNan()
}

File diff suppressed because it is too large Load Diff

View File

@ -11,7 +11,6 @@ type Op2To2Func func(Number, Number) (Number, Number)
type ReduceFunc func(...Number) Number type ReduceFunc func(...Number) Number
type MapFunc func(...Number) []Number type MapFunc func(...Number) []Number
// ToBase convertit n selon la base donnée.
func ToBase[N integer](n Number, base N) Number { func ToBase[N integer](n Number, base N) Number {
return n.ToBase(formatBase(base)) return n.ToBase(formatBase(base))
} }
@ -25,33 +24,36 @@ func toType[N integer](n Number, t NumberType, base ...N) Number {
return n return n
} }
// ToInteger convertit n en entier. func ToInteger[N integer](n Number, base ...N) Number {
func ToInteger[N integer](n Number, base ...N) Number { return toType(n, Integer, base...) } return toType(n, Integer, base...)
}
// ToDecimal convertit n en décimal. func ToDecimal[N integer](n Number, base ...N) Number {
func ToDecimal[N integer](n Number, base ...N) Number { return toType(n, Decimal, base...) } return toType(n, Decimal, base...)
}
// ToFraction convertit n en fraction. func ToFraction[N integer](n Number, base ...N) Number {
func ToFraction[N integer](n Number, base ...N) Number { return toType(n, Fraction, base...) } return toType(n, Fraction, base...)
}
// ToScientific convertit n en nombre scientifique. func ToScientific[N integer](n Number, base ...N) Number {
func ToScientific[N integer](n Number, base ...N) Number { return toType(n, Scientific, base...) } return toType(n, Scientific, base...)
}
// Fonctions de type f(n) → n // Fonctions de type f(n) → n
func Neg(n Number) Number { return n.Neg() } func Neg(n Number) Number { return n.Neg() }
func Abs(n Number) Number { return n.Abs() } func Abs(n Number) Number { return n.Abs() }
func Num(n Number) Number { return n.Num() } func Num(n Number) Number { return n.Num() }
func Denom(n Number) Number { return n.Denom() } func Denom(n Number) Number { return n.Denom() }
func Inc(n Number) Number { return n.Inc() } func Inc(n Number) Number { return n.Inc() }
func Dec(n Number) Number { return n.Dec() } func Dec(n Number) Number { return n.Dec() }
func Inv(n Number) Number { return n.Inv() } func Inv(n Number) Number { return n.Inv() }
func Fact(n Number) Number { return n.Fact() } func Fact(n Number) Number { return n.Fact() }
func Len(n Number) Number { return IntOf(n.Len()) } func Len(n Number) Number { return Int(n.Len()) }
func Sqrt(n Number) Number { return n.Sqrt() } func Sqrt(n Number) Number { return n.Sqrt() }
func Square(n Number) Number { return n.Square() }
// Fonctions de type f(n, n) → n // Fonctions de type f(n, n) → n
func Cmp(n1, n2 Number) Number { return IntOf(n1.Cmp(n2)) } func Cmp(n1, n2 Number) Number { return Int(n1.Cmp(n2)) }
func Eq(n1, n2 Number) Number { return ParseBool(n1.Eq(n2)) } func Eq(n1, n2 Number) Number { return ParseBool(n1.Eq(n2)) }
func Ne(n1, n2 Number) Number { return ParseBool(n1.Ne(n2)) } func Ne(n1, n2 Number) Number { return ParseBool(n1.Ne(n2)) }
func Gt(n1, n2 Number) Number { return ParseBool(n1.Gt(n2)) } func Gt(n1, n2 Number) Number { return ParseBool(n1.Gt(n2)) }
@ -66,7 +68,7 @@ func Quo(n1, n2 Number) Number { return n1.Quo(n2) }
func Rem(n1, n2 Number) Number { return n1.Rem(n2) } func Rem(n1, n2 Number) Number { return n1.Rem(n2) }
func Lsh(n1, n2 Number) Number { return n1.Lsh(n2) } func Lsh(n1, n2 Number) Number { return n1.Lsh(n2) }
func Rsh(n1, n2 Number) Number { return n1.Rsh(n2) } func Rsh(n1, n2 Number) Number { return n1.Rsh(n2) }
func Bit(n1, n2 Number) Number { return IntOf(n1.Bit(n2)) } func Bit(n1, n2 Number) Number { return Int(n1.Bit(n2)) }
func Pow(n1, n2 Number) Number { return n1.Pow(n2) } func Pow(n1, n2 Number) Number { return n1.Pow(n2) }
func Sqrtn(n1, n2 Number) Number { return n1.Sqrtn(n2) } func Sqrtn(n1, n2 Number) Number { return n1.Sqrtn(n2) }
@ -103,7 +105,6 @@ func Reduce(callback Op2Func) ReduceFunc {
} }
} }
// Max retourne le nombre le plus grand de la liste.
func Max(numbers ...Number) (n Number) { func Max(numbers ...Number) (n Number) {
return Reduce(func(n1, n2 Number) Number { return Reduce(func(n1, n2 Number) Number {
if n2.Gt(n1) { if n2.Gt(n1) {
@ -113,7 +114,6 @@ func Max(numbers ...Number) (n Number) {
})(numbers...) })(numbers...)
} }
// Min retourne le nombre le plus petit de la liste.
func Min(numbers ...Number) (n Number) { func Min(numbers ...Number) (n Number) {
return Reduce(func(n1, n2 Number) Number { return Reduce(func(n1, n2 Number) Number {
if n2.Lt(n1) { if n2.Lt(n1) {
@ -123,100 +123,35 @@ func Min(numbers ...Number) (n Number) {
})(numbers...) })(numbers...)
} }
// Sum retourne la somme des nombres. func Sum(numbers ...Number) (n Number) {
func Sum(numbers ...Number) (n Number) { return Reduce(Add)(numbers...) } return Reduce(Add)(numbers...)
}
// Mean retourne la moyenne des nombres.
func Mean(numbers ...Number) (n Number) { func Mean(numbers ...Number) (n Number) {
l := len(numbers) l := len(numbers)
if l == 0 { if l == 0 {
return Nan() return Nan()
} }
return Sum(numbers...).Div(IntOf(l)) return Sum(numbers...).Div(Int(l))
} }
// Median retourne la médiane des nombres.
func Median(numbers ...Number) Number {
l := len(numbers)
if l == 0 {
return Nan()
}
numbers = Sort(numbers...)
if l&1 == 0 {
i := l >> 1
return numbers[i].Add(numbers[i-1]).Div(Two())
}
return numbers[l>>1]
}
// Mode retourne retourne le mode des nombres (ie. le nombre le plus fréquent).
func Mode(numbers ...Number) Number {
l := len(numbers)
if l == 0 {
return Nan()
}
m := make(map[Number]int)
loop:
for _, n := range numbers {
for k := range m {
if k.Eq(n) {
m[k]++
continue loop
}
}
m[n] = 1
}
i := 0
var n Number
for k, j := range m {
if j > i {
n, i = k, j
}
}
return n
}
// Variance retourne la variance des nombres.
func Variance(numbers ...Number) Number {
m := Mean(numbers...)
if m.IsNan() {
return m
}
numbers = Map(func(n Number) Number {
return n.Sub(m).Square()
})(numbers...)
return Mean(numbers...)
}
// StdDeviation retourne lécart-type des nombres.
func StdDeviation(numbers ...Number) Number { return Variance(numbers...).Sqrt() }
// Round arrondit le n selon la précision et la base données.
func Round(n Number, precision uint64, base ...uint) Number { func Round(n Number, precision uint64, base ...uint) Number {
if !n.IsDefined() || n.Type() == Integer { if !n.IsDefined() || n.Type() == Integer {
return n return n
} }
b := n.Base() p := Number{
if len(base) > 0 { base: n.Base(),
b = formatBase(base...) tpe: n.Type(),
atom: pow(formatBase(base...), precision),
} }
p.format()
p := pow(b, precision)
num, denom := n.Num().Mul(p), n.Denom() num, denom := n.Num().Mul(p), n.Denom()
return num.Quo(denom).Div(p).ToType(n.Type()) return num.Quo(denom).Div(p)
} }
// Reverse inverse lordre de la liste des nombres.
func Reverse(numbers ...Number) []Number { func Reverse(numbers ...Number) []Number {
l := len(numbers) l := len(numbers)
for i := 0; i < l>>1; i++ { for i := 0; i < l>>1; i++ {
@ -227,7 +162,6 @@ func Reverse(numbers ...Number) []Number {
return numbers return numbers
} }
// Sort trie les nombres par ordre croissant.
func Sort(numbers ...Number) []Number { func Sort(numbers ...Number) []Number {
sort.Slice(numbers, func(i, j int) bool { sort.Slice(numbers, func(i, j int) bool {
return numbers[i].Lt(numbers[j]) return numbers[i].Lt(numbers[j])
@ -236,7 +170,6 @@ func Sort(numbers ...Number) []Number {
return numbers return numbers
} }
// SortDesc trie les nombres par ordre décroissant.
func SortDesc(numbers ...Number) []Number { func SortDesc(numbers ...Number) []Number {
sort.Slice(numbers, func(i, j int) bool { sort.Slice(numbers, func(i, j int) bool {
return numbers[i].Gt(numbers[j]) return numbers[i].Gt(numbers[j])

View File

@ -1,11 +1,5 @@
package number package number
import (
"math/big"
"gitea.zaclys.com/bvaudour/gob/option"
)
type integer interface { type integer interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 ~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
} }
@ -14,8 +8,6 @@ type float interface {
~float32 | ~float64 ~float32 | ~float64
} }
type rat = option.Option[*big.Rat]
func signOf[N integer | float](n N) int { func signOf[N integer | float](n N) int {
switch { switch {
case n < 0: case n < 0:
@ -27,14 +19,6 @@ func signOf[N integer | float](n N) int {
} }
} }
func abs[N integer | float](n N) N {
if n < 0 {
return -n
}
return n
}
func compare[N integer | float](n1, n2 N) int { func compare[N integer | float](n1, n2 N) int {
return signOf(n1 - n2) return signOf(n1 - n2)
} }

View File

@ -1,9 +1,5 @@
package option package option
import (
"fmt"
)
// Result stocke un résultat: // Result stocke un résultat:
// - soit le résultat est valide, et une valeur est stockée, // - soit le résultat est valide, et une valeur est stockée,
// - soit le résultat est invalide, et une erreur est stockée. // - soit le résultat est invalide, et une erreur est stockée.
@ -45,11 +41,3 @@ func (r Result[T]) Err() (err error, ok bool) {
func (r Result[T]) IsOk() bool { func (r Result[T]) IsOk() bool {
return r.ok return r.ok
} }
func (r Result[T]) String() string {
return fmt.Sprintf(`{
value: %v,
error: %s,
ok: %v,
}`, r.v, r.err, r.ok)
}

View File

@ -56,8 +56,11 @@ func (in *input) restart() {
n := in.readRune() n := in.readRune()
next <- n next <- n
r, ok := n.Ok() needClose := !n.IsOk()
needClose := !ok || r == Lf || r == Cr || r == C_C || r == C_D if !needClose {
r, ok := n.Ok()
needClose = ok && (r == Lf || r == Cr || r == C_C || r == C_D)
}
if needClose { if needClose {
close(next) close(next)
@ -314,21 +317,22 @@ func (in *input) nextChar() (key nkey) {
return return
} }
var s Sequence
switch r { switch r {
case Bs: case Bs:
key = nk(keyS(A_Bs)) s = A_Bs
case 'O': case 'O':
key = in.escO() return in.escO()
case '[': case '[':
key = in.escBracket() return in.escBracket()
case 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', case 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z': 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z':
key = nk(keyS(Sequence(r << 16))) s = Sequence(r << 16)
//default: default:
// return return
} }
in.clear() in.clear()
return return nk(keyS(s))
} }