Skip to content

Commit

Permalink
Feature/#7 numeric functions (#116)
Browse files Browse the repository at this point in the history
* #7 Added ABS

* #7 Added ACOS

* #7 Added ASIN

* #7 Added ATAN

* #7 Added ATAN2

* #7 Added AVERAGE

* #7 Added CEIL

* #7 Added COS

* #7 Added DEGREES

* #7 Added EXP

* #7 Added EXP2

* #7 Added FLOOR

* #7 Added LOG

* #7 Added LOG2

* #7 Added LOG10

* #7 Added MAX

* #7 Added MEDIAN

* #7 Added MIN

* #7 Added PERCENTILE

* #7 Added PI

* #7 Added POW

* #7 Added RADIANS

* #7 Added RAND

* #7 Added RANGE

* #7 Added ROUND

* #7 Added SIN

* #7 Added SQRT

* #7 Added TAN

* #7 Added SUM

* #7 Added STDDEV_POPULATION

* #7 Added STDDEV_SAMPLE, VARIANCE_POPULATION, VARIANCE_SAMPLE
  • Loading branch information
ziflex authored Oct 14, 2018
1 parent 2417be3 commit 5f94b77
Show file tree
Hide file tree
Showing 74 changed files with 2,466 additions and 0 deletions.
15 changes: 15 additions & 0 deletions pkg/runtime/values/array.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"encoding/binary"
"encoding/json"
"hash/fnv"
"sort"

"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/pkg/errors"
Expand Down Expand Up @@ -221,3 +222,17 @@ func (t *Array) Clone() core.Cloneable {

return cloned
}

func (t *Array) Sort() *Array {
c := make([]core.Value, len(t.value))
copy(c, t.value)

sort.SliceStable(c, func(i, j int) bool {
return c[i].Compare(c[j]) == 0
})

res := new(Array)
res.value = c

return res
}
8 changes: 8 additions & 0 deletions pkg/runtime/values/float.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ func ParseFloatP(input interface{}) Float {
return res
}

func IsNaN(input Float) Boolean {
return NewBoolean(math.IsNaN(float64(input)))
}

func IsInf(input Float, sign Int) Boolean {
return NewBoolean(math.IsInf(float64(input), int(sign)))
}

func (t Float) MarshalJSON() ([]byte, error) {
return json.Marshal(float64(t))
}
Expand Down
2 changes: 2 additions & 0 deletions pkg/stdlib/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"github.com/MontFerret/ferret/pkg/stdlib/arrays"
"github.com/MontFerret/ferret/pkg/stdlib/collections"
"github.com/MontFerret/ferret/pkg/stdlib/html"
"github.com/MontFerret/ferret/pkg/stdlib/math"
"github.com/MontFerret/ferret/pkg/stdlib/objects"
"github.com/MontFerret/ferret/pkg/stdlib/strings"
"github.com/MontFerret/ferret/pkg/stdlib/types"
Expand All @@ -22,6 +23,7 @@ func NewLib() map[string]core.Function {

add(types.NewLib())
add(strings.NewLib())
add(math.NewLib())
add(collections.NewLib())
add(arrays.NewLib())
add(objects.NewLib())
Expand Down
29 changes: 29 additions & 0 deletions pkg/stdlib/math/abs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package math

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"math"
)

/*
* Returns the absolute value of a given number.
* @param number (Int|Float) - Input number.
* @returns (Float) - The absolute value of a given number.
*/
func Abs(_ context.Context, args ...core.Value) (core.Value, error) {
err := core.ValidateArgs(args, 1, 1)

if err != nil {
return values.None, err
}

err = core.ValidateType(args[0], core.IntType, core.FloatType)

if err != nil {
return values.None, err
}

return values.NewFloat(math.Abs(toFloat(args[0]))), nil
}
38 changes: 38 additions & 0 deletions pkg/stdlib/math/abs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package math_test

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/stdlib/math"
"testing"

. "github.com/smartystreets/goconvey/convey"
)

func TestAbs(t *testing.T) {
Convey("Should return absolute value", t, func() {
Convey("When value is int", func() {
out, err := math.Abs(context.Background(), values.NewInt(-5))

So(err, ShouldBeNil)
So(out, ShouldEqual, 5)

out, err = math.Abs(context.Background(), values.NewInt(3))

So(err, ShouldBeNil)
So(out, ShouldEqual, 3)
})

Convey("When value is float", func() {
out, err := math.Abs(context.Background(), values.NewFloat(-5))

So(err, ShouldBeNil)
So(out, ShouldEqual, 5)

out, err = math.Abs(context.Background(), values.NewFloat(5.1))

So(err, ShouldBeNil)
So(out, ShouldEqual, 5.1)
})
})
}
29 changes: 29 additions & 0 deletions pkg/stdlib/math/acos.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package math

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"math"
)

/*
* Returns the arccosine, in radians, of a given number.
* @param number (Int|Float) - Input number.
* @returns (Float) - The arccosine, in radians, of a given number.
*/
func Acos(_ context.Context, args ...core.Value) (core.Value, error) {
err := core.ValidateArgs(args, 1, 1)

if err != nil {
return values.None, err
}

err = core.ValidateType(args[0], core.IntType, core.FloatType)

if err != nil {
return values.None, err
}

return values.NewFloat(math.Acos(toFloat(args[0]))), nil
}
24 changes: 24 additions & 0 deletions pkg/stdlib/math/acos_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package math_test

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/stdlib/math"
"testing"

. "github.com/smartystreets/goconvey/convey"
)

func TestAcos(t *testing.T) {
Convey("Should return arccosine", t, func() {
out, err := math.Acos(context.Background(), values.NewInt(-1))

So(err, ShouldBeNil)
So(out, ShouldEqual, 3.141592653589793)

out, err = math.Acos(context.Background(), values.NewInt(0))

So(err, ShouldBeNil)
So(out, ShouldEqual, 1.5707963267948966)
})
}
29 changes: 29 additions & 0 deletions pkg/stdlib/math/asin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package math

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"math"
)

/*
* Returns the arcsine, in radians, of a given number.
* @param number (Int|Float) - Input number.
* @returns (Float) - The arcsine, in radians, of a given number.
*/
func Asin(_ context.Context, args ...core.Value) (core.Value, error) {
err := core.ValidateArgs(args, 1, 1)

if err != nil {
return values.None, err
}

err = core.ValidateType(args[0], core.IntType, core.FloatType)

if err != nil {
return values.None, err
}

return values.NewFloat(math.Asin(toFloat(args[0]))), nil
}
34 changes: 34 additions & 0 deletions pkg/stdlib/math/asin_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package math_test

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/stdlib/math"
"testing"

. "github.com/smartystreets/goconvey/convey"
)

func TestAsin(t *testing.T) {
Convey("Should return arcsine value", t, func() {
out, err := math.Asin(context.Background(), values.NewInt(1))

So(err, ShouldBeNil)
So(out, ShouldEqual, 1.5707963267948966)

out, err = math.Asin(context.Background(), values.NewInt(0))

So(err, ShouldBeNil)
So(out, ShouldEqual, 0)

out, err = math.Asin(context.Background(), values.NewInt(-1))

So(err, ShouldBeNil)
So(out, ShouldEqual, -1.5707963267948966)

out, err = math.Asin(context.Background(), values.NewInt(2))

So(err, ShouldBeNil)
So(values.IsNaN(out.(values.Float)), ShouldEqual, true)
})
}
29 changes: 29 additions & 0 deletions pkg/stdlib/math/atan.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package math

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"math"
)

/*
* Returns the arctangent, in radians, of a given number.
* @param number (Int|Float) - Input number.
* @returns (Float) - The arctangent, in radians, of a given number.
*/
func Atan(_ context.Context, args ...core.Value) (core.Value, error) {
err := core.ValidateArgs(args, 1, 1)

if err != nil {
return values.None, err
}

err = core.ValidateType(args[0], core.IntType, core.FloatType)

if err != nil {
return values.None, err
}

return values.NewFloat(math.Atan(toFloat(args[0]))), nil
}
39 changes: 39 additions & 0 deletions pkg/stdlib/math/atan2.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package math

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/core"
"github.com/MontFerret/ferret/pkg/runtime/values"
"math"
)

/*
* Returns the arc tangent of y/x, using the signs of the two to determine the quadrant of the return value.
* @param number1 (Int|Float) - Input number.
* @param number2 (Int|Float) - Input number.
* @returns (Float) - The arc tangent of y/x, using the signs of the two to determine the quadrant of the return value.
*/
func Atan2(_ context.Context, args ...core.Value) (core.Value, error) {
err := core.ValidateArgs(args, 2, 2)

if err != nil {
return values.None, err
}

err = core.ValidateType(args[0], core.IntType, core.FloatType)

if err != nil {
return values.None, err
}

err = core.ValidateType(args[1], core.IntType, core.FloatType)

if err != nil {
return values.None, err
}

arg1 := toFloat(args[0])
arg2 := toFloat(args[1])

return values.NewFloat(math.Atan2(arg1, arg2)), nil
}
34 changes: 34 additions & 0 deletions pkg/stdlib/math/atan2_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package math_test

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/stdlib/math"
"testing"

. "github.com/smartystreets/goconvey/convey"
)

func TestAtan2(t *testing.T) {
Convey("Should return tangent value", t, func() {
out, err := math.Atan2(context.Background(), values.NewInt(0), values.NewInt(0))

So(err, ShouldBeNil)
So(out, ShouldEqual, 0)

out, err = math.Atan2(context.Background(), values.NewInt(1), values.NewInt(0))

So(err, ShouldBeNil)
So(out, ShouldEqual, 1.5707963267948966)

out, err = math.Atan2(context.Background(), values.NewInt(1), values.NewInt(1))

So(err, ShouldBeNil)
So(out.Unwrap(), ShouldEqual, 0.7853981633974483)

out, err = math.Atan2(context.Background(), values.NewInt(-10), values.NewInt(20))

So(err, ShouldBeNil)
So(out.Unwrap(), ShouldEqual, -0.4636476090008061)
})
}
29 changes: 29 additions & 0 deletions pkg/stdlib/math/atan_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package math_test

import (
"context"
"github.com/MontFerret/ferret/pkg/runtime/values"
"github.com/MontFerret/ferret/pkg/stdlib/math"
"testing"

. "github.com/smartystreets/goconvey/convey"
)

func TestAtan(t *testing.T) {
Convey("Should return arctangent value", t, func() {
out, err := math.Atan(context.Background(), values.NewInt(-1))

So(err, ShouldBeNil)
So(out, ShouldEqual, -0.7853981633974483)

out, err = math.Atan(context.Background(), values.NewInt(0))

So(err, ShouldBeNil)
So(out, ShouldEqual, 0)

out, err = math.Atan(context.Background(), values.NewInt(10))

So(err, ShouldBeNil)
So(out.Unwrap(), ShouldEqual, 1.4711276743037345)
})
}
Loading

0 comments on commit 5f94b77

Please sign in to comment.