MCPcopy
hub / github.com/shopspring/decimal / Ln

Method Ln

decimal.go:1121–1236  ·  view source on GitHub ↗

Ln calculates natural logarithm of d. Precision argument specifies how precise the result must be (number of digits after decimal point). Negative precision is allowed. Example: d1, err := NewFromFloat(13.3).Ln(2) d1.String() // output: "2.59" d2, err := NewFromFloat(579.161).Ln(10) d2.Strin

(precision int32)

Source from the content-addressed store, hash-verified

1119// d2, err := NewFromFloat(579.161).Ln(10)
1120// d2.String() // output: "6.3615805046"
1121func (d Decimal) Ln(precision int32) (Decimal, error) {
1122 // Algorithm based on The Use of Iteration Methods for Approximating the Natural Logarithm,
1123 // James F. Epperson, The American Mathematical Monthly, Vol. 96, No. 9, November 1989, pp. 831-835.
1124 if d.IsNegative() {
1125 return Decimal{}, fmt.Errorf("cannot calculate natural logarithm for negative decimals")
1126 }
1127
1128 if d.IsZero() {
1129 return Decimal{}, fmt.Errorf("cannot represent natural logarithm of 0, result: -infinity")
1130 }
1131
1132 calcPrecision := precision + 2
1133 z := d.Copy()
1134
1135 var comp1, comp3, comp2, comp4, reduceAdjust Decimal
1136 comp1 = z.Sub(Decimal{oneInt, 0})
1137 comp3 = Decimal{oneInt, -1}
1138
1139 // for decimal in range [0.9, 1.1] where ln(d) is close to 0
1140 usePowerSeries := false
1141
1142 if comp1.Abs().Cmp(comp3) <= 0 {
1143 usePowerSeries = true
1144 } else {
1145 // reduce input decimal to range [0.1, 1)
1146 expDelta := int32(z.NumDigits()) + z.exp
1147 z.exp -= expDelta
1148
1149 // Input decimal was reduced by factor of 10^expDelta, thus we will need to add
1150 // ln(10^expDelta) = expDelta * ln(10)
1151 // to the result to compensate that
1152 ln10 := ln10.withPrecision(calcPrecision)
1153 reduceAdjust = NewFromInt32(expDelta)
1154 reduceAdjust = reduceAdjust.Mul(ln10)
1155
1156 comp1 = z.Sub(Decimal{oneInt, 0})
1157
1158 if comp1.Abs().Cmp(comp3) <= 0 {
1159 usePowerSeries = true
1160 } else {
1161 // initial estimate using floats
1162 zFloat := z.InexactFloat64()
1163 comp1 = NewFromFloat(math.Log(zFloat))
1164 }
1165 }
1166
1167 epsilon := Decimal{oneInt, -calcPrecision}
1168
1169 if usePowerSeries {
1170 // Power Series - https://en.wikipedia.org/wiki/Logarithm#Power_series
1171 // Calculating n-th term of formula: ln(z+1) = 2 sum [ 1 / (2n+1) * (z / (z+2))^(2n+1) ]
1172 // until the difference between current and next term is smaller than epsilon.
1173 // Coverage quite fast for decimals close to 1.0
1174
1175 // z + 2
1176 comp2 = comp1.Add(Decimal{twoInt, 0})
1177 // z / (z + 2)
1178 comp3 = comp1.DivRound(comp2, calcPrecision)

Callers 5

TestDecimal_LnFunction · 0.80
TestDecimal_LnZeroFunction · 0.80
TestDecimal_LnNegativeFunction · 0.80
PowMethod · 0.80
PowWithPrecisionMethod · 0.80

Calls 15

IsNegativeMethod · 0.95
IsZeroMethod · 0.95
CopyMethod · 0.95
SubMethod · 0.95
AbsMethod · 0.95
MulMethod · 0.95
AddMethod · 0.95
DivRoundMethod · 0.95
ExpTaylorMethod · 0.95
RoundMethod · 0.95
NewFromInt32Function · 0.85
NewFromFloatFunction · 0.85

Tested by 3

TestDecimal_LnFunction · 0.64
TestDecimal_LnZeroFunction · 0.64
TestDecimal_LnNegativeFunction · 0.64