Skip to content

Commit f38aaf8

Browse files
authored
feat: add ln and log (#12)
* add Ln and Log
1 parent 2569144 commit f38aaf8

File tree

3 files changed

+82
-4
lines changed

3 files changed

+82
-4
lines changed

function.go

+32
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ var builtInFunctions = map[string]FunctionalValue{
6262
"sqrt": Sqrt,
6363
"floor": Floor,
6464
"trunc": Trunc,
65+
"ln": Ln,
66+
"log": Log,
6567
}
6668

6769
// BuiltInFunction returns a built-in function body if known.
@@ -162,6 +164,36 @@ func Tan(args ...Value) Value {
162164
return NewUndefinedWithReasonf("tan(): invalid argument type '%s'", args[0].String())
163165
}
164166

167+
// Ln returns the natural logarithm of d.
168+
func Ln(args ...Value) Value {
169+
if len(args) != 2 {
170+
return NewUndefinedWithReasonf("ln() requires 2 arguments, got %d", len(args))
171+
}
172+
173+
if v, ok := args[0].(Numberer); ok {
174+
if p, ok := args[1].(Numberer); ok {
175+
return v.Number().Ln(int32(p.Number().value.IntPart()))
176+
}
177+
}
178+
179+
return NewUndefinedWithReasonf("ln(): invalid argument type '%s'", args[0].String())
180+
}
181+
182+
// Log returns the logarithm base 10 of d.
183+
func Log(args ...Value) Value {
184+
if len(args) != 2 {
185+
return NewUndefinedWithReasonf("log() requires 2 arguments, got %d", len(args))
186+
}
187+
188+
if v, ok := args[0].(Numberer); ok {
189+
if p, ok := args[1].(Numberer); ok {
190+
return v.Number().Log(int32(p.Number().value.IntPart()))
191+
}
192+
}
193+
194+
return NewUndefinedWithReasonf("log(): invalid argument type '%s'", args[0].String())
195+
}
196+
165197
// Sqrt returns the square root.
166198
func Sqrt(args ...Value) Value {
167199
if len(args) != 1 {

function_test.go

+19
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ func TestFactorial(t *testing.T) {
2828

2929
val = gal.Factorial(gal.NewNumber(10))
3030
assert.Equal(t, gal.NewNumber(3_628_800).String(), val.String())
31+
32+
val = gal.Factorial(gal.NewNumber(-10))
33+
assert.Equal(t, "undefined: Factorial: requires a positive integer, cannot accept -10", val.String())
3134
}
3235

3336
func TestCos(t *testing.T) {
@@ -54,3 +57,19 @@ func TestFloor(t *testing.T) {
5457
val := gal.Floor(gal.NewNumberFromFloat(0.0))
5558
assert.Equal(t, int64(0), gal.ToNumber(val).Int64())
5659
}
60+
61+
func TestLn(t *testing.T) {
62+
val := gal.Ln(gal.NewNumber(123456), gal.NewNumber(5))
63+
assert.Equal(t, "11.72364", val.String())
64+
65+
val = gal.Ln(gal.NewNumber(-123456), gal.NewNumber(5))
66+
assert.Equal(t, "undefined: Ln:cannot calculate natural logarithm for negative decimals", val.String())
67+
}
68+
69+
func TestLog(t *testing.T) {
70+
val := gal.Log(gal.NewNumber(123456), gal.NewNumber(5))
71+
assert.Equal(t, "5.09152", val.String())
72+
73+
val = gal.Log(gal.NewNumber(-123456), gal.NewNumber(5))
74+
assert.Equal(t, "undefined: Log:cannot calculate natural logarithm for negative decimals", val.String())
75+
}

value.go

+31-4
Original file line numberDiff line numberDiff line change
@@ -343,12 +343,12 @@ func (n Number) Cos() Number {
343343
}
344344
}
345345

346-
func (n Number) Sqrt() Number {
346+
func (n Number) Sqrt() Value {
347347
n, err := NewNumberFromString(
348348
new(big.Float).Sqrt(n.value.BigFloat()).String(),
349349
)
350350
if err != nil {
351-
panic(err) // TODO: :-/ - Maybe `Sqrt() Value` and here return Undefined{} instead??
351+
return NewUndefinedWithReasonf("Sqrt:" + err.Error())
352352
}
353353

354354
return n
@@ -360,6 +360,33 @@ func (n Number) Tan() Number {
360360
}
361361
}
362362

363+
func (n Number) Ln(precision int32) Value {
364+
res, err := n.value.Ln(precision)
365+
if err != nil {
366+
return NewUndefinedWithReasonf("Ln:" + err.Error())
367+
}
368+
369+
return Number{
370+
value: res,
371+
}
372+
}
373+
374+
func (n Number) Log(precision int32) Value {
375+
res1, err := n.value.Ln(precision)
376+
if err != nil {
377+
return NewUndefinedWithReasonf("Log:" + err.Error())
378+
}
379+
380+
res10, err := decimal.New(10, 0).Ln(precision)
381+
if err != nil {
382+
return NewUndefinedWithReasonf("Log:" + err.Error())
383+
}
384+
385+
return Number{
386+
value: res1.Div(res10).Truncate(precision),
387+
}
388+
}
389+
363390
func (n Number) Floor() Number {
364391
return Number{
365392
value: n.value.Floor(),
@@ -372,9 +399,9 @@ func (n Number) Trunc(precision int32) Number {
372399
}
373400
}
374401

375-
func (n Number) Factorial() Number {
402+
func (n Number) Factorial() Value {
376403
if !n.value.IsInteger() || n.value.IsNegative() {
377-
panic(fmt.Sprintf("invalid calculation: Factorial requires a positive integer, cannot accept %s", n.String())) // TODO :-/
404+
return NewUndefinedWithReasonf(fmt.Sprintf("Factorial: requires a positive integer, cannot accept %s", n.String()))
378405
}
379406

380407
res := decimal.NewFromInt(1)

0 commit comments

Comments
 (0)