forked from ALTree/bigfloat
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlog.go
81 lines (70 loc) · 1.82 KB
/
log.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
package bigfloat
import (
"math/big"
)
// Log sets o to z's natural logarithm to o's precision and returns o. Panics
// with ErrNaN if z is negative, including -0; returns -Inf when z = +0, and
// +Inf when z = +Inf. If o's precision is zero, then it is given the
// precision of z.
func Log(o, z *big.Float) *big.Float {
if o.Prec() == 0 {
o.SetPrec(z.Prec())
}
// panic on negative z
if z.Signbit() {
panic(ErrNaN{msg: "Log: argument is negative"})
}
// Log(0) = -Inf
if z.Sign() == 0 {
return o.SetInf(true)
}
// Log(+Inf) = +Inf
if z.IsInf() {
return o.Set(z)
}
prec := o.Prec() + 64 // guard digits
one := big.NewFloat(1).SetPrec(prec)
two := big.NewFloat(2).SetPrec(prec)
four := big.NewFloat(4).SetPrec(prec)
var neg bool
switch z.Cmp(one) {
case 1:
o.SetPrec(prec).Set(z)
case -1:
// if 0 < z < 1 we compute log(z) as -log(1/z)
o.SetPrec(prec).Quo(one, z)
neg = true
case 0:
// Log(1) = 0
return o.Set(&gzero)
default:
panic("bigfloat: unexpected comparison result, not 0, 1, or -1")
}
// 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 o.Cmp(lim) < 0 {
o.Mul(o, o)
k++
}
// Compute the natural log of z using the fact that
// log(z) = π / (2 * AGM(1, 4/z))
// if
// z >= 2**(prec/2),
// where prec is the desired precision (in bits)
pi := cachedPi(prec)
agm := AGM(new(big.Float), one, o.Quo(four, o)) // agm = AGM(1, 4/z)
o.Quo(pi, o.Mul(two, agm))
if neg {
o.Neg(o)
}
// scale the result back multiplying by 2**-k
// reuse lim to reduce allocations.
o.Mul(o, lim.SetMantExp(one, -k))
return o.SetPrec(prec - 64)
}