Skip to content

Commit

Permalink
feat: add ln and log (#12)
Browse files Browse the repository at this point in the history
* add Ln and Log
  • Loading branch information
seborama authored May 5, 2024
1 parent 2569144 commit f38aaf8
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 4 deletions.
32 changes: 32 additions & 0 deletions function.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ var builtInFunctions = map[string]FunctionalValue{
"sqrt": Sqrt,
"floor": Floor,
"trunc": Trunc,
"ln": Ln,
"log": Log,
}

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

// Ln returns the natural logarithm of d.
func Ln(args ...Value) Value {
if len(args) != 2 {
return NewUndefinedWithReasonf("ln() requires 2 arguments, got %d", len(args))
}

if v, ok := args[0].(Numberer); ok {
if p, ok := args[1].(Numberer); ok {
return v.Number().Ln(int32(p.Number().value.IntPart()))
}
}

return NewUndefinedWithReasonf("ln(): invalid argument type '%s'", args[0].String())
}

// Log returns the logarithm base 10 of d.
func Log(args ...Value) Value {
if len(args) != 2 {
return NewUndefinedWithReasonf("log() requires 2 arguments, got %d", len(args))
}

if v, ok := args[0].(Numberer); ok {
if p, ok := args[1].(Numberer); ok {
return v.Number().Log(int32(p.Number().value.IntPart()))
}
}

return NewUndefinedWithReasonf("log(): invalid argument type '%s'", args[0].String())
}

// Sqrt returns the square root.
func Sqrt(args ...Value) Value {
if len(args) != 1 {
Expand Down
19 changes: 19 additions & 0 deletions function_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ func TestFactorial(t *testing.T) {

val = gal.Factorial(gal.NewNumber(10))
assert.Equal(t, gal.NewNumber(3_628_800).String(), val.String())

val = gal.Factorial(gal.NewNumber(-10))
assert.Equal(t, "undefined: Factorial: requires a positive integer, cannot accept -10", val.String())
}

func TestCos(t *testing.T) {
Expand All @@ -54,3 +57,19 @@ func TestFloor(t *testing.T) {
val := gal.Floor(gal.NewNumberFromFloat(0.0))
assert.Equal(t, int64(0), gal.ToNumber(val).Int64())
}

func TestLn(t *testing.T) {
val := gal.Ln(gal.NewNumber(123456), gal.NewNumber(5))
assert.Equal(t, "11.72364", val.String())

val = gal.Ln(gal.NewNumber(-123456), gal.NewNumber(5))
assert.Equal(t, "undefined: Ln:cannot calculate natural logarithm for negative decimals", val.String())
}

func TestLog(t *testing.T) {
val := gal.Log(gal.NewNumber(123456), gal.NewNumber(5))
assert.Equal(t, "5.09152", val.String())

val = gal.Log(gal.NewNumber(-123456), gal.NewNumber(5))
assert.Equal(t, "undefined: Log:cannot calculate natural logarithm for negative decimals", val.String())
}
35 changes: 31 additions & 4 deletions value.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,12 +343,12 @@ func (n Number) Cos() Number {
}
}

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

return n
Expand All @@ -360,6 +360,33 @@ func (n Number) Tan() Number {
}
}

func (n Number) Ln(precision int32) Value {
res, err := n.value.Ln(precision)
if err != nil {
return NewUndefinedWithReasonf("Ln:" + err.Error())
}

return Number{
value: res,
}
}

func (n Number) Log(precision int32) Value {
res1, err := n.value.Ln(precision)
if err != nil {
return NewUndefinedWithReasonf("Log:" + err.Error())
}

res10, err := decimal.New(10, 0).Ln(precision)
if err != nil {
return NewUndefinedWithReasonf("Log:" + err.Error())
}

return Number{
value: res1.Div(res10).Truncate(precision),
}
}

func (n Number) Floor() Number {
return Number{
value: n.value.Floor(),
Expand All @@ -372,9 +399,9 @@ func (n Number) Trunc(precision int32) Number {
}
}

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

res := decimal.NewFromInt(1)
Expand Down

0 comments on commit f38aaf8

Please sign in to comment.