func renderFloat(img *image.RGBA) { var yminF, ymaxMinF, heightF big.Float yminF.SetInt64(ymin) ymaxMinF.SetInt64(ymax - ymin) heightF.SetInt64(height) var xminF, xmaxMinF, widthF big.Float xminF.SetInt64(xmin) xmaxMinF.SetInt64(xmax - xmin) widthF.SetInt64(width) var y, x big.Float for py := int64(0); py < height; py++ { // y := float64(py)/height*(ymax-ymin) + ymin y.SetInt64(py) y.Quo(&y, &heightF) y.Mul(&y, &ymaxMinF) y.Add(&y, &yminF) for px := int64(0); px < width; px++ { // x := float64(px)/width*(xmax-xmin) + xmin x.SetInt64(px) x.Quo(&x, &widthF) x.Mul(&x, &xmaxMinF) x.Add(&x, &xminF) c := mandelbrotFloat(&x, &y) if c == nil { c = color.Black } img.Set(int(px), int(py), c) } } }
// Sqrt returns the square root n. func Sqrt(n *big.Float) *big.Float { prec := n.Prec() x := new(big.Float).SetPrec(prec).SetInt64(1) z := new(big.Float).SetPrec(prec).SetInt64(1) half := new(big.Float).SetPrec(prec).SetFloat64(0.5) t := new(big.Float).SetPrec(prec) for { z.Copy(x) t.Mul(x, x) t.Sub(t, n) t.Quo(t, x) t.Mul(t, half) x.Sub(x, t) if x.Cmp(z) == 0 { break } } return x }
// Compute the square root of n using Newton's Method. We start with // an initial estimate for sqrt(n), and then iterate // x_{i+1} = 1/2 * ( x_i + (n / x_i) ) // Result is returned in x func (e *Pslq) Sqrt(n, x *big.Float) { if n == x { panic("need distinct input and output") } if n.Sign() == 0 { x.Set(n) return } else if n.Sign() < 0 { panic("Sqrt of negative number") } prec := n.Prec() // Use the floating point square root as initial estimate nFloat64, _ := n.Float64() x.SetPrec(prec).SetFloat64(math.Sqrt(nFloat64)) // We use t as a temporary variable. There's no need to set its precision // since big.Float values with unset (== 0) precision automatically assume // the largest precision of the arguments when used as the result (receiver) // of a big.Float operation. var t big.Float // Iterate. for { t.Quo(n, x) // t = n / x_i t.Add(x, &t) // t = x_i + (n / x_i) t.Mul(&e.half, &t) // x_{i+1} = 0.5 * t if x.Cmp(&t) == 0 { // Exit loop if no change to result break } x.Set(&t) } }
// Divide func (a Scalar) Div_S(b S) S { var x, y big.Float x = big.Float(a) y = big.Float(b.(Scalar)) z := x.Quo(&x, &y) return (Scalar)(*z) }
func splitRangeString(start, end string, splits int) []string { results := []string{start} if start == end { return results } if end < start { tmp := start start = end end = tmp } // find longest common prefix between strings minLen := len(start) if len(end) < minLen { minLen = len(end) } prefix := "" for i := 0; i < minLen; i++ { if start[i] == end[i] { prefix = start[0 : i+1] } else { break } } // remove prefix from strings to split start = start[len(prefix):] end = end[len(prefix):] ordStart := stringToOrd(start) ordEnd := stringToOrd(end) tmp := new(big.Int) tmp.Sub(ordEnd, ordStart) stride := new(big.Float) stride.SetInt(tmp) stride.Quo(stride, big.NewFloat(float64(splits))) for i := 1; i <= splits; i++ { tmp := new(big.Float) tmp.Mul(stride, big.NewFloat(float64(i))) tmp.Add(tmp, new(big.Float).SetInt(ordStart)) result, _ := tmp.Int(new(big.Int)) value := prefix + ordToString(result, 0) if value != results[len(results)-1] { results = append(results, value) } } return results }
// floatLog computes natural log(x) using the Maclaurin series for log(1-x). func floatLog(c Context, x *big.Float) *big.Float { if x.Sign() <= 0 { Errorf("log of non-positive value") } // The series wants x < 1, and log 1/x == -log x, so exploit that. invert := false if x.Cmp(floatOne) > 0 { invert = true x.Quo(floatOne, x) } // x = mantissa * 2**exp, and 0.5 <= mantissa < 1. // So log(x) is log(mantissa)+exp*log(2), and 1-x will be // between 0 and 0.5, so the series for 1-x will converge well. // (The series converges slowly in general.) mantissa := newFloat(c) exp2 := x.MantExp(mantissa) exp := newFloat(c).SetInt64(int64(exp2)) exp.Mul(exp, floatLog2) if invert { exp.Neg(exp) } // y = 1-x (whereupon x = 1-y and we use that in the series). y := newFloat(c).SetInt64(1) y.Sub(y, mantissa) // The Maclaurin series for log(1-y) == log(x) is: -y - y²/2 - y³/3 ... yN := newFloat(c).Set(y) term := newFloat(c) n := newFloat(c).Set(floatOne) z := newFloat(c) // This is the slowest-converging series, so we add a factor of ten to the cutoff. // Only necessary when FloatPrec is at or beyond constPrecisionInBits. for loop := newLoop(c.Config(), "log", x, 40); ; { term.Quo(yN, n.SetUint64(loop.i+1)) z.Sub(z, term) if loop.done(z) { break } // Advance y**index (multiply by y). yN.Mul(yN, y) } if invert { z.Neg(z) } z.Add(z, exp) return z }
// sqrt for big.Float func sqrt(given *big.Float) *big.Float { const prec = 200 steps := int(math.Log2(prec)) given.SetPrec(prec) half := new(big.Float).SetPrec(prec).SetFloat64(0.5) x := new(big.Float).SetPrec(prec).SetInt64(1) t := new(big.Float) for i := 0; i <= steps; i++ { t.Quo(given, x) t.Add(x, t) t.Mul(half, t) } return x }
// compute √z using newton to solve // t² - z = 0 for t func sqrtDirect(z *big.Float) *big.Float { // f(t)/f'(t) = 0.5(t² - z)/t half := big.NewFloat(0.5) f := func(t *big.Float) *big.Float { x := new(big.Float).Mul(t, t) // x = t² x.Sub(x, z) // x = t² - z x.Mul(half, x) // x = 0.5(t² - z) return x.Quo(x, t) // return x = 0.5(t² - z)/t } // initial guess zf, _ := z.Float64() guess := big.NewFloat(math.Sqrt(zf)) return newton(f, guess, z.Prec()) }
// hypot for big.Float func hypot(p, q *big.Float) *big.Float { // special cases switch { case p.IsInf() || q.IsInf(): return big.NewFloat(math.Inf(1)) } p = p.Abs(p) q = q.Abs(q) if p.Cmp(p) < 0 { p, q = q, p } if p.Cmp(big.NewFloat(0)) == 0 { return big.NewFloat(0) } q = q.Quo(q, p) return sqrt(q.Mul(q, q).Add(q, big.NewFloat(1))).Mul(q, p) }
func sqrtFloat(x *big.Float) *big.Float { t1 := new(big.Float).SetPrec(prec) t2 := new(big.Float).SetPrec(prec) t1.Copy(x) // Iterate. // x{n} = (x{n-1}+x{0}/x{n-1}) / 2 for i := 0; i <= steps; i++ { if t1.Cmp(zero) == 0 || t1.IsInf() { return t1 } t2.Quo(x, t1) t2.Add(t2, t1) t1.Mul(half, t2) } return t1 }
// This example shows how to use big.Float to compute the square root of 2 with // a precision of 200 bits, and how to print the result as a decimal number. func Example_sqrt2() { // We'll do computations with 200 bits of precision in the mantissa. const prec = 200 // Compute the square root of 2 using Newton's Method. We start with // an initial estimate for sqrt(2), and then iterate: // x_{n+1} = 1/2 * ( x_n + (2.0 / x_n) ) // Since Newton's Method doubles the number of correct digits at each // iteration, we need at least log_2(prec) steps. steps := int(math.Log2(prec)) // Initialize values we need for the computation. two := new(big.Float).SetPrec(prec).SetInt64(2) half := new(big.Float).SetPrec(prec).SetFloat64(0.5) // Use 1 as the initial estimate. x := new(big.Float).SetPrec(prec).SetInt64(1) // We use t as a temporary variable. There's no need to set its precision // since big.Float values with unset (== 0) precision automatically assume // the largest precision of the arguments when used as the result (receiver) // of a big.Float operation. t := new(big.Float) // Iterate. for i := 0; i <= steps; i++ { t.Quo(two, x) // t = 2.0 / x_n t.Add(x, t) // t = x_n + (2.0 / x_n) x.Mul(half, t) // x_{n+1} = 0.5 * t } // We can use the usual fmt.Printf verbs since big.Float implements fmt.Formatter fmt.Printf("sqrt(2) = %.50f\n", x) // Print the error between 2 and x*x. t.Mul(x, x) // t = x*x fmt.Printf("error = %e\n", t.Sub(two, t)) // Output: // sqrt(2) = 1.41421356237309504880168872420969807856967187537695 // error = 0.000000e+00 }
// return: x^y func Pow(x *big.Float, n int64) *big.Float { res := new(big.Float).Copy(x) if n < 0 { res = res.Quo(big.NewFloat(1), res) n = -n } else if n == 0 { return big.NewFloat(1) } y := big.NewFloat(1) for i := n; i > 1; { if i%2 == 0 { i /= 2 } else { y = y.Mul(res, y) i = (i - 1) / 2 } res = res.Mul(res, res) } return res.Mul(res, y) }
// Pow returns a big.Float representation of z**w. Precision is the same as the one // of the first argument. The function panics when z is negative. func Pow(z *big.Float, w *big.Float) *big.Float { if z.Sign() < 0 { panic("Pow: negative base") } // Pow(z, 0) = 1.0 if w.Sign() == 0 { return big.NewFloat(1).SetPrec(z.Prec()) } // Pow(z, 1) = z // Pow(+Inf, n) = +Inf if w.Cmp(big.NewFloat(1)) == 0 || z.IsInf() { return new(big.Float).Copy(z) } // Pow(z, -w) = 1 / Pow(z, w) if w.Sign() < 0 { x := new(big.Float) zExt := new(big.Float).Copy(z).SetPrec(z.Prec() + 64) wNeg := new(big.Float).Neg(w) return x.Quo(big.NewFloat(1), Pow(zExt, wNeg)).SetPrec(z.Prec()) } // w integer fast path if w.IsInt() { wi, _ := w.Int64() return powInt(z, int(wi)) } // compute w**z as exp(z log(w)) x := new(big.Float).SetPrec(z.Prec() + 64) logZ := Log(new(big.Float).Copy(z).SetPrec(z.Prec() + 64)) x.Mul(w, logZ) x = Exp(x) return x.SetPrec(z.Prec()) }
// Evaluates a BBP term // // sum(k=0->inf)(1/base**k * (1/a*k + b)) func bbp(prec uint, base, a, b int64, result *big.Float) { var term, power, aFp, bFp, _1, k, _base, oldresult big.Float power.SetPrec(prec).SetInt64(1) result.SetPrec(prec).SetInt64(0) aFp.SetPrec(prec).SetInt64(a) bFp.SetPrec(prec).SetInt64(b) _1.SetPrec(prec).SetInt64(1) k.SetPrec(prec).SetInt64(0) _base.SetPrec(prec).SetInt64(base) for { oldresult.Set(result) term.Mul(&aFp, &k) term.Add(&term, &bFp) term.Quo(&_1, &term) term.Mul(&term, &power) result.Add(result, &term) if oldresult.Cmp(result) == 0 { break } power.Quo(&power, &_base) k.Add(&k, &_1) } }
// Returns acot(x) in result func acot(prec uint, x int64, result *big.Float) { var term, power, _x, _kp, x2, oldresult big.Float _x.SetPrec(prec).SetInt64(x) power.SetPrec(prec).SetInt64(1) power.Quo(&power, &_x) // 1/x x2.Mul(&_x, &_x) result.SetPrec(prec).SetInt64(0) positive := true for k := int64(1); ; k += 2 { oldresult.Set(result) kp := k if !positive { kp = -k } positive = !positive _kp.SetPrec(prec).SetInt64(kp) term.Quo(&power, &_kp) result.Add(result, &term) if oldresult.Cmp(result) == 0 { break } power.Quo(&power, &x2) } }
// Log returns a big.Float representation of the natural logarithm of // z. Precision is the same as the one of the argument. The function // panics if z is negative, returns -Inf when z = 0, and +Inf when z = // +Inf func Log(z *big.Float) *big.Float { // panic on negative z if z.Sign() == -1 { panic("Log: argument is negative") } // Log(0) = -Inf if z.Sign() == 0 { return big.NewFloat(math.Inf(-1)).SetPrec(z.Prec()) } prec := z.Prec() + 64 // guard digits one := big.NewFloat(1).SetPrec(prec) two := big.NewFloat(2).SetPrec(prec) four := big.NewFloat(4).SetPrec(prec) // Log(1) = 0 if z.Cmp(one) == 0 { return big.NewFloat(0).SetPrec(z.Prec()) } // Log(+Inf) = +Inf if z.IsInf() { return big.NewFloat(math.Inf(+1)).SetPrec(z.Prec()) } x := new(big.Float).SetPrec(prec) // if 0 < z < 1 we compute log(z) as -log(1/z) var neg bool if z.Cmp(one) < 0 { x.Quo(one, z) neg = true } else { x.Set(z) } // We scale up x until x >= 2**(prec/2), and then we'll be allowed // to use the AGM formula for Log(x). // // Double x until the condition is met, and keep track of the // number of doubling we did (needed to scale back later). lim := new(big.Float) lim.SetMantExp(two, int(prec/2)) k := 0 for x.Cmp(lim) < 0 { x.Mul(x, x) k++ } // Compute the natural log of x using the fact that // log(x) = π / (2 * AGM(1, 4/x)) // if // x >= 2**(prec/2), // where prec is the desired precision (in bits) pi := pi(prec) agm := agm(one, x.Quo(four, x)) // agm = AGM(1, 4/x) x.Quo(pi, x.Mul(two, agm)) // reuse x, we don't need it if neg { x.Neg(x) } // scale the result back multiplying by 2**-k // reuse lim to reduce allocations. x.Mul(x, lim.SetMantExp(one, -k)) return x.SetPrec(z.Prec()) }
func (f BigFloat) String() string { var mant big.Float exp := f.Float.MantExp(&mant) positive := 1 if exp < 0 { positive = 0 exp = -exp } verb, prec := byte('g'), 12 format := conf.Format() if format != "" { v, p, ok := conf.FloatFormat() if ok { verb, prec = v, p } } // Printing huge floats can be very slow using // big.Float's native methods; see issue #11068. // For example 1e5000000 takes a minute of CPU time just // to print. The code below is instantaneous, by rescaling // first. It is however less feature-complete. // (Big ints are problematic too, but if you print 1e50000000 // as an integer you probably won't be surprised it's slow.) if fastFloatPrint && exp > 10000 { // We always use %g to print the fraction, and it will // never have an exponent, but if the format is %E we // need to use a capital E. eChar := 'e' if verb == 'E' || verb == 'G' { eChar = 'E' } fexp := newF().SetInt64(int64(exp)) fexp.Mul(fexp, floatLog2) fexp.Quo(fexp, floatLog10) // We now have a floating-point base 10 exponent. // Break into the integer part and the fractional part. // The integer part is what we will show. // The 10**(fractional part) will be multiplied back in. iexp, _ := fexp.Int(nil) fraction := fexp.Sub(fexp, newF().SetInt(iexp)) // Now compute 10**(fractional part). // Fraction is in base 10. Move it to base e. fraction.Mul(fraction, floatLog10) scale := exponential(fraction) if positive > 0 { mant.Mul(&mant, scale) } else { mant.Quo(&mant, scale) } ten := newF().SetInt64(10) i64exp := iexp.Int64() // For numbers not too far from one, print without the E notation. // Shouldn't happen (exp must be large to get here) but just // in case, we keep this around. if -4 <= i64exp && i64exp <= 11 { if i64exp > 0 { for i := 0; i < int(i64exp); i++ { mant.Mul(&mant, ten) } } else { for i := 0; i < int(-i64exp); i++ { mant.Quo(&mant, ten) } } return fmt.Sprintf("%g\n", &mant) } else { sign := "" if mant.Sign() < 0 { sign = "-" mant.Neg(&mant) } // If it has a leading zero, rescale. digits := mant.Text('g', prec) for digits[0] == '0' { mant.Mul(&mant, ten) if positive > 0 { i64exp-- } else { i64exp++ } digits = mant.Text('g', prec) } return fmt.Sprintf("%s%s%c%c%d", sign, digits, eChar, "-+"[positive], i64exp) } } return f.Float.Text(verb, prec) }
func init() { unaryRoll = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { i := int64(v.(Int)) if i <= 0 { Errorf("illegal roll value %v", v) } return Int(conf.Origin()) + Int(conf.Random().Int63n(i)) }, bigIntType: func(v Value) Value { if v.(BigInt).Sign() <= 0 { Errorf("illegal roll value %v", v) } return unaryBigIntOp(bigIntRand, v) }, }, } unaryPlus = &unaryOp{ fn: [numType]unaryFn{ intType: self, bigIntType: self, bigRatType: self, bigFloatType: self, vectorType: self, matrixType: self, }, } unaryMinus = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return -v.(Int) }, bigIntType: func(v Value) Value { return unaryBigIntOp((*big.Int).Neg, v) }, bigRatType: func(v Value) Value { return unaryBigRatOp((*big.Rat).Neg, v) }, bigFloatType: func(v Value) Value { return unaryBigFloatOp((*big.Float).Neg, v) }, }, } unaryRecip = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { i := int64(v.(Int)) if i == 0 { Errorf("division by zero") } return BigRat{ Rat: big.NewRat(0, 1).SetFrac64(1, i), }.shrink() }, bigIntType: func(v Value) Value { // Zero division cannot happen for unary. return BigRat{ Rat: big.NewRat(0, 1).SetFrac(bigOne.Int, v.(BigInt).Int), }.shrink() }, bigRatType: func(v Value) Value { // Zero division cannot happen for unary. r := v.(BigRat) return BigRat{ Rat: big.NewRat(0, 1).SetFrac(r.Denom(), r.Num()), }.shrink() }, bigFloatType: func(v Value) Value { // Zero division cannot happen for unary. f := v.(BigFloat) one := new(big.Float).SetPrec(conf.FloatPrec()).SetInt64(1) return BigFloat{ Float: one.Quo(one, f.Float), }.shrink() }, }, } unarySignum = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { i := int64(v.(Int)) if i > 0 { return one } if i < 0 { return minusOne } return zero }, bigIntType: func(v Value) Value { return Int(v.(BigInt).Sign()) }, bigRatType: func(v Value) Value { return Int(v.(BigRat).Sign()) }, bigFloatType: func(v Value) Value { return Int(v.(BigFloat).Sign()) }, }, } unaryBitwiseNot = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return ^v.(Int) }, bigIntType: func(v Value) Value { // Lots of ways to do this, here's one. return BigInt{Int: bigInt64(0).Xor(v.(BigInt).Int, bigMinusOne.Int)} }, }, } unaryLogicalNot = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { if v.(Int) == 0 { return one } return zero }, bigIntType: func(v Value) Value { if v.(BigInt).Sign() == 0 { return one } return zero }, bigRatType: func(v Value) Value { if v.(BigRat).Sign() == 0 { return one } return zero }, bigFloatType: func(v Value) Value { if v.(BigFloat).Sign() == 0 { return one } return zero }, }, } unaryAbs = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { i := v.(Int) if i < 0 { i = -i } return i }, bigIntType: func(v Value) Value { return unaryBigIntOp((*big.Int).Abs, v) }, bigRatType: func(v Value) Value { return unaryBigRatOp((*big.Rat).Abs, v) }, bigFloatType: func(v Value) Value { return unaryBigFloatOp((*big.Float).Abs, v) }, }, } floor = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return v }, bigIntType: func(v Value) Value { return v }, bigRatType: func(v Value) Value { i := v.(BigRat) if i.IsInt() { // It can't be an integer, which means we must move up or down. panic("min: is int") } positive := i.Sign() >= 0 if !positive { j := bigRatInt64(0) j.Abs(i.Rat) i = j } z := bigInt64(0) z.Quo(i.Num(), i.Denom()) if !positive { z.Add(z.Int, bigOne.Int) z.Neg(z.Int) } return z }, bigFloatType: func(v Value) Value { f := v.(BigFloat) i, acc := f.Int(nil) switch acc { case big.Exact, big.Below: // Done. case big.Above: i.Sub(i, bigOne.Int) } return BigInt{i}.shrink() }, }, } ceil = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return v }, bigIntType: func(v Value) Value { return v }, bigRatType: func(v Value) Value { i := v.(BigRat) if i.IsInt() { // It can't be an integer, which means we must move up or down. panic("max: is int") } positive := i.Sign() >= 0 if !positive { j := bigRatInt64(0) j.Abs(i.Rat) i = j } z := bigInt64(0) z.Quo(i.Num(), i.Denom()) if positive { z.Add(z.Int, bigOne.Int) } else { z.Neg(z.Int) } return z }, bigFloatType: func(v Value) Value { f := v.(BigFloat) i, acc := f.Int(nil) switch acc { case big.Exact, big.Above: // Done case big.Below: i.Add(i, bigOne.Int) } return BigInt{i}.shrink() }, }, } unaryIota = &unaryOp{ fn: [numType]unaryFn{ intType: func(v Value) Value { i := v.(Int) if i < 0 || maxInt < i { Errorf("bad iota %d", i) } if i == 0 { return Vector{} } n := make([]Value, i) for k := range n { n[k] = Int(k + conf.Origin()) } return NewVector(n) }, }, } unaryRho = &unaryOp{ fn: [numType]unaryFn{ intType: func(v Value) Value { return Vector{} }, charType: func(v Value) Value { return Vector{} }, bigIntType: func(v Value) Value { return Vector{} }, bigRatType: func(v Value) Value { return Vector{} }, bigFloatType: func(v Value) Value { return Vector{} }, vectorType: func(v Value) Value { return Int(len(v.(Vector))) }, matrixType: func(v Value) Value { return v.(Matrix).shape }, }, } unaryRavel = &unaryOp{ fn: [numType]unaryFn{ intType: vectorSelf, charType: vectorSelf, bigIntType: vectorSelf, bigRatType: vectorSelf, bigFloatType: vectorSelf, vectorType: self, matrixType: func(v Value) Value { return v.(Matrix).data }, }, } gradeUp = &unaryOp{ fn: [numType]unaryFn{ intType: self, charType: self, bigIntType: self, bigRatType: self, bigFloatType: self, vectorType: func(v Value) Value { return v.(Vector).grade() }, }, } gradeDown = &unaryOp{ fn: [numType]unaryFn{ intType: self, charType: self, bigIntType: self, bigRatType: self, bigFloatType: self, vectorType: func(v Value) Value { x := v.(Vector).grade() for i, j := 0, len(x)-1; i < j; i, j = i+1, j-1 { x[i], x[j] = x[j], x[i] } return x }, }, } reverse = &unaryOp{ fn: [numType]unaryFn{ intType: self, charType: self, bigIntType: self, bigRatType: self, bigFloatType: self, vectorType: func(v Value) Value { x := v.(Vector) for i, j := 0, len(x)-1; i < j; i, j = i+1, j-1 { x[i], x[j] = x[j], x[i] } return x }, matrixType: func(v Value) Value { m := v.(Matrix) if len(m.shape) == 0 { return m } if len(m.shape) == 1 { Errorf("rev: matrix is vector") } size := m.size() ncols := int(m.shape[len(m.shape)-1].(Int)) x := m.data for index := 0; index <= size-ncols; index += ncols { for i, j := 0, ncols-1; i < j; i, j = i+1, j-1 { x[index+i], x[index+j] = x[index+j], x[index+i] } } return m }, }, } flip = &unaryOp{ fn: [numType]unaryFn{ intType: self, charType: self, bigIntType: self, bigRatType: self, bigFloatType: self, vectorType: func(v Value) Value { return Unary("rev", v) }, matrixType: func(v Value) Value { m := v.(Matrix) if len(m.shape) == 0 { return m } if len(m.shape) == 1 { Errorf("flip: matrix is vector") } elemSize := m.elemSize() size := m.size() x := m.data lo := 0 hi := size - elemSize for lo < hi { for i := 0; i < elemSize; i++ { x[lo+i], x[hi+i] = x[hi+i], x[lo+i] } lo += elemSize hi -= elemSize } return m }, }, } unaryCos = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return cos(v) }, bigIntType: func(v Value) Value { return cos(v) }, bigRatType: func(v Value) Value { return cos(v) }, bigFloatType: func(v Value) Value { return cos(v) }, }, } unaryLog = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return logn(v) }, bigIntType: func(v Value) Value { return logn(v) }, bigRatType: func(v Value) Value { return logn(v) }, bigFloatType: func(v Value) Value { return logn(v) }, }, } unarySin = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return sin(v) }, bigIntType: func(v Value) Value { return sin(v) }, bigRatType: func(v Value) Value { return sin(v) }, bigFloatType: func(v Value) Value { return sin(v) }, }, } unaryTan = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return tan(v) }, bigIntType: func(v Value) Value { return tan(v) }, bigRatType: func(v Value) Value { return tan(v) }, bigFloatType: func(v Value) Value { return tan(v) }, }, } unaryAsin = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return asin(v) }, bigIntType: func(v Value) Value { return asin(v) }, bigRatType: func(v Value) Value { return asin(v) }, bigFloatType: func(v Value) Value { return asin(v) }, }, } unaryAcos = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return acos(v) }, bigIntType: func(v Value) Value { return acos(v) }, bigRatType: func(v Value) Value { return acos(v) }, bigFloatType: func(v Value) Value { return acos(v) }, }, } unaryAtan = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return atan(v) }, bigIntType: func(v Value) Value { return atan(v) }, bigRatType: func(v Value) Value { return atan(v) }, bigFloatType: func(v Value) Value { return atan(v) }, }, } unaryExp = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return exp(v) }, bigIntType: func(v Value) Value { return exp(v) }, bigRatType: func(v Value) Value { return exp(v) }, bigFloatType: func(v Value) Value { return exp(v) }, }, } unarySqrt = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return sqrt(v) }, bigIntType: func(v Value) Value { return sqrt(v) }, bigRatType: func(v Value) Value { return sqrt(v) }, bigFloatType: func(v Value) Value { return sqrt(v) }, }, } unaryChar = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: func(v Value) Value { return Char(v.(Int)).validate() }, }, } unaryCode = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ charType: func(v Value) Value { return Int(v.(Char)) }, }, } unaryText = &unaryOp{ fn: [numType]unaryFn{ intType: func(v Value) Value { return text(v) }, bigIntType: func(v Value) Value { return text(v) }, bigRatType: func(v Value) Value { return text(v) }, bigFloatType: func(v Value) Value { return text(v) }, vectorType: func(v Value) Value { return text(v) }, matrixType: func(v Value) Value { return text(v) }, }, } unaryIvy = &unaryOp{ fn: [numType]unaryFn{ vectorType: func(v Value) Value { text := v.(Vector) if !text.allChars() { Errorf("ivy: value is not a vector of char") } return IvyEval(context, text.makeString(false)) }, }, } unaryFloat = &unaryOp{ elementwise: true, fn: [numType]unaryFn{ intType: floatSelf, bigIntType: floatSelf, bigRatType: floatSelf, bigFloatType: floatSelf, }, } unaryOps = map[string]*unaryOp{ "**": unaryExp, "+": unaryPlus, ",": unaryRavel, "-": unaryMinus, "/": unaryRecip, "?": unaryRoll, "^": unaryBitwiseNot, "abs": unaryAbs, "acos": unaryAcos, "asin": unaryAsin, "atan": unaryAtan, "ceil": ceil, "char": unaryChar, "code": unaryCode, "cos": unaryCos, "down": gradeDown, "flip": flip, "float": unaryFloat, "floor": floor, "iota": unaryIota, "ivy": unaryIvy, "log": unaryLog, "rev": reverse, "rho": unaryRho, "sin": unarySin, "sgn": unarySignum, "sqrt": unarySqrt, "tan": unaryTan, "text": unaryText, "up": gradeUp, "~": unaryLogicalNot, } }
// Given a vector of real numbers x = [x_0, x_1, ..., x_n], this // uses the PSLQ algorithm to find a list of integers // [c_0, c_1, ..., c_n] such that // // |c_1 * x_1 + c_2 * x_2 + ... + c_n * x_n| < tolerance // // and such that max |c_k| < maxcoeff. If no such vector exists, Pslq // returns one of the errors in this package depending on whether it // has run out of iterations, precision or explored up to the // maxcoeff. The tolerance defaults to 3/4 of the precision. // // This is a fairly direct translation of the pseudocode given by // David Bailey, "The PSLQ Integer Relation Algorithm": // http://www.cecm.sfu.ca/organics/papers/bailey/paper/html/node3.html // // If a result is returned, the first non-zero element will be positive func (e *Pslq) Run(x []big.Float) ([]big.Int, error) { n := len(x) if n <= 1 { return nil, ErrorBadArguments } // At too low precision, the algorithm becomes meaningless if e.prec < 64 { return nil, ErrorPrecisionTooLow } if e.verbose && int(e.prec)/max(2, int(n)) < 5 { log.Printf("Warning: precision for PSLQ may be too low") } if e.verbose { log.Printf("PSLQ using prec %d and tol %g", e.prec, e.tol) } if e.tol.Sign() == 0 { return nil, ErrorToleranceRoundsToZero } // Temporary variables tmp0 := new(big.Float).SetPrec(e.prec) tmp1 := new(big.Float).SetPrec(e.prec) bigTmp := new(big.Int) // Convert to use 1-based indexing to allow us to be // consistent with Bailey's indexing. xNew := make([]big.Float, len(x)+1) minx := new(big.Float).SetPrec(e.prec) minxFirst := true for i, xk := range x { p := &xNew[i+1] p.Set(&xk) tmp0.Abs(p) if minxFirst || tmp0.Cmp(minx) < 0 { minxFirst = false minx.Set(tmp0) } } x = xNew if debug { printVector("x", x) } // Sanity check on magnitudes if minx.Sign() == 0 { return nil, ErrorZeroArguments } tmp1.SetInt64(128) tmp0.Quo(&e.tol, tmp1) if minx.Cmp(tmp0) < 0 { // minx < tol/128 return nil, ErrorArgumentTooSmall } tmp0.SetInt64(4) tmp1.SetInt64(3) tmp0.Quo(tmp0, tmp1) var γ big.Float e.Sqrt(tmp0, &γ) // sqrt(4<<prec)/3) if debug { fmt.Printf("γ = %f\n", &γ) } A := newBigIntMatrix(n+1, n+1) B := newBigIntMatrix(n+1, n+1) H := newMatrix(n+1, n+1) // Initialization Step 1 // // Set the n×n matrices A and B to the identity. for i := 1; i <= n; i++ { for j := 1; j <= n; j++ { if i == j { A[i][j].SetInt64(1) B[i][j].SetInt64(1) } else { A[i][j].SetInt64(0) B[i][j].SetInt64(0) } H[i][j].SetInt64(0) } } if debug { printBigIntMatrix("A", A) printBigIntMatrix("B", B) printMatrix("H", H) } // Initialization Step 2 // // For k := 1 to n // compute s_k := sqrt( sum_j=k^n x_j^2 ) // endfor. // Set t = 1/s1. // For k := 1 to n: // y_k := t * x_k // s_k := t * s_k // endfor. s := make([]big.Float, n+1) for i := 1; i <= n; i++ { s[i].SetInt64(0) } for k := 1; k <= n; k++ { var t big.Float t.SetInt64(0) for j := k; j <= n; j++ { tmp0.Mul(&x[j], &x[j]) t.Add(&t, tmp0) } e.Sqrt(&t, &s[k]) } if debug { fmt.Println("Init Step 2") printVector("s", s) } var t big.Float t.Set(&s[1]) y := make([]big.Float, len(x)) copy(y, x) for k := 1; k <= n; k++ { // y[k] = (x[k] << prec) / t y[k].Quo(&x[k], &t) // s[k] = (s[k] << prec) / t s[k].Quo(&s[k], &t) } if debug { printVector("y", y) printVector("s", s) } // Init Step 3 // // Compute the n×(n−1) matrix H as follows: // For i := 1 to n: // for j := i + 1 to n − 1: // set Hij := 0 // endfor // if i ≤ n − 1 then set Hii := s_(i+1)/s_i // for j := 1 to i−1: // set Hij := −y_i * y_j / (s_j * s_(j+1)) // endfor // endfor for i := 1; i <= n; i++ { for j := i + 1; j < n; j++ { H[i][j].SetInt64(0) } if i <= n-1 { if s[i].Sign() == 0 { // Precision probably exhausted return nil, ErrorPrecisionExhausted } // H[i][i] = (s[i+1] << prec) / s[i] H[i][i].Quo(&s[i+1], &s[i]) } for j := 1; j < i; j++ { var sjj1 big.Float sjj1.Mul(&s[j], &s[j+1]) if debug { fmt.Printf("sjj1 = %f\n", &sjj1) } if sjj1.Sign() == 0 { // Precision probably exhausted return nil, ErrorPrecisionExhausted } // H[i][j] = ((-y[i] * y[j]) << prec) / sjj1 tmp0.Mul(&y[i], &y[j]) tmp0.Neg(tmp0) H[i][j].Quo(tmp0, &sjj1) } } if debug { fmt.Println("Init Step 3") printMatrix("H", H) } // Init Step 4 // // Perform full reduction on H, simultaneously updating y, A and B: // // For i := 2 to n: // for j := i−1 to 1 step−1: // t := nint(Hij/Hjj) // y_j := y_j + t * y_i // for k := 1 to j: // Hik := Hik − t * Hjk // endfor // for k := 1 to n: // Aik := Aik − t * Ajk // Bkj := Bkj + t * Bki // endfor // endfor // endfor for i := 2; i <= n; i++ { for j := i - 1; j > 0; j-- { //t = floor(H[i][j]/H[j,j] + 0.5) var t big.Int var tFloat big.Float if H[j][j].Sign() == 0 { // Precision probably exhausted return nil, ErrorPrecisionExhausted } tmp0.Quo(&H[i][j], &H[j][j]) e.NearestInt(tmp0, &t) tFloat.SetInt(&t).SetPrec(e.prec) if debug { fmt.Printf("H[i][j]=%f\n", &H[i][j]) fmt.Printf("H[j][j]=%f\n", &H[j][j]) fmt.Printf("tmp=%f\n", tmp0) fmt.Printf("t=%d\n", &t) } // y[j] = y[j] + (t * y[i] >> prec) tmp0.Mul(&y[i], &tFloat) y[j].Add(&y[j], tmp0) for k := 1; k <= j; k++ { // H[i][k] = H[i][k] - (t * H[j][k] >> prec) tmp0.Mul(&H[j][k], &tFloat) H[i][k].Sub(&H[i][k], tmp0) } for k := 1; k <= n; k++ { bigTmp.Mul(&t, &A[j][k]) A[i][k].Sub(&A[i][k], bigTmp) bigTmp.Mul(&t, &B[k][i]) B[k][j].Add(&B[k][j], bigTmp) } } } if debug { fmt.Println("Init Step 4") printBigIntMatrix("A", A) printBigIntMatrix("B", B) printMatrix("H", H) } // Main algorithm var REP int var norm big.Int vec := make([]big.Int, n) for REP = 0; REP < e.maxsteps; REP++ { // Step 1 // // Select m such that γ^i * |Hii| is maximal when i = m. m := -1 var szmax big.Float szmax.SetInt64(-1) var γPower big.Float γPower.Set(&γ) for i := 1; i < n; i++ { var absH big.Float absH.Abs(&H[i][i]) var sz big.Float sz.Mul(&γPower, &absH) // sz := (g**i * abs(h)) >> (prec * (i - 1)) if sz.Cmp(&szmax) > 0 { m = i szmax.Set(&sz) } γPower.Mul(&γPower, &γ) } if debug { fmt.Println("Step 1") fmt.Printf("szmax=%f\n", &szmax) fmt.Printf("m=%d\n", m) } // Step 2 // // Exchange entries m and m+1 of y, corresponding rows // of A and H, and corresponding columns of B. y[m], y[m+1] = y[m+1], y[m] for i := 1; i < n+1; i++ { H[m][i], H[m+1][i] = H[m+1][i], H[m][i] } for i := 1; i < n+1; i++ { A[m][i], A[m+1][i] = A[m+1][i], A[m][i] } for i := 1; i < n+1; i++ { B[i][m], B[i][m+1] = B[i][m+1], B[i][m] } if debug { fmt.Println("Step 2") printVector("y", y) printBigIntMatrix("A", A) printBigIntMatrix("B", B) printMatrix("H", H) } // Step 3 // // If m ≤ n−2 then update H as follows: // // t0 := sqrt( Hmm^2 + H(m,m+1)^2 ) // t1 := Hmm/t0 // t2 := H(m,m+1)/t0. // for i := m to n: // t3 := Him // t4 := Hi,m+1 // Him := t1t3 +t2t4 // Hi,m+1 := −t2t3 +t1t4 // endfor. if m <= n-2 { tmp0.Mul(&H[m][m], &H[m][m]) tmp1.Mul(&H[m][m+1], &H[m][m+1]) tmp0.Add(tmp0, tmp1) var t0 big.Float e.Sqrt(tmp0, &t0) // Precision probably exhausted if t0.Sign() == 0 { return nil, ErrorPrecisionExhausted } var t1, t2 big.Float t1.Quo(&H[m][m], &t0) t2.Quo(&H[m][m+1], &t0) for i := m; i <= n; i++ { var t3, t4 big.Float t3.Set(&H[i][m]) t4.Set(&H[i][m+1]) // H[i][m] = (t1*t3 + t2*t4) >> prec tmp0.Mul(&t1, &t3) tmp1.Mul(&t2, &t4) H[i][m].Add(tmp0, tmp1) // H[i][m+1] = (-t2*t3 + t1*t4) >> prec tmp0.Mul(&t2, &t3) tmp1.Mul(&t1, &t4) H[i][m+1].Sub(tmp1, tmp0) } } if debug { fmt.Println("Step 3") printMatrix("H", H) } // Step 4 // Perform block reduction on H, simultaneously updating y, A and B: // // For i := m+1 to n: // for j := min(i−1, m+1) to 1 step −1: // t := nint(Hij/Hjj) // yj := yj + t * yi // for k := 1 to j: // Hik := Hik − tHjk // endfor // for k := 1 to n: // Aik := Aik −tAjk // Bkj := Bkj +tBki // endfor // endfor // endfor. for i := m + 1; i <= n; i++ { var t big.Int var tFloat big.Float for j := min(i-1, m+1); j > 0; j-- { if H[j][j].Sign() == 0 { // Precision probably exhausted return nil, ErrorPrecisionExhausted } tmp0.Quo(&H[i][j], &H[j][j]) e.NearestInt(tmp0, &t) tFloat.SetInt(&t).SetPrec(e.prec) // y[j] = y[j] + ((t * y[i]) >> prec) tmp0.Mul(&y[i], &tFloat) y[j].Add(&y[j], tmp0) for k := 1; k <= j; k++ { // H[i][k] = H[i][k] - (t * H[j][k] >> prec) tmp0.Mul(&H[j][k], &tFloat) H[i][k].Sub(&H[i][k], tmp0) } for k := 1; k <= n; k++ { bigTmp.Mul(&t, &A[j][k]) A[i][k].Sub(&A[i][k], bigTmp) bigTmp.Mul(&t, &B[k][i]) B[k][j].Add(&B[k][j], bigTmp) } } } if debug { fmt.Println("Step 4") printBigIntMatrix("A", A) printBigIntMatrix("B", B) printMatrix("H", H) } // Step 6 // // Termination test: If the largest entry of A exceeds // the level of numeric precision used, then precision // is exhausted. If the smallest entry of the y vector // is less than the detection threshold, a relation // has been detected and is given in the corresponding // column of B. // // Until a relation is found, the error typically decreases // slowly (e.g. a factor 1-10) with each step TODO: we could // compare err from two successive iterations. If there is a // large drop (several orders of magnitude), that indicates a // "high quality" relation was detected. Reporting this to // the user somehow might be useful. maxAPrecision := 0 for i := 1; i <= n; i++ { for j := 1; j <= n; j++ { precision := A[i][j].BitLen() if precision > maxAPrecision { maxAPrecision = precision } } } if debug { log.Printf("Max A precision = %d, precision = %d, tolerance %d, ratio = %.3f\n", maxAPrecision, e.prec, e.target, float64(maxAPrecision)/float64(e.target)) } if float64(maxAPrecision)/float64(e.target) > 0.85 { if e.verbose { log.Printf("CANCELLING after step %d/%d.", REP, e.maxsteps) } return nil, ErrorPrecisionExhausted } var best_err big.Float best_err.Set(&e.maxcoeff_fp) for i := 1; i <= n; i++ { var err big.Float err.Abs(&y[i]) // Maybe we are done? if err.Cmp(&e.tol) < 0 { // We are done if the coefficients are acceptable var maxc big.Int for j := 1; j <= n; j++ { if debug { fmt.Printf("vec[%d]=%d\n", j-1, &B[j][i]) } t := B[j][i] if debug { fmt.Printf("vec[%d]=%d\n", j-1, t) } vec[j-1] = t if t.Sign() < 0 { t.Neg(&t) } if t.Cmp(&maxc) > 0 { maxc.Set(&t) } } if debug { fmt.Printf("maxc = %d, maxcoeff = %d\n", maxc, e.maxcoeff) } if maxc.Cmp(&e.maxcoeff) < 0 { if e.verbose { log.Printf("FOUND relation at iter %d/%d, error: %g", REP, e.maxsteps, &err) } // Find sign of first non zero item sign := 0 for i := range vec { sign = vec[i].Sign() if sign != 0 { break } } // Normalise vec making first non-zero argument positive if sign < 0 { for i := range vec { vec[i].Neg(&vec[i]) } } return vec, nil } } if err.Cmp(&best_err) < 0 { best_err = err } } // Step 5 // // Norm bound: Compute M := 1/maxj |Hj|, where Hj // denotes the j-th row of H. // // Then there can exist no relation vector whose // Euclidean norm is less than M. // // Calculate a lower bound for the norm. We could do this // more exactly (using the Euclidean norm) but there is probably // no practical benefit. var recnorm big.Float recnorm.SetInt64(0) for i := 1; i <= n; i++ { for j := 1; j <= n; j++ { tmp0.Abs(&H[i][j]) if tmp0.Cmp(&recnorm) > 0 { recnorm.Set(tmp0) } } } norm.Set(&e.maxcoeff) if recnorm.Sign() != 0 { // norm = ((1 << (2 * prec)) / recnorm) >> prec tmp0.Quo(&e.one, &recnorm) tmp0.Int(&norm) } if e.verbose { log.Printf("%2d/%2d: Error: %g Norm: %d", REP, e.maxsteps, &best_err, &norm) } if norm.Cmp(&e.maxcoeff) >= 0 { if e.verbose { log.Printf("CANCELLING after step %d/%d.", REP, e.maxsteps) log.Printf("Could not find an integer relation. Norm bound: %d", &norm) } return nil, ErrorNoRelationFound } } if e.verbose { log.Printf("CANCELLING after step %d/%d.", REP, e.maxsteps) log.Printf("Could not find an integer relation. Norm bound: %d", &norm) } return nil, ErrorIterationsExceeded }