-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add new mathx package * Fix docstring * Move type * Comments * Remove field * Change constant name
- Loading branch information
1 parent
91b9ef3
commit f08f1b0
Showing
6 changed files
with
285 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package mathx | ||
|
||
// Min returns the minimum of two ints. | ||
func Min(a, b int) int { | ||
if a < b { | ||
return a | ||
} | ||
return b | ||
} |
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,52 @@ | ||
package mathx | ||
|
||
import "testing" | ||
|
||
func TestMin(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
a int | ||
b int | ||
expected int | ||
}{ | ||
{ | ||
name: "pos-pos", | ||
a: 2, | ||
b: 3, | ||
expected: 2, | ||
}, | ||
{ | ||
name: "neg-neg", | ||
a: -2, | ||
b: -3, | ||
expected: -3, | ||
}, | ||
{ | ||
name: "pos-neg", | ||
a: 2, | ||
b: -3, | ||
expected: -3, | ||
}, | ||
{ | ||
name: "same", | ||
a: 2, | ||
b: 2, | ||
expected: 2, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got := Min(tt.a, tt.b) | ||
|
||
if got != tt.expected { | ||
t.Errorf("Min() = %d, want %d", got, tt.expected) | ||
} | ||
|
||
got = Min(tt.b, tt.a) | ||
|
||
if got != tt.expected { | ||
t.Errorf("Min() = %d, want %d", got, tt.expected) | ||
} | ||
}) | ||
} | ||
} |
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,33 @@ | ||
package mathx | ||
|
||
import ( | ||
"math" | ||
) | ||
|
||
const earthRadiusKm = 6371 | ||
|
||
// GetHaversineDistance finds the distance (in km) between two latitude/longitude | ||
// pairs using the Haversine formula. | ||
// For more details, see http://en.wikipedia.org/wiki/Haversine_formula. | ||
func GetHaversineDistance(lat1, lon1, lat2, lon2 float64) float64 { | ||
dlat1 := degreesToRadian(lat1) | ||
dlon1 := degreesToRadian(lon1) | ||
dlat2 := degreesToRadian(lat2) | ||
dlon2 := degreesToRadian(lon2) | ||
|
||
diffLat := dlat2 - dlat1 | ||
diffLon := dlon2 - dlon1 | ||
sinDiffLat := math.Sin(diffLat / 2) | ||
sinDiffLon := math.Sin(diffLon / 2) | ||
|
||
a := sinDiffLat*sinDiffLat + math.Cos(dlat1)* | ||
math.Cos(dlat2)*sinDiffLon*sinDiffLon | ||
c := 2 * math.Atan2(math.Sqrt(a), math.Sqrt(1-a)) | ||
d := earthRadiusKm * c | ||
|
||
return d | ||
} | ||
|
||
func degreesToRadian(d float64) float64 { | ||
return d * math.Pi / 180 | ||
} |
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,62 @@ | ||
package mathx | ||
|
||
import ( | ||
"math" | ||
"testing" | ||
) | ||
|
||
func TestGetHaversineDistance(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
lat1 float64 | ||
lon1 float64 | ||
lat2 float64 | ||
lon2 float64 | ||
expected float64 | ||
}{ | ||
{ | ||
name: "US-UK", | ||
lat1: 37.09024, | ||
lon1: -95.712891, | ||
lat2: 55.378051, | ||
lon2: -3.435973, | ||
expected: 6830.40, | ||
}, | ||
{ | ||
name: "US-US", | ||
lat1: 37.09024, | ||
lon1: -95.712891, | ||
lat2: 37.09024, | ||
lon2: -95.712891, | ||
expected: 0, | ||
}, | ||
{ | ||
name: "0-UK", | ||
lat1: 0, | ||
lon1: 0, | ||
lat2: 55.378051, | ||
lon2: -3.435973, | ||
expected: 6165.67, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got := GetHaversineDistance(tt.lat1, tt.lon1, tt.lat2, tt.lon2) | ||
|
||
if !compareFloats(got, tt.expected) { | ||
t.Errorf("GetHaversineDistance() = %f, want %f", got, tt.expected) | ||
} | ||
|
||
got = GetHaversineDistance(tt.lat2, tt.lon2, tt.lat1, tt.lon1) | ||
|
||
if !compareFloats(got, tt.expected) { | ||
t.Errorf("GetHaversineDistance() = %f, want %f", got, tt.expected) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func compareFloats(f1 float64, f2 float64) bool { | ||
diff := math.Abs(f1 - f2) | ||
return diff < 0.01 | ||
} |
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,36 @@ | ||
package mathx | ||
|
||
import ( | ||
"math" | ||
"math/rand" | ||
) | ||
|
||
// Random is a source of random values. | ||
type Random struct { | ||
src *rand.Rand | ||
} | ||
|
||
// NewRandom returns a new Random that uses the provided seed to generate | ||
// random values. | ||
func NewRandom(seed int64) Random { | ||
src := rand.New(rand.NewSource(seed)) | ||
return Random{src: src} | ||
} | ||
|
||
// GetRandomInt returns a non-negative pseudo-random number in the interval [0, max). | ||
// It returns 0 if max <= 0. | ||
func (r *Random) GetRandomInt(max int) int { | ||
if max <= 0 { | ||
return 0 | ||
} | ||
return r.src.Intn(max) | ||
} | ||
|
||
// GetExpDistributedInt returns a exponentially distributed number in the interval | ||
// [0, +math.MaxFloat64), rounded to the nearest int. Callers can adjust the rate of the | ||
// function through the rate parameter. | ||
func (r *Random) GetExpDistributedInt(rate float64) int { | ||
f := r.src.ExpFloat64() / rate | ||
index := int(math.Round(f)) | ||
return index | ||
} |
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,93 @@ | ||
package mathx | ||
|
||
import "testing" | ||
|
||
const seed = 1658340109320624211 | ||
|
||
func TestRandom_GetRandomInt(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
max int | ||
expected1 int | ||
expected2 int | ||
}{ | ||
{ | ||
name: "random", | ||
max: 10, | ||
expected1: 6, | ||
expected2: 8, | ||
}, | ||
{ | ||
name: "zero", | ||
max: 0, | ||
expected1: 0, | ||
expected2: 0, | ||
}, | ||
{ | ||
name: "negative", | ||
max: -10, | ||
expected1: 0, | ||
expected2: 0, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
r := NewRandom(seed) | ||
got := r.GetRandomInt(tt.max) | ||
|
||
if got != tt.expected1 { | ||
t.Errorf("GetRandomInt() = %d, want %d", got, tt.expected1) | ||
} | ||
|
||
got = r.GetRandomInt(tt.max) | ||
|
||
if got != tt.expected2 { | ||
t.Errorf("GetRandomInt() = %d, want %d", got, tt.expected2) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestRandom_GetExpDistributedInt(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
rate float64 | ||
expected1 int | ||
expected2 int | ||
}{ | ||
{ | ||
name: "rate-1", | ||
rate: 1, | ||
expected1: 1, | ||
expected2: 0, | ||
}, | ||
{ | ||
name: "rate-0.1", | ||
rate: 0.1, | ||
expected1: 5, | ||
expected2: 2, | ||
}, | ||
{ | ||
name: "rate-5", | ||
rate: 5, | ||
expected1: 0, | ||
expected2: 0, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
r := NewRandom(seed) | ||
got := r.GetExpDistributedInt(tt.rate) | ||
|
||
if got != tt.expected1 { | ||
t.Errorf("GetExpDistributedInt() = %d, want %d", got, tt.expected1) | ||
} | ||
|
||
got = r.GetExpDistributedInt(tt.rate) | ||
|
||
if got != tt.expected2 { | ||
t.Errorf("GetExpDistributedInt() = %d, want %d", got, tt.expected2) | ||
} | ||
}) | ||
} | ||
} |