From 2701bcc4d2e3f7d25fc0b642e63a2c658e16492a Mon Sep 17 00:00:00 2001 From: dudaodong Date: Tue, 30 May 2023 11:41:54 +0800 Subject: [PATCH] feat: add Cos, Sin, LCM, GCD function --- internal/assert.go | 47 +++++++++++++++++++++++++++++ mathutil/mathutil.go | 63 +++++++++++++++++++++++++++++++++++++++ mathutil/mathutil_test.go | 58 +++++++++++++++++++++++++++++++++++ 3 files changed, 168 insertions(+) diff --git a/internal/assert.go b/internal/assert.go index 3e817d8..ec4954b 100644 --- a/internal/assert.go +++ b/internal/assert.go @@ -5,6 +5,7 @@ package internal import ( + "bytes" "fmt" "reflect" "runtime" @@ -36,6 +37,52 @@ func (a *Assert) Equal(expected, actual interface{}) { } } +// EqualValues asserts that two objects are equal or convertable to the same types and equal. +// https://github.com/stretchr/testify/assert/assertions.go +func (a *Assert) EqualValues(expected, actual interface{}) { + if !objectsAreEqualValues(expected, actual) { + makeTestFailed(a.T, a.CaseName, expected, actual) + } +} + +func objectsAreEqualValues(expected, actual interface{}) bool { + if objectsAreEqual(expected, actual) { + return true + } + + actualType := reflect.TypeOf(actual) + if actualType == nil { + return false + } + expectedValue := reflect.ValueOf(expected) + if expectedValue.IsValid() && expectedValue.Type().ConvertibleTo(actualType) { + // Attempt comparison after type conversion + return reflect.DeepEqual(expectedValue.Convert(actualType).Interface(), actual) + } + + return false +} + +func objectsAreEqual(expected, actual interface{}) bool { + if expected == nil || actual == nil { + return expected == actual + } + + exp, ok := expected.([]byte) + if !ok { + return reflect.DeepEqual(expected, actual) + } + + act, ok := actual.([]byte) + if !ok { + return false + } + if exp == nil || act == nil { + return exp == nil && act == nil + } + return bytes.Equal(exp, act) +} + // NotEqual check if expected is not equal with actual func (a *Assert) NotEqual(expected, actual interface{}) { if compare(expected, actual) == compareEqual { diff --git a/mathutil/mathutil.go b/mathutil/mathutil.go index 1cde95b..35bc1a7 100644 --- a/mathutil/mathutil.go +++ b/mathutil/mathutil.go @@ -126,3 +126,66 @@ func IsPrime(n int) bool { return true } + +// GCD return greatest common divisor (GCD) of integers. +func GCD(integers ...int) int { + result := integers[0] + + for k := range integers { + result = gcd(integers[k], result) + + if result == 1 { + return 1 + } + } + + return result +} + +// find greatest common divisor (GCD) +func gcd(a, b int) int { + if b == 0 { + return a + } + + return gcd(b, a%b) +} + +// LCM return Least Common Multiple (LCM) of integers. +func LCM(integers ...int) int { + result := integers[0] + + for k := range integers { + result = lcm(integers[k], result) + } + + return result +} + +// find Least Common Multiple (LCM) via GCD. +func lcm(a, b int) int { + if a == 0 || b == 0 { + panic("lcm function: provide non zero integers only.") + } + return a * b / gcd(a, b) +} + +// Cos returns the cosine of the radian argument. +func Cos(radian float64, precision ...int) float64 { + t := 1.0 / (2.0 * math.Pi) + radian *= t + radian -= 0.25 + math.Floor(radian+0.25) + radian *= 16.0 * (math.Abs(radian) - 0.5) + radian += 0.225 * radian * (math.Abs(radian) - 1.0) + + if len(precision) == 1 { + return TruncRound(radian, precision[0]) + } + + return TruncRound(radian, 3) +} + +// Cos returns the sine of the radian argument. +func Sin(radian float64, precision ...int) float64 { + return Cos((math.Pi / 2) - radian) +} diff --git a/mathutil/mathutil_test.go b/mathutil/mathutil_test.go index fa15e3b..a10f5d0 100644 --- a/mathutil/mathutil_test.go +++ b/mathutil/mathutil_test.go @@ -114,3 +114,61 @@ func TestIsPrime(t *testing.T) { assert.Equal(true, IsPrime(3)) assert.Equal(false, IsPrime(4)) } + +func TestGCD(t *testing.T) { + assert := internal.NewAssert(t, "TestGCD") + + assert.Equal(1, GCD(1, 1)) + assert.Equal(1, GCD(1, -1)) + assert.Equal(-1, GCD(-1, 1)) + assert.Equal(-1, GCD(-1, -1)) + + assert.Equal(1, GCD(1, 0)) + assert.Equal(1, GCD(0, 1)) + assert.Equal(-1, GCD(-1, 0)) + assert.Equal(-1, GCD(0, -1)) + + assert.Equal(1, GCD(1, -2)) + assert.Equal(1, GCD(-2, 1)) + assert.Equal(-1, GCD(-1, 2)) + assert.Equal(-1, GCD(2, -1)) + + assert.Equal(-1, GCD(-1, -2)) + assert.Equal(-1, GCD(-2, -1)) + + assert.Equal(-9, GCD(-27, -36)) + assert.Equal(3, GCD(3, 6, 9)) +} + +func TestLCM(t *testing.T) { + assert := internal.NewAssert(t, "TestLCM") + + assert.Equal(1, LCM(1)) + assert.Equal(-1, LCM(-1)) + assert.Equal(-1, LCM(1, -1)) + assert.Equal(1, LCM(-1, 1)) + assert.Equal(1, LCM(1, 1)) + assert.Equal(-1, LCM(-1, -1)) + assert.Equal(2, LCM(1, 2)) + assert.Equal(18, LCM(3, 6, 9)) +} + +func TestCos(t *testing.T) { + assert := internal.NewAssert(t, "TestCos") + + assert.EqualValues(1, Cos(0)) + assert.EqualValues(-0.447, Cos(90)) + assert.EqualValues(-0.598, Cos(180)) + assert.EqualValues(-1, Cos(math.Pi)) + assert.EqualValues(0, Cos(math.Pi/2)) +} + +func TestSin(t *testing.T) { + assert := internal.NewAssert(t, "TestSin") + + assert.EqualValues(0, Sin(0)) + assert.EqualValues(0.894, Sin(90)) + assert.EqualValues(-0.801, Sin(180)) + assert.EqualValues(0, Sin(math.Pi)) + assert.EqualValues(1, Sin(math.Pi/2)) +}