-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement ModScalar, Min, Max operations (#12)
- Loading branch information
Showing
9 changed files
with
580 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= | ||
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package govec | ||
|
||
// V2F | ||
|
||
// Max returns a vector with the maximum of each component of the two vectors. | ||
func (v V2F[T]) Max(v2 V2F[T]) V2F[T] { | ||
return V2F[T]{X: max(v.X, v2.X), Y: max(v.Y, v2.Y)} | ||
} | ||
|
||
// MaxInPlace updates the vector in-place with the maximum of each component of the two vectors. | ||
func (v *V2F[T]) MaxInPlace(v2 V2F[T]) { | ||
v.X = max(v.X, v2.X) | ||
v.Y = max(v.Y, v2.Y) | ||
} | ||
|
||
// MaxComp returns a vector with the maximum of each component of the vector and the given components. | ||
func (v V2F[T]) MaxComp(x T, y T) V2F[T] { | ||
return V2F[T]{X: max(v.X, x), Y: max(v.Y, y)} | ||
} | ||
|
||
// MaxCompInPlace updates the vector in-place with the maximum of each component of the vector and the given components. | ||
func (v *V2F[T]) MaxCompInPlace(x T, y T) { | ||
v.X = max(v.X, x) | ||
v.Y = max(v.Y, y) | ||
} | ||
|
||
// V3F | ||
|
||
// Max returns a vector with the maximum of each component of the two vectors. | ||
func (v V3F[T]) Max(v2 V3F[T]) V3F[T] { | ||
return V3F[T]{X: max(v.X, v2.X), Y: max(v.Y, v2.Y), Z: max(v.Z, v2.Z)} | ||
} | ||
|
||
// MaxInPlace updates the vector in-place with the maximum of each component of the two vectors. | ||
func (v *V3F[T]) MaxInPlace(v2 V3F[T]) { | ||
v.X = max(v.X, v2.X) | ||
v.Y = max(v.Y, v2.Y) | ||
v.Z = max(v.Z, v2.Z) | ||
} | ||
|
||
// MaxComp returns a vector with the maximum of each component of the vector and the given components. | ||
func (v V3F[T]) MaxComp(x T, y T, z T) V3F[T] { | ||
return V3F[T]{X: max(v.X, x), Y: max(v.Y, y), Z: max(v.Z, z)} | ||
} | ||
|
||
// MaxCompInPlace updates the vector in-place with the maximum of each component of the vector and the given components. | ||
func (v *V3F[T]) MaxCompInPlace(x T, y T, z T) { | ||
v.X = max(v.X, x) | ||
v.Y = max(v.Y, y) | ||
v.Z = max(v.Z, z) | ||
} | ||
|
||
// V2I | ||
|
||
// Max returns a vector with the maximum of each component of the two vectors. | ||
func (v V2I[T]) Max(v2 V2I[T]) V2I[T] { | ||
return V2I[T]{X: max(v.X, v2.X), Y: max(v.Y, v2.Y)} | ||
} | ||
|
||
// MaxInPlace updates the vector in-place with the maximum of each component of the two vectors. | ||
func (v *V2I[T]) MaxInPlace(v2 V2I[T]) { | ||
v.X = max(v.X, v2.X) | ||
v.Y = max(v.Y, v2.Y) | ||
} | ||
|
||
// MaxComp returns a vector with the maximum of each component of the vector and the given components. | ||
func (v V2I[T]) MaxComp(x T, y T) V2I[T] { | ||
return V2I[T]{X: max(v.X, x), Y: max(v.Y, y)} | ||
} | ||
|
||
// MaxCompInPlace updates the vector in-place with the maximum of each component of the vector and the given components. | ||
func (v *V2I[T]) MaxCompInPlace(x T, y T) { | ||
v.X = max(v.X, x) | ||
v.Y = max(v.Y, y) | ||
} | ||
|
||
// V3I | ||
|
||
// Max returns a vector with the maximum of each component of the two vectors. | ||
func (v V3I[T]) Max(v2 V3I[T]) V3I[T] { | ||
return V3I[T]{X: max(v.X, v2.X), Y: max(v.Y, v2.Y), Z: max(v.Z, v2.Z)} | ||
} | ||
|
||
// MaxInPlace updates the vector in-place with the maximum of each component of the two vectors. | ||
func (v *V3I[T]) MaxInPlace(v2 V3I[T]) { | ||
v.X = max(v.X, v2.X) | ||
v.Y = max(v.Y, v2.Y) | ||
v.Z = max(v.Z, v2.Z) | ||
} | ||
|
||
// MaxComp returns a vector with the maximum of each component of the vector and the given components. | ||
func (v V3I[T]) MaxComp(x T, y T, z T) V3I[T] { | ||
return V3I[T]{X: max(v.X, x), Y: max(v.Y, y), Z: max(v.Z, z)} | ||
} | ||
|
||
// MaxCompInPlace updates the vector in-place with the maximum of each component of the vector and the given components. | ||
func (v *V3I[T]) MaxCompInPlace(x T, y T, z T) { | ||
v.X = max(v.X, x) | ||
v.Y = max(v.Y, y) | ||
v.Z = max(v.Z, z) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
package govec | ||
|
||
import ( | ||
"golang.org/x/exp/constraints" | ||
"testing" | ||
) | ||
|
||
func runMaxTestsFloat[T constraints.Float](t *testing.T, unitName string) { | ||
testCases := []struct { | ||
name string | ||
v1x, v1y, v1z T | ||
v2x, v2y, v2z T | ||
expectedX, expectedY, expectedZ T | ||
}{ | ||
{"all same", 1, 1, 1, 1, 1, 1, 1, 1, 1}, | ||
{"v1 max", 2, 3, 4, 1, 2, 3, 2, 3, 4}, | ||
{"v2 max", 1, 2, 3, 2, 3, 4, 2, 3, 4}, | ||
{"v1 max neg", -1, -2, -3, -2, -3, -4, -1, -2, -3}, | ||
{"v2 max neg", -2, -3, -4, -1, -2, -3, -1, -2, -3}, | ||
{"v1 max mixed", -1, 2, -3, -2, 1, -4, -1, 2, -3}, | ||
{"v2 max mixed", -2, 1, -4, -1, 2, -3, -1, 2, -3}, | ||
{"rand 1", 3, 5, -3, 15, 2, 4, 15, 5, 4}, | ||
{"rand 2", 120, 127, -2, -51, 36, 1, 120, 127, 1}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name+" V2F["+unitName+"]", func(t *testing.T) { | ||
// Bring to proper type | ||
v1x, v1y := tc.v1x, tc.v1y | ||
v2x, v2y := tc.v2x, tc.v2y | ||
expectedX, expectedY := tc.expectedX, tc.expectedY | ||
|
||
expected := V2F[T]{X: expectedX, Y: expectedY} | ||
|
||
// Results of operation variants | ||
vMax := V2F[T]{X: v1x, Y: v1y}.Max(V2F[T]{X: v2x, Y: v2y}) | ||
vMaxComp := V2F[T]{X: v1x, Y: v1y}.MaxComp(v2x, v2y) | ||
vMaxInPlace := V2F[T]{X: v1x, Y: v1y} | ||
vMaxInPlace.MaxInPlace(V2F[T]{X: v2x, Y: v2y}) | ||
vMaxCompInPlace := V2F[T]{X: v1x, Y: v1y} | ||
vMaxCompInPlace.MaxCompInPlace(v2x, v2y) | ||
results := []V2F[T]{vMax, vMaxComp, vMaxInPlace, vMaxCompInPlace} | ||
|
||
// Check results | ||
for i, result := range results { | ||
if !almostEqual(result.X, expected.X, 1e-9) || !almostEqual(result.Y, expected.Y, 1e-9) { | ||
t.Errorf("Expected %v, got %v when testing variant #%v", expected, result, i) | ||
} | ||
} | ||
}) | ||
|
||
t.Run(tc.name+" V3F["+unitName+"]", func(t *testing.T) { | ||
// Bring to proper type | ||
v1x, v1y, v1z := tc.v1x, tc.v1y, tc.v1z | ||
v2x, v2y, v2z := tc.v2x, tc.v2y, tc.v2z | ||
expectedX, expectedY, expectedZ := tc.expectedX, tc.expectedY, tc.expectedZ | ||
|
||
expected := V3F[T]{X: expectedX, Y: expectedY, Z: expectedZ} | ||
|
||
// Results of operation variants | ||
vMax := V3F[T]{X: v1x, Y: v1y, Z: v1z}.Max(V3F[T]{X: v2x, Y: v2y, Z: v2z}) | ||
vMaxComp := V3F[T]{X: v1x, Y: v1y, Z: v1z}.MaxComp(v2x, v2y, v2z) | ||
vMaxInPlace := V3F[T]{X: v1x, Y: v1y, Z: v1z} | ||
vMaxInPlace.MaxInPlace(V3F[T]{X: v2x, Y: v2y, Z: v2z}) | ||
vMaxCompInPlace := V3F[T]{X: v1x, Y: v1y, Z: v1z} | ||
vMaxCompInPlace.MaxCompInPlace(v2x, v2y, v2z) | ||
results := []V3F[T]{vMax, vMaxComp, vMaxInPlace, vMaxCompInPlace} | ||
|
||
// Check results | ||
for i, result := range results { | ||
if !almostEqual(result.X, expected.X, 1e-9) || !almostEqual(result.Y, expected.Y, 1e-9) || !almostEqual(result.Z, expected.Z, 1e-9) { | ||
t.Errorf("Expected %v, got %v when testing variant #%v", expected, result, i) | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func runMaxTestsInteger[T constraints.Signed](t *testing.T, unitName string) { | ||
testCases := []struct { | ||
name string | ||
v1x, v1y, v1z T | ||
v2x, v2y, v2z T | ||
expectedX, expectedY, expectedZ T | ||
}{ | ||
{"all same", 1, 1, 1, 1, 1, 1, 1, 1, 1}, | ||
{"v1 max", 2, 3, 4, 1, 2, 3, 2, 3, 4}, | ||
{"v2 max", 1, 2, 3, 2, 3, 4, 2, 3, 4}, | ||
{"v1 max neg", -1, -2, -3, -2, -3, -4, -1, -2, -3}, | ||
{"v2 max neg", -2, -3, -4, -1, -2, -3, -1, -2, -3}, | ||
{"v1 max mixed", -1, 2, -3, -2, 1, -4, -1, 2, -3}, | ||
{"v2 max mixed", -2, 1, -4, -1, 2, -3, -1, 2, -3}, | ||
{"rand 1", 3, 5, -3, 15, 2, 4, 15, 5, 4}, | ||
{"rand 2", 120, 127, -2, -51, 36, 1, 120, 127, 1}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name+" V2I["+unitName+"]", func(t *testing.T) { | ||
// Bring to proper type | ||
v1x, v1y := tc.v1x, tc.v1y | ||
v2x, v2y := tc.v2x, tc.v2y | ||
expectedX, expectedY := tc.expectedX, tc.expectedY | ||
|
||
expected := V2I[T]{X: expectedX, Y: expectedY} | ||
|
||
// Results of operation variants | ||
vMax := V2I[T]{X: v1x, Y: v1y}.Max(V2I[T]{X: v2x, Y: v2y}) | ||
vMaxComp := V2I[T]{X: v1x, Y: v1y}.MaxComp(v2x, v2y) | ||
vMaxInPlace := V2I[T]{X: v1x, Y: v1y} | ||
vMaxInPlace.MaxInPlace(V2I[T]{X: v2x, Y: v2y}) | ||
vMaxCompInPlace := V2I[T]{X: v1x, Y: v1y} | ||
vMaxCompInPlace.MaxCompInPlace(v2x, v2y) | ||
results := []V2I[T]{vMax, vMaxComp, vMaxInPlace, vMaxCompInPlace} | ||
|
||
// Check results | ||
for i, result := range results { | ||
if result.X != expected.X || result.Y != expected.Y { | ||
t.Errorf("Expected %v, got %v when testing variant #%v", expected, result, i) | ||
} | ||
} | ||
}) | ||
|
||
t.Run(tc.name+" V3I["+unitName+"]", func(t *testing.T) { | ||
// Bring to proper type | ||
v1x, v1y, v1z := tc.v1x, tc.v1y, tc.v1z | ||
v2x, v2y, v2z := tc.v2x, tc.v2y, tc.v2z | ||
expectedX, expectedY, expectedZ := tc.expectedX, tc.expectedY, tc.expectedZ | ||
|
||
expected := V3I[T]{X: expectedX, Y: expectedY, Z: expectedZ} | ||
|
||
// Results of operation variants | ||
vMax := V3I[T]{X: v1x, Y: v1y, Z: v1z}.Max(V3I[T]{X: v2x, Y: v2y, Z: v2z}) | ||
vMaxComp := V3I[T]{X: v1x, Y: v1y, Z: v1z}.MaxComp(v2x, v2y, v2z) | ||
vMaxInPlace := V3I[T]{X: v1x, Y: v1y, Z: v1z} | ||
vMaxInPlace.MaxInPlace(V3I[T]{X: v2x, Y: v2y, Z: v2z}) | ||
vMaxCompInPlace := V3I[T]{X: v1x, Y: v1y, Z: v1z} | ||
vMaxCompInPlace.MaxCompInPlace(v2x, v2y, v2z) | ||
results := []V3I[T]{vMax, vMaxComp, vMaxInPlace, vMaxCompInPlace} | ||
|
||
// Check results | ||
for i, result := range results { | ||
if result.X != expected.X || result.Y != expected.Y || result.Z != expected.Z { | ||
t.Errorf("Expected %v, got %v when testing variant #%v", expected, result, i) | ||
} | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestMax(t *testing.T) { | ||
runMaxTestsFloat[float64](t, "float64") | ||
runMaxTestsFloat[float32](t, "float32") | ||
runMaxTestsInteger[int64](t, "int64") | ||
runMaxTestsInteger[int32](t, "int32") | ||
runMaxTestsInteger[int16](t, "int16") | ||
runMaxTestsInteger[int8](t, "int8") | ||
runMaxTestsInteger[int](t, "int") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package govec | ||
|
||
// V2F | ||
|
||
// Min returns a vector with the minimum of each component of the two vectors. | ||
func (v V2F[T]) Min(v2 V2F[T]) V2F[T] { | ||
return V2F[T]{X: min(v.X, v2.X), Y: min(v.Y, v2.Y)} | ||
} | ||
|
||
// MinInPlace updates the vector in-place with the minimum of each component of the two vectors. | ||
func (v *V2F[T]) MinInPlace(v2 V2F[T]) { | ||
v.X = min(v.X, v2.X) | ||
v.Y = min(v.Y, v2.Y) | ||
} | ||
|
||
// MinComp returns a vector with the minimum of each component of the vector and the given components. | ||
func (v V2F[T]) MinComp(x T, y T) V2F[T] { | ||
return V2F[T]{X: min(v.X, x), Y: min(v.Y, y)} | ||
} | ||
|
||
// MinCompInPlace updates the vector in-place with the minimum of each component of the vector and the given components. | ||
func (v *V2F[T]) MinCompInPlace(x T, y T) { | ||
v.X = min(v.X, x) | ||
v.Y = min(v.Y, y) | ||
} | ||
|
||
// V3F | ||
|
||
// Min returns a vector with the minimum of each component of the two vectors. | ||
func (v V3F[T]) Min(v2 V3F[T]) V3F[T] { | ||
return V3F[T]{X: min(v.X, v2.X), Y: min(v.Y, v2.Y), Z: min(v.Z, v2.Z)} | ||
} | ||
|
||
// MinInPlace updates the vector in-place with the minimum of each component of the two vectors. | ||
func (v *V3F[T]) MinInPlace(v2 V3F[T]) { | ||
v.X = min(v.X, v2.X) | ||
v.Y = min(v.Y, v2.Y) | ||
v.Z = min(v.Z, v2.Z) | ||
} | ||
|
||
// MinComp returns a vector with the minimum of each component of the vector and the given components. | ||
func (v V3F[T]) MinComp(x T, y T, z T) V3F[T] { | ||
return V3F[T]{X: min(v.X, x), Y: min(v.Y, y), Z: min(v.Z, z)} | ||
} | ||
|
||
// MinCompInPlace updates the vector in-place with the minimum of each component of the vector and the given components. | ||
func (v *V3F[T]) MinCompInPlace(x T, y T, z T) { | ||
v.X = min(v.X, x) | ||
v.Y = min(v.Y, y) | ||
v.Z = min(v.Z, z) | ||
} | ||
|
||
// V2I | ||
|
||
// Min returns a vector with the minimum of each component of the two vectors. | ||
func (v V2I[T]) Min(v2 V2I[T]) V2I[T] { | ||
return V2I[T]{X: min(v.X, v2.X), Y: min(v.Y, v2.Y)} | ||
} | ||
|
||
// MinInPlace updates the vector in-place with the minimum of each component of the two vectors. | ||
func (v *V2I[T]) MinInPlace(v2 V2I[T]) { | ||
v.X = min(v.X, v2.X) | ||
v.Y = min(v.Y, v2.Y) | ||
} | ||
|
||
// MinComp returns a vector with the minimum of each component of the vector and the given components. | ||
func (v V2I[T]) MinComp(x T, y T) V2I[T] { | ||
return V2I[T]{X: min(v.X, x), Y: min(v.Y, y)} | ||
} | ||
|
||
// MinCompInPlace updates the vector in-place with the minimum of each component of the vector and the given components. | ||
func (v *V2I[T]) MinCompInPlace(x T, y T) { | ||
v.X = min(v.X, x) | ||
v.Y = min(v.Y, y) | ||
} | ||
|
||
// V3I | ||
|
||
// Min returns a vector with the minimum of each component of the two vectors. | ||
func (v V3I[T]) Min(v2 V3I[T]) V3I[T] { | ||
return V3I[T]{X: min(v.X, v2.X), Y: min(v.Y, v2.Y), Z: min(v.Z, v2.Z)} | ||
} | ||
|
||
// MinInPlace updates the vector in-place with the minimum of each component of the two vectors. | ||
func (v *V3I[T]) MinInPlace(v2 V3I[T]) { | ||
v.X = min(v.X, v2.X) | ||
v.Y = min(v.Y, v2.Y) | ||
v.Z = min(v.Z, v2.Z) | ||
} | ||
|
||
// MinComp returns a vector with the minimum of each component of the vector and the given components. | ||
func (v V3I[T]) MinComp(x T, y T, z T) V3I[T] { | ||
return V3I[T]{X: min(v.X, x), Y: min(v.Y, y), Z: min(v.Z, z)} | ||
} | ||
|
||
// MinCompInPlace updates the vector in-place with the minimum of each component of the vector and the given components. | ||
func (v *V3I[T]) MinCompInPlace(x T, y T, z T) { | ||
v.X = min(v.X, x) | ||
v.Y = min(v.Y, y) | ||
v.Z = min(v.Z, z) | ||
} |
Oops, something went wrong.