ExpTaylor calculates the natural exponent of decimal (e to the power of d) using Taylor series expansion. Precision argument specifies how precise the result must be (number of digits after decimal point). Negative precision is allowed. ExpTaylor is much faster for large precision values than ExpHu
(precision int32)
| 1052 | // NewFromFloat(26.1).ExpTaylor(-10).String() |
| 1053 | // d.String() // output: "220000000000" |
| 1054 | func (d Decimal) ExpTaylor(precision int32) (Decimal, error) { |
| 1055 | // Note(mwoss): Implementation can be optimized by exclusively using big.Int API only |
| 1056 | if d.IsZero() { |
| 1057 | return Decimal{oneInt, 0}.Round(precision), nil |
| 1058 | } |
| 1059 | |
| 1060 | var epsilon Decimal |
| 1061 | var divPrecision int32 |
| 1062 | if precision < 0 { |
| 1063 | epsilon = New(1, -1) |
| 1064 | divPrecision = 8 |
| 1065 | } else { |
| 1066 | epsilon = New(1, -precision-1) |
| 1067 | divPrecision = precision + 1 |
| 1068 | } |
| 1069 | |
| 1070 | decAbs := d.Abs() |
| 1071 | pow := d.Abs() |
| 1072 | factorial := New(1, 0) |
| 1073 | |
| 1074 | result := New(1, 0) |
| 1075 | |
| 1076 | for i := int64(1); ; { |
| 1077 | step := pow.DivRound(factorial, divPrecision) |
| 1078 | result = result.Add(step) |
| 1079 | |
| 1080 | // Stop Taylor series when current step is smaller than epsilon |
| 1081 | if step.Cmp(epsilon) < 0 { |
| 1082 | break |
| 1083 | } |
| 1084 | |
| 1085 | pow = pow.Mul(decAbs) |
| 1086 | |
| 1087 | i++ |
| 1088 | |
| 1089 | // Calculate next factorial number or retrieve cached value |
| 1090 | if len(factorials) >= int(i) && !factorials[i-1].IsZero() { |
| 1091 | factorial = factorials[i-1] |
| 1092 | } else { |
| 1093 | // To avoid any race conditions, firstly the zero value is appended to a slice to create |
| 1094 | // a spot for newly calculated factorial. After that, the zero value is replaced by calculated |
| 1095 | // factorial using the index notation. |
| 1096 | factorial = factorials[i-2].Mul(New(i, 0)) |
| 1097 | factorials = append(factorials, Zero) |
| 1098 | factorials[i-1] = factorial |
| 1099 | } |
| 1100 | } |
| 1101 | |
| 1102 | if d.Sign() < 0 { |
| 1103 | result = New(1, 0).DivRound(result, precision+1) |
| 1104 | } |
| 1105 | |
| 1106 | result = result.Round(precision) |
| 1107 | return result, nil |
| 1108 | } |
| 1109 | |
| 1110 | // Ln calculates natural logarithm of d. |
| 1111 | // Precision argument specifies how precise the result must be (number of digits after decimal point). |