mirror of
				https://github.com/MontFerret/ferret.git
				synced 2025-10-30 23:37:40 +02:00 
			
		
		
		
	Feature/#7 numeric functions (#116)
* #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
This commit is contained in:
		| @@ -4,6 +4,7 @@ import ( | ||||
| 	"encoding/binary" | ||||
| 	"encoding/json" | ||||
| 	"hash/fnv" | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/pkg/errors" | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
| @@ -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)) | ||||
| } | ||||
|   | ||||
| @@ -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" | ||||
| @@ -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()) | ||||
|   | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/abs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/abs.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								pkg/stdlib/math/abs_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								pkg/stdlib/math/abs_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								pkg/stdlib/math/acos.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/acos.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								pkg/stdlib/math/acos_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								pkg/stdlib/math/acos_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								pkg/stdlib/math/asin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/asin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								pkg/stdlib/math/asin_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								pkg/stdlib/math/asin_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								pkg/stdlib/math/atan.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/atan.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								pkg/stdlib/math/atan2.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								pkg/stdlib/math/atan2.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								pkg/stdlib/math/atan2_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								pkg/stdlib/math/atan2_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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
									
								
								pkg/stdlib/math/atan_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/atan_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										55
									
								
								pkg/stdlib/math/average.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								pkg/stdlib/math/average.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the average (arithmetic mean) of the values in array. | ||||
|  * @param array (Array) - Array of numbers. | ||||
|  * @returns (Float) - The average of the values in array. | ||||
|  */ | ||||
| func Average(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var err error | ||||
| 	err = core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
|  | ||||
| 	if arr.Length() == 0 { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	var sum float64 | ||||
|  | ||||
| 	arr.ForEach(func(value core.Value, idx int) bool { | ||||
| 		err = core.ValidateType(value, core.FloatType, core.IntType) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		sum += toFloat(value) | ||||
|  | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	count := arr.Length() | ||||
|  | ||||
| 	return values.Float(sum / float64(count)), nil | ||||
| } | ||||
							
								
								
									
										47
									
								
								pkg/stdlib/math/average_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								pkg/stdlib/math/average_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| 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 TestAverage(t *testing.T) { | ||||
| 	Convey("Should return average value", t, func() { | ||||
| 		out, err := math.Average(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(5), | ||||
| 			values.NewInt(2), | ||||
| 			values.NewInt(9), | ||||
| 			values.NewInt(2), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 4.5) | ||||
|  | ||||
| 		out, err = math.Average(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(-3), | ||||
| 			values.NewInt(-5), | ||||
| 			values.NewInt(2), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, -2) | ||||
|  | ||||
| 		out, err = math.Average(context.Background(), values.NewArrayWith( | ||||
| 			values.None, | ||||
| 			values.NewInt(-5), | ||||
| 			values.False, | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, values.None) | ||||
|  | ||||
| 		out, err = math.Average(context.Background(), values.NewArray(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, values.None) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/ceil.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/ceil.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 least integer value greater than or equal to a given value. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Int) - The least integer value greater than or equal to a given value. | ||||
|  */ | ||||
| func Ceil(_ 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.NewInt(int(math.Ceil(toFloat(args[0])))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/ceil_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/ceil_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestCeil(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Ceil(context.Background(), values.NewFloat(2.49)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 3) | ||||
|  | ||||
| 		out, err = math.Ceil(context.Background(), values.NewFloat(2.50)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 3) | ||||
|  | ||||
| 		out, err = math.Ceil(context.Background(), values.NewFloat(-2.50)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, -2) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/cos.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/cos.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 cosine of a given number. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Float) - The cosine of a given number. | ||||
|  */ | ||||
| func Cos(_ 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.Cos(toFloat(args[0]))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/cos_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/cos_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestCos(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Cos(context.Background(), values.NewFloat(1)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 0.5403023058681398) | ||||
|  | ||||
| 		out, err = math.Cos(context.Background(), values.NewFloat(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 1) | ||||
|  | ||||
| 		out, err = math.Cos(context.Background(), values.NewFloat(-3.141592653589783)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, -1) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										30
									
								
								pkg/stdlib/math/degrees.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								pkg/stdlib/math/degrees.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the angle converted from radians to degrees. | ||||
|  * @param number (Float|Int) - The input number. | ||||
|  * @returns (Float) - The angle in degrees. | ||||
|  */ | ||||
| func Degrees(_ 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 | ||||
| 	} | ||||
|  | ||||
| 	r := toFloat(args[0]) | ||||
|  | ||||
| 	return values.NewFloat(r * RadToDeg), nil | ||||
| } | ||||
							
								
								
									
										24
									
								
								pkg/stdlib/math/degrees_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								pkg/stdlib/math/degrees_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestDegrees(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Degrees(context.Background(), values.NewFloat(0.7853981633974483)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 45) | ||||
|  | ||||
| 		out, err = math.Degrees(context.Background(), values.NewFloat(3.141592653589793)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 180) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/exp.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/exp.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns Euler's constant (2.71828...) raised to the power of value. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Float) - Euler's constant raised to the power of value. | ||||
|  */ | ||||
| func Exp(_ 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.Exp(toFloat(args[0]))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/exp2.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/exp2.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns 2 raised to the power of value. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Float) - 2 raised to the power of value. | ||||
|  */ | ||||
| func Exp2(_ 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.Exp2(toFloat(args[0]))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/exp2_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/exp2_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestExp2(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Exp2(context.Background(), values.NewFloat(16)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 65536) | ||||
|  | ||||
| 		out, err = math.Exp(context.Background(), values.NewFloat(1)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Compare(values.NewFloat(2)) == 1, ShouldBeTrue) | ||||
|  | ||||
| 		out, err = math.Exp(context.Background(), values.NewFloat(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 1) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/exp_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/exp_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestExp(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Exp(context.Background(), values.NewFloat(1)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2.718281828459045) | ||||
|  | ||||
| 		out, err = math.Exp(context.Background(), values.NewFloat(10)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Compare(values.NewFloat(22026.46579480671)) == 1, ShouldBeTrue) | ||||
|  | ||||
| 		out, err = math.Exp(context.Background(), values.NewFloat(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 1) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/floor.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/floor.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 greatest integer value less than or equal to a given value. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Int) - The greatest integer value less than or equal to a given value. | ||||
|  */ | ||||
| func Floor(_ 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.NewInt(int(math.Floor(toFloat(args[0])))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/floor_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/floor_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestFloor(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Floor(context.Background(), values.NewFloat(2.49)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2) | ||||
|  | ||||
| 		out, err = math.Floor(context.Background(), values.NewFloat(2.50)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2) | ||||
|  | ||||
| 		out, err = math.Floor(context.Background(), values.NewFloat(-2.50)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, -3) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										60
									
								
								pkg/stdlib/math/lib.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								pkg/stdlib/math/lib.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	RadToDeg  = 180 / math.Pi | ||||
| 	DegToRad  = math.Pi / 180 | ||||
| 	RadToGrad = 200 / math.Pi | ||||
| 	GradToDeg = math.Pi / 200 | ||||
| ) | ||||
|  | ||||
| func NewLib() map[string]core.Function { | ||||
| 	return map[string]core.Function{ | ||||
| 		"ABS":                 Abs, | ||||
| 		"ACOS":                Acos, | ||||
| 		"ASIN":                Asin, | ||||
| 		"ATAN":                Atan, | ||||
| 		"ATAN2":               Atan2, | ||||
| 		"AVERAGE":             Average, | ||||
| 		"CEIL":                Ceil, | ||||
| 		"COS":                 Cos, | ||||
| 		"DEGREES":             Degrees, | ||||
| 		"EXP":                 Exp, | ||||
| 		"EXP2":                Exp2, | ||||
| 		"FLOOR":               Floor, | ||||
| 		"LOG":                 Log, | ||||
| 		"LOG2":                Log2, | ||||
| 		"LOG10":               Log10, | ||||
| 		"MAX":                 Max, | ||||
| 		"MEDIAN":              Median, | ||||
| 		"MIN":                 Min, | ||||
| 		"PERCENTILE":          Percentile, | ||||
| 		"PI":                  Pi, | ||||
| 		"POW":                 Pow, | ||||
| 		"RADIANS":             Radians, | ||||
| 		"RAND":                Rand, | ||||
| 		"RANGE":               Range, | ||||
| 		"ROUND":               Round, | ||||
| 		"SIN":                 Sin, | ||||
| 		"SQRT":                Sqrt, | ||||
| 		"STDDEV_POPULATION":   StandardDeviationPopulation, | ||||
| 		"STDDEV_SAMPLE":       StandardDeviationSample, | ||||
| 		"SUM":                 Sum, | ||||
| 		"TAN":                 Tan, | ||||
| 		"VARIANCE_POPULATION": PopulationVariance, | ||||
| 		"VARIANCE_SAMPLE":     SampleVariance, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func toFloat(arg core.Value) float64 { | ||||
| 	if arg.Type() == core.IntType { | ||||
| 		return float64(arg.(values.Int)) | ||||
| 	} | ||||
|  | ||||
| 	return float64(arg.(values.Float)) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/log.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/log.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 natural logarithm of a given value. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Float) - The natural logarithm of a given value. | ||||
|  */ | ||||
| func Log(_ 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.Log(toFloat(args[0]))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/log10.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/log10.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 decimal logarithm of a given value. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Float) - The decimal logarithm of a given value. | ||||
|  */ | ||||
| func Log10(_ 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.Log10(toFloat(args[0]))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/log10_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/log10_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestLog10(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Log10(context.Background(), values.NewFloat(10000)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 4) | ||||
|  | ||||
| 		out, err = math.Log10(context.Background(), values.NewFloat(10)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 1) | ||||
|  | ||||
| 		out, err = math.Log10(context.Background(), values.NewFloat(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(values.IsInf(out.(values.Float), -1).Unwrap(), ShouldBeTrue) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/log2.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/log2.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 binary logarithm of a given value. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Float) - The binary logarithm of a given value. | ||||
|  */ | ||||
| func Log2(_ 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.Log2(toFloat(args[0]))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/log2_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/log2_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestLog2(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Log2(context.Background(), values.NewFloat(1024)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 10) | ||||
|  | ||||
| 		out, err = math.Log2(context.Background(), values.NewFloat(8)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 3) | ||||
|  | ||||
| 		out, err = math.Log2(context.Background(), values.NewFloat(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(values.IsInf(out.(values.Float), -1).Unwrap(), ShouldBeTrue) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/log_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/log_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestLog(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Log(context.Background(), values.NewFloat(2.718281828459045)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 1) | ||||
|  | ||||
| 		out, err = math.Log(context.Background(), values.NewFloat(10)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2.302585092994046) | ||||
|  | ||||
| 		out, err = math.Log(context.Background(), values.NewFloat(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(values.IsInf(out.(values.Float), -1).Unwrap(), ShouldBeTrue) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										57
									
								
								pkg/stdlib/math/max.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								pkg/stdlib/math/max.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the greatest (arithmetic mean) of the values in array. | ||||
|  * @param array (Array) - Array of numbers. | ||||
|  * @returns (Float) - The greatest of the values in array. | ||||
|  */ | ||||
| func Max(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var err error | ||||
| 	err = core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
|  | ||||
| 	if arr.Length() == 0 { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	var max float64 | ||||
|  | ||||
| 	arr.ForEach(func(value core.Value, idx int) bool { | ||||
| 		err = core.ValidateType(value, core.FloatType, core.IntType) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		fv := toFloat(value) | ||||
|  | ||||
| 		if fv > max { | ||||
| 			max = fv | ||||
| 		} | ||||
|  | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	return values.NewFloat(max), nil | ||||
| } | ||||
							
								
								
									
										47
									
								
								pkg/stdlib/math/max_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								pkg/stdlib/math/max_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| 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 TestMax(t *testing.T) { | ||||
| 	Convey("Should return the largest value", t, func() { | ||||
| 		out, err := math.Max(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(5), | ||||
| 			values.NewInt(2), | ||||
| 			values.NewInt(9), | ||||
| 			values.NewInt(2), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 9) | ||||
|  | ||||
| 		out, err = math.Max(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(-3), | ||||
| 			values.NewInt(-5), | ||||
| 			values.NewInt(2), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2) | ||||
|  | ||||
| 		out, err = math.Max(context.Background(), values.NewArrayWith( | ||||
| 			values.None, | ||||
| 			values.NewInt(-5), | ||||
| 			values.False, | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, values.None) | ||||
|  | ||||
| 		out, err = math.Max(context.Background(), values.NewArray(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, values.None) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										34
									
								
								pkg/stdlib/math/mean.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								pkg/stdlib/math/mean.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| func mean(input *values.Array) (values.Float, error) { | ||||
| 	if input.Length() == 0 { | ||||
| 		return values.NewFloat(math.NaN()), nil | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var sum float64 | ||||
|  | ||||
| 	input.ForEach(func(value core.Value, idx int) bool { | ||||
| 		err = core.ValidateType(value, core.FloatType, core.IntType) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		sum += toFloat(value) | ||||
|  | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return 0, err | ||||
| 	} | ||||
|  | ||||
| 	return values.NewFloat(sum / float64(input.Length())), nil | ||||
| } | ||||
							
								
								
									
										53
									
								
								pkg/stdlib/math/median.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								pkg/stdlib/math/median.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the median of the values in array. | ||||
|  * @param array (Array) - Array of numbers. | ||||
|  * @returns (Float) - The median of the values in array. | ||||
|  */ | ||||
| func Median(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var err error | ||||
| 	err = core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
| 	sorted := arr.Sort() | ||||
|  | ||||
| 	l := sorted.Length() | ||||
|  | ||||
| 	var median core.Value | ||||
|  | ||||
| 	if l == 0 { | ||||
| 		return values.NewFloat(math.NaN()), nil | ||||
| 	} else if l%2 == 0 { | ||||
| 		median, err = mean(sorted.Slice(l/2-1, l/2+1)) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return values.None, nil | ||||
| 		} | ||||
| 	} else { | ||||
| 		median = sorted.Get(l / 2) | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	return median, nil | ||||
| } | ||||
							
								
								
									
										52
									
								
								pkg/stdlib/math/median_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								pkg/stdlib/math/median_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| 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 TestMedian(t *testing.T) { | ||||
| 	Convey("Should return median value", t, func() { | ||||
| 		out, err := math.Median(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(1), | ||||
| 			values.NewInt(2), | ||||
| 			values.NewInt(3), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2) | ||||
|  | ||||
| 		out, err = math.Average(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(1), | ||||
| 			values.NewInt(2), | ||||
| 			values.NewInt(3), | ||||
| 			values.NewInt(4), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2.5) | ||||
|  | ||||
| 		out, err = math.Average(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(2), | ||||
| 			values.NewInt(1), | ||||
| 			values.NewInt(4), | ||||
| 			values.NewInt(3), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2.5) | ||||
|  | ||||
| 		out, err = math.Average(context.Background(), values.NewArrayWith( | ||||
| 			values.None, | ||||
| 			values.NewInt(-5), | ||||
| 			values.False, | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, values.None) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										57
									
								
								pkg/stdlib/math/min.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								pkg/stdlib/math/min.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the smallest (arithmetic mean) of the values in array. | ||||
|  * @param array (Array) - Array of numbers. | ||||
|  * @returns (Float) - The smallest of the values in array. | ||||
|  */ | ||||
| func Min(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var err error | ||||
| 	err = core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
|  | ||||
| 	if arr.Length() == 0 { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	var min float64 | ||||
|  | ||||
| 	arr.ForEach(func(value core.Value, idx int) bool { | ||||
| 		err = core.ValidateType(value, core.FloatType, core.IntType) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		fv := toFloat(value) | ||||
|  | ||||
| 		if min > fv || idx == 0 { | ||||
| 			min = fv | ||||
| 		} | ||||
|  | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	return values.NewFloat(min), nil | ||||
| } | ||||
							
								
								
									
										47
									
								
								pkg/stdlib/math/min_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								pkg/stdlib/math/min_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| 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 TestMin(t *testing.T) { | ||||
| 	Convey("Should return the smallest value", t, func() { | ||||
| 		out, err := math.Min(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(5), | ||||
| 			values.NewInt(2), | ||||
| 			values.NewInt(9), | ||||
| 			values.NewInt(2), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2) | ||||
|  | ||||
| 		out, err = math.Min(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(-3), | ||||
| 			values.NewInt(-5), | ||||
| 			values.NewInt(2), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, -5) | ||||
|  | ||||
| 		out, err = math.Min(context.Background(), values.NewArrayWith( | ||||
| 			values.None, | ||||
| 			values.NewInt(-5), | ||||
| 			values.False, | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, values.None) | ||||
|  | ||||
| 		out, err = math.Min(context.Background(), values.NewArray(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, values.None) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										92
									
								
								pkg/stdlib/math/percentile.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								pkg/stdlib/math/percentile.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,92 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"github.com/pkg/errors" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the nth percentile of the values in a given array. | ||||
|  * @param array (Array) - Array of numbers. | ||||
|  * @param numb (Int) - A number which must be between 0 (excluded) and 100 (included). | ||||
|  * @param method (String, optional) - "rank" (default) or "interpolation". | ||||
|  * @returns (Float) - The nth percentile, or null if the array is empty or only null values are contained in it or the percentile cannot be calculated. | ||||
|  */ | ||||
| func Percentile(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateArgs(args, 2, 3) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[1], core.IntType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	// TODO: Implement different methods | ||||
| 	//method := "rank" | ||||
| 	// | ||||
| 	//if len(args) > 2 { | ||||
| 	//	err = core.ValidateType(args[2], core.StringType) | ||||
| 	// | ||||
| 	//	if err != nil { | ||||
| 	//		return values.None, err | ||||
| 	//	} | ||||
| 	// | ||||
| 	//	if args[2].String() == "interpolation" { | ||||
| 	//		method = "interpolation" | ||||
| 	//	} | ||||
| 	//} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
| 	percent := values.Float(args[1].(values.Int)) | ||||
|  | ||||
| 	if arr.Length() == 0 { | ||||
| 		return values.NewFloat(math.NaN()), nil | ||||
| 	} | ||||
|  | ||||
| 	if percent <= 0 || percent > 100 { | ||||
| 		return values.NewFloat(math.NaN()), errors.New("input is outside of range") | ||||
| 	} | ||||
|  | ||||
| 	sorted := arr.Sort() | ||||
|  | ||||
| 	// Multiply percent by length of input | ||||
| 	l := values.Float(sorted.Length()) | ||||
| 	index := (percent / 100) * l | ||||
| 	even := values.Float(values.Int(index)) | ||||
|  | ||||
| 	var percentile core.Value | ||||
|  | ||||
| 	// Check if the index is a whole number | ||||
| 	if index == even { | ||||
|  | ||||
| 		// Convert float to int | ||||
| 		i := values.Int(index) | ||||
|  | ||||
| 		// Find the value at the index | ||||
| 		percentile = sorted.Get(i - 1) | ||||
| 	} else if index > 1 { | ||||
|  | ||||
| 		// Convert float to int via truncation | ||||
| 		i := values.Int(index) | ||||
|  | ||||
| 		// Find the average of the index and following values | ||||
| 		percentile, _ = mean(values.NewArrayWith(sorted.Get(i-1), sorted.Get(i))) | ||||
| 	} else { | ||||
| 		return values.NewFloat(math.NaN()), errors.New("input is outside of range") | ||||
| 	} | ||||
|  | ||||
| 	return percentile, nil | ||||
| } | ||||
							
								
								
									
										28
									
								
								pkg/stdlib/math/percentile_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pkg/stdlib/math/percentile_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| 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 TestPrecentile(t *testing.T) { | ||||
| 	Convey("Should return nth percentile value", t, func() { | ||||
| 		out, err := math.Percentile( | ||||
| 			context.Background(), | ||||
| 			values.NewArrayWith( | ||||
| 				values.NewInt(1), | ||||
| 				values.NewInt(2), | ||||
| 				values.NewInt(3), | ||||
| 				values.NewInt(4), | ||||
| 			), | ||||
| 			values.NewInt(50), | ||||
| 		) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										22
									
								
								pkg/stdlib/math/pi.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								pkg/stdlib/math/pi.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns Pi value. | ||||
|  * @returns (Float) - Pi value. | ||||
|  */ | ||||
| func Pi(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateArgs(args, 0, 0) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	return values.NewFloat(math.Pi), nil | ||||
| } | ||||
							
								
								
									
										18
									
								
								pkg/stdlib/math/pi_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								pkg/stdlib/math/pi_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| package math_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/stdlib/math" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	m "math" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestPi(t *testing.T) { | ||||
| 	Convey("Should return Pi value", t, func() { | ||||
| 		out, err := math.Pi(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, m.Pi) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										36
									
								
								pkg/stdlib/math/pow.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								pkg/stdlib/math/pow.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the base to the exponent value. | ||||
|  * @param base (Int|Float) - The base value. | ||||
|  * @param exp (Int|Float) - The exponent value. | ||||
|  * @returns (Float) - The exponentiated value. | ||||
|  */ | ||||
| func Pow(_ 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 | ||||
| 	} | ||||
|  | ||||
| 	return values.NewFloat(math.Pow(toFloat(args[0]), toFloat(args[1]))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/pow_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/pow_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestPow(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Pow(context.Background(), values.NewInt(2), values.NewInt(4)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 16) | ||||
|  | ||||
| 		out, err = math.Pow(context.Background(), values.NewInt(5), values.NewInt(-1)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 0.2) | ||||
|  | ||||
| 		out, err = math.Pow(context.Background(), values.NewInt(5), values.NewInt(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 1) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										30
									
								
								pkg/stdlib/math/radians.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								pkg/stdlib/math/radians.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the angle converted from degrees to radians. | ||||
|  * @param number (Float|Int) - The input number. | ||||
|  * @returns (Float) - The angle in radians. | ||||
|  */ | ||||
| func Radians(_ 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 | ||||
| 	} | ||||
|  | ||||
| 	r := toFloat(args[0]) | ||||
|  | ||||
| 	return values.NewFloat(r * DegToRad), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/radians_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/radians_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestRadians(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Radians(context.Background(), values.NewInt(180)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 3.141592653589793) | ||||
|  | ||||
| 		out, err = math.Radians(context.Background(), values.NewFloat(90)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 1.5707963267948966) | ||||
|  | ||||
| 		out, err = math.Radians(context.Background(), values.NewFloat(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 0) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										22
									
								
								pkg/stdlib/math/rand.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								pkg/stdlib/math/rand.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math/rand" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Return a pseudo-random number between 0 and 1. | ||||
|  * @returns (Float) - A number greater than 0 and less than 1. | ||||
|  */ | ||||
| func Rand(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateArgs(args, 0, 0) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	return values.NewFloat(rand.Float64()), nil | ||||
| } | ||||
							
								
								
									
										17
									
								
								pkg/stdlib/math/rand_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								pkg/stdlib/math/rand_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| package math_test | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/stdlib/math" | ||||
| 	. "github.com/smartystreets/goconvey/convey" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestRand(t *testing.T) { | ||||
| 	Convey("Should return pseudo-random value", t, func() { | ||||
| 		out, err := math.Rand(context.Background()) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldBeLessThan, 1) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										56
									
								
								pkg/stdlib/math/range.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								pkg/stdlib/math/range.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns an array of numbers in the specified range, optionally with increments other than 1. | ||||
|  * @param start (Int|Float) - The value to start the range at (inclusive). | ||||
|  * @param end (Int|Float) - The value to end the range with (inclusive). | ||||
|  * @param step (Int|Float, optional) - How much to increment in every step, the default is 1.0. | ||||
|  */ | ||||
| func Range(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateArgs(args, 2, 3) | ||||
|  | ||||
| 	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 | ||||
| 	} | ||||
|  | ||||
| 	var step float64 = 1 | ||||
|  | ||||
| 	if len(args) > 2 { | ||||
| 		err = core.ValidateType(args[2], core.IntType, core.FloatType) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return values.None, err | ||||
| 		} | ||||
|  | ||||
| 		step = toFloat(args[2]) | ||||
| 	} | ||||
|  | ||||
| 	start := toFloat(args[0]) | ||||
| 	end := toFloat(args[1]) | ||||
|  | ||||
| 	arr := values.NewArray(int(end)) | ||||
|  | ||||
| 	for i := start; i <= end; i += step { | ||||
| 		arr.Push(values.NewFloat(i)) | ||||
| 	} | ||||
|  | ||||
| 	return arr, nil | ||||
| } | ||||
							
								
								
									
										62
									
								
								pkg/stdlib/math/range_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								pkg/stdlib/math/range_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | ||||
| 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 TestRange(t *testing.T) { | ||||
| 	Convey("Should return range of numbers", t, func() { | ||||
| 		out, err := math.Range(context.Background(), values.NewInt(1), values.NewInt(4)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.String(), ShouldEqual, "[1,2,3,4]") | ||||
|  | ||||
| 		out, err = math.Range(context.Background(), | ||||
| 			values.NewInt(1), | ||||
| 			values.NewInt(4), | ||||
| 			values.NewInt(2)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.String(), ShouldEqual, "[1,3]") | ||||
|  | ||||
| 		out, err = math.Range(context.Background(), | ||||
| 			values.NewInt(1), | ||||
| 			values.NewInt(4), | ||||
| 			values.NewInt(3), | ||||
| 		) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.String(), ShouldEqual, "[1,4]") | ||||
|  | ||||
| 		out, err = math.Range(context.Background(), | ||||
| 			values.NewFloat(1.5), | ||||
| 			values.NewFloat(2.5), | ||||
| 		) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.String(), ShouldEqual, "[1.5,2.5]") | ||||
|  | ||||
| 		out, err = math.Range(context.Background(), | ||||
| 			values.NewFloat(1.5), | ||||
| 			values.NewFloat(2.5), | ||||
| 			values.NewFloat(0.5), | ||||
| 		) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.String(), ShouldEqual, "[1.5,2,2.5]") | ||||
|  | ||||
| 		out, err = math.Range(context.Background(), | ||||
| 			values.NewFloat(-0.75), | ||||
| 			values.NewFloat(1.1), | ||||
| 			values.NewFloat(0.5), | ||||
| 		) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.String(), ShouldEqual, "[-0.75,-0.25,0.25,0.75]") | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/round.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/round.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 nearest integer, rounding half away from zero. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Int) - The nearest integer, rounding half away from zero. | ||||
|  */ | ||||
| func Round(_ 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.NewInt(int(math.Round(toFloat(args[0])))), nil | ||||
| } | ||||
							
								
								
									
										34
									
								
								pkg/stdlib/math/round_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								pkg/stdlib/math/round_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestRound(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.Round(context.Background(), values.NewFloat(2.49)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 2) | ||||
|  | ||||
| 		out, err = math.Round(context.Background(), values.NewFloat(2.50)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 3) | ||||
|  | ||||
| 		out, err = math.Ceil(context.Background(), values.NewFloat(-2.50)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, -2) | ||||
|  | ||||
| 		out, err = math.Ceil(context.Background(), values.NewFloat(-2.49)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, -2) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/sin.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/sin.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 sine of the radian argument. | ||||
|  * @param number (Int|Float) - Input number. | ||||
|  * @returns (Float) - The sin, in radians, of a given number. | ||||
|  */ | ||||
| func Sin(_ 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.Sin(toFloat(args[0]))), nil | ||||
| } | ||||
							
								
								
									
										36
									
								
								pkg/stdlib/math/sin_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								pkg/stdlib/math/sin_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| 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 TestSin(t *testing.T) { | ||||
| 	Convey("Should return sin value", t, func() { | ||||
| 		out, err := math.Sin(context.Background(), values.NewFloat(3.141592653589783/2)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 1) | ||||
|  | ||||
| 		out, err = math.Sin(context.Background(), values.NewInt(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 0) | ||||
|  | ||||
| 		out, err = math.Sin(context.Background(), values.NewFloat(-3.141592653589783/2)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, -1) | ||||
|  | ||||
| 		v, _ := math.Radians(context.Background(), values.NewInt(270)) | ||||
|  | ||||
| 		out, err = math.Sin(context.Background(), v) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, -1) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/sqrt.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/sqrt.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 square root of a given number. | ||||
|  * @param value (Int|Float) - A number. | ||||
|  * @returns (Float) - The square root. | ||||
|  */ | ||||
| func Sqrt(_ 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.Sqrt(toFloat(args[0]))), nil | ||||
| } | ||||
							
								
								
									
										24
									
								
								pkg/stdlib/math/sqrt_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								pkg/stdlib/math/sqrt_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestSqrt(t *testing.T) { | ||||
| 	Convey("Should return square value", t, func() { | ||||
| 		out, err := math.Sqrt(context.Background(), values.NewFloat(9)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 3) | ||||
|  | ||||
| 		out, err = math.Sqrt(context.Background(), values.NewInt(2)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 1.4142135623730951) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										42
									
								
								pkg/stdlib/math/stddev_population.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								pkg/stdlib/math/stddev_population.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the population standard deviation of the values in a given array. | ||||
|  * @params (Array) - Array of numbers. | ||||
|  * @returns (Float) - The population standard deviation. | ||||
|  */ | ||||
| func StandardDeviationPopulation(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var err error | ||||
| 	err = core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
|  | ||||
| 	if arr.Length() == 0 { | ||||
| 		return values.NewFloat(math.NaN()), nil | ||||
| 	} | ||||
|  | ||||
| 	vp, err := variance(arr, values.NewInt(0)) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.NewFloat(math.NaN()), err | ||||
| 	} | ||||
|  | ||||
| 	return values.NewFloat(math.Pow(float64(vp), 0.5)), nil | ||||
| } | ||||
							
								
								
									
										28
									
								
								pkg/stdlib/math/stddev_population_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pkg/stdlib/math/stddev_population_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| 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 TestStandardDeviationPopulation(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.StandardDeviationPopulation( | ||||
| 			context.Background(), | ||||
| 			values.NewArrayWith( | ||||
| 				values.NewInt(1), | ||||
| 				values.NewInt(3), | ||||
| 				values.NewInt(6), | ||||
| 				values.NewInt(5), | ||||
| 				values.NewInt(2), | ||||
| 			), | ||||
| 		) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, 1.8547236990991407) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										42
									
								
								pkg/stdlib/math/stddev_sample.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								pkg/stdlib/math/stddev_sample.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the sample standard deviation of the values in a given array. | ||||
|  * @params (Array) - Array of numbers. | ||||
|  * @returns (Float) - The sample standard deviation. | ||||
|  */ | ||||
| func StandardDeviationSample(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var err error | ||||
| 	err = core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
|  | ||||
| 	if arr.Length() == 0 { | ||||
| 		return values.NewFloat(math.NaN()), nil | ||||
| 	} | ||||
|  | ||||
| 	vp, err := variance(arr, values.NewInt(1)) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.NewFloat(math.NaN()), err | ||||
| 	} | ||||
|  | ||||
| 	return values.NewFloat(math.Pow(float64(vp), 0.5)), nil | ||||
| } | ||||
							
								
								
									
										28
									
								
								pkg/stdlib/math/stddev_sample_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pkg/stdlib/math/stddev_sample_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| 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 TestStandardDeviationSample(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.StandardDeviationSample( | ||||
| 			context.Background(), | ||||
| 			values.NewArrayWith( | ||||
| 				values.NewInt(1), | ||||
| 				values.NewInt(3), | ||||
| 				values.NewInt(6), | ||||
| 				values.NewInt(5), | ||||
| 				values.NewInt(2), | ||||
| 			), | ||||
| 		) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, 2.073644135332772) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										53
									
								
								pkg/stdlib/math/sum.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								pkg/stdlib/math/sum.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the sum of the values in a given array. | ||||
|  * @param array (Array) - Array of numbers. | ||||
|  * @returns (Float) - The sum of the values. | ||||
|  */ | ||||
| func Sum(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var err error | ||||
| 	err = core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
|  | ||||
| 	if arr.Length() == 0 { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	var sum float64 | ||||
|  | ||||
| 	arr.ForEach(func(value core.Value, idx int) bool { | ||||
| 		err = core.ValidateType(value, core.FloatType, core.IntType) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		sum += toFloat(value) | ||||
|  | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, nil | ||||
| 	} | ||||
|  | ||||
| 	return values.NewFloat(sum), nil | ||||
| } | ||||
							
								
								
									
										33
									
								
								pkg/stdlib/math/sum_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								pkg/stdlib/math/sum_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| 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 TestSum(t *testing.T) { | ||||
| 	Convey("Should return sum of values", t, func() { | ||||
| 		out, err := math.Sum(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(5), | ||||
| 			values.NewInt(2), | ||||
| 			values.NewInt(9), | ||||
| 			values.NewInt(2), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 18) | ||||
|  | ||||
| 		out, err = math.Sum(context.Background(), values.NewArrayWith( | ||||
| 			values.NewInt(-3), | ||||
| 			values.NewInt(-5), | ||||
| 			values.NewInt(2), | ||||
| 		)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, -6) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/tan.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/tan.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 tangent of a given number. | ||||
|  * @param value (Int|Float) - A number. | ||||
|  * @returns (Float) - The tangent. | ||||
|  */ | ||||
| func Tan(_ 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.Tan(toFloat(args[0]))), nil | ||||
| } | ||||
							
								
								
									
										29
									
								
								pkg/stdlib/math/tan_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								pkg/stdlib/math/tan_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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 TestTan(t *testing.T) { | ||||
| 	Convey("Should return tan value", t, func() { | ||||
| 		out, err := math.Tan(context.Background(), values.NewFloat(10)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, 0.6483608274590867) | ||||
|  | ||||
| 		out, err = math.Tan(context.Background(), values.NewInt(5)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, -3.3805150062465854) | ||||
|  | ||||
| 		out, err = math.Tan(context.Background(), values.NewInt(0)) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out, ShouldEqual, 0) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										39
									
								
								pkg/stdlib/math/variance.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								pkg/stdlib/math/variance.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| func variance(input *values.Array, sample values.Int) (values.Float, error) { | ||||
| 	if input.Length() == 0 { | ||||
| 		return values.NewFloat(math.NaN()), nil | ||||
| 	} | ||||
|  | ||||
| 	m, _ := mean(input) | ||||
|  | ||||
| 	var err error | ||||
| 	var variance values.Float | ||||
|  | ||||
| 	input.ForEach(func(value core.Value, idx int) bool { | ||||
| 		err = core.ValidateType(value, core.IntType, core.FloatType) | ||||
|  | ||||
| 		if err != nil { | ||||
| 			return false | ||||
| 		} | ||||
|  | ||||
| 		n := values.Float(toFloat(value)) | ||||
|  | ||||
| 		variance += (n - m) * (n - m) | ||||
|  | ||||
| 		return true | ||||
| 	}) | ||||
|  | ||||
| 	// When getting the mean of the squared differences | ||||
| 	// "sample" will allow us to know if it's a sample | ||||
| 	// or population and wether to subtract by one or not | ||||
| 	l := values.Float(input.Length() - (1 * sample)) | ||||
|  | ||||
| 	return variance / l, nil | ||||
| } | ||||
							
								
								
									
										36
									
								
								pkg/stdlib/math/variance_population.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								pkg/stdlib/math/variance_population.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the population variance of the values in a given array. | ||||
|  * @params (Array) - Array of numbers. | ||||
|  * @returns (Float) - The population variance. | ||||
|  */ | ||||
| func PopulationVariance(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var err error | ||||
| 	err = core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
|  | ||||
| 	if arr.Length() == 0 { | ||||
| 		return values.NewFloat(math.NaN()), nil | ||||
| 	} | ||||
|  | ||||
| 	return variance(arr, values.NewInt(0)) | ||||
| } | ||||
							
								
								
									
										28
									
								
								pkg/stdlib/math/variance_population_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pkg/stdlib/math/variance_population_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| 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 TestPopulationVariance(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.PopulationVariance( | ||||
| 			context.Background(), | ||||
| 			values.NewArrayWith( | ||||
| 				values.NewInt(1), | ||||
| 				values.NewInt(3), | ||||
| 				values.NewInt(6), | ||||
| 				values.NewInt(5), | ||||
| 				values.NewInt(2), | ||||
| 			), | ||||
| 		) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, 3.44) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										36
									
								
								pkg/stdlib/math/variance_sample.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								pkg/stdlib/math/variance_sample.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| package math | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| 	"math" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Returns the sample variance of the values in a given array. | ||||
|  * @params (Array) - Array of numbers. | ||||
|  * @returns (Float) - The sample variance. | ||||
|  */ | ||||
| func SampleVariance(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	var err error | ||||
| 	err = core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	err = core.ValidateType(args[0], core.ArrayType) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	arr := args[0].(*values.Array) | ||||
|  | ||||
| 	if arr.Length() == 0 { | ||||
| 		return values.NewFloat(math.NaN()), nil | ||||
| 	} | ||||
|  | ||||
| 	return variance(arr, values.NewInt(1)) | ||||
| } | ||||
							
								
								
									
										28
									
								
								pkg/stdlib/math/variance_sample_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								pkg/stdlib/math/variance_sample_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| 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 TestSampleVariance(t *testing.T) { | ||||
| 	Convey("Should return a value", t, func() { | ||||
| 		out, err := math.SampleVariance( | ||||
| 			context.Background(), | ||||
| 			values.NewArrayWith( | ||||
| 				values.NewInt(1), | ||||
| 				values.NewInt(3), | ||||
| 				values.NewInt(6), | ||||
| 				values.NewInt(5), | ||||
| 				values.NewInt(2), | ||||
| 			), | ||||
| 		) | ||||
|  | ||||
| 		So(err, ShouldBeNil) | ||||
| 		So(out.Unwrap(), ShouldEqual, 4.3) | ||||
| 	}) | ||||
| } | ||||
							
								
								
									
										26
									
								
								pkg/stdlib/types/is_nan.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								pkg/stdlib/types/is_nan.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| package types | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/core" | ||||
| 	"github.com/MontFerret/ferret/pkg/runtime/values" | ||||
| ) | ||||
|  | ||||
| /* | ||||
|  * Checks whether value is NaN. | ||||
|  * @param value (Value) - Input value of arbitrary type. | ||||
|  * @returns (Boolean) - Returns true if value is NaN, otherwise false. | ||||
|  */ | ||||
| func IsNaN(_ context.Context, args ...core.Value) (core.Value, error) { | ||||
| 	err := core.ValidateArgs(args, 1, 1) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return values.None, err | ||||
| 	} | ||||
|  | ||||
| 	if args[0].Type() != core.FloatType { | ||||
| 		return values.False, nil | ||||
| 	} | ||||
|  | ||||
| 	return values.IsNaN(args[0].(values.Float)), nil | ||||
| } | ||||
| @@ -24,6 +24,7 @@ func NewLib() map[string]core.Function { | ||||
| 		"IS_HTML_ELEMENT":  IsHTMLElement, | ||||
| 		"IS_HTML_DOCUMENT": IsHTMLDocument, | ||||
| 		"IS_BINARY":        IsBinary, | ||||
| 		"IS_NAN":           IsNaN, | ||||
| 		"TYPENAME":         TypeName, | ||||
| 	} | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user