patterngoMinor
Benchmark switch, binary search and if-else
Viewed 0 times
searchelsebinarybenchmarkandswitch
Problem
Just for curiosity I have done some benchmark for testing the best performance between switch, binary-search, and if-else statement.
here is the code :
```
package switchStatement
type Badge struct {
score int
badge string
}
func initiateBadges() []Badge {
badge := []Badge{
{score: 4501, badge: "gold-1.gif"},
{score: 10001, badge: "gold-2.gif"},
{score: 15001, badge: "gold-3.gif"},
{score: 30001, badge: "gold-4.gif"},
{score: 45001, badge: "gold-5.gif"},
{score: 50001, badge: "diamond-1.gif"},
{score: 100001, badge: "diamond-2.gif"},
{score: 150001, badge: "diamond-3.gif"},
{score: 200001, badge: "diamond-4.gif"},
{score: 500001, badge: "diamond-5.gif"},
}
return badge
}
func GetReputationBadgeImprove(score int) string {
badges := initiateBadges()
//search score using binary search
index := BinarySearchBadge(badges, score)
if index == -1 {
return "badges-off.jpg"
}
return badges[index].badge
}
func BinarySearchBadge(badges []Badge, score int) int {
low := 0
high := len(badges) - 1
middle := (high + low) / 2
for low score {
return middle
} else if badges[middle].score >= score {
high = middle - 1
} else {
low = middle + 1
}
middle = (high + low) / 2
}
return -1
}
func GetReputationBadgeImproveSwitchCase(score int) string {
switch {
case score >= 500001:
return "diamond-5.gif"
case score >= 200001:
return "diamond-4.gif"
case score >= 150001:
return "diamond-3.gif"
case score >= 100001:
return "diamond-2.gif"
case score >= 50001:
return "diamond-1.gif"
case score >= 45001:
return "gold-5.gif"
case score >= 30001:
return "gold-4.gif"
case score >= 15001:
return "gold-3.gif"
case score >= 10001:
return "gold-2.gif"
case
here is the code :
```
package switchStatement
type Badge struct {
score int
badge string
}
func initiateBadges() []Badge {
badge := []Badge{
{score: 4501, badge: "gold-1.gif"},
{score: 10001, badge: "gold-2.gif"},
{score: 15001, badge: "gold-3.gif"},
{score: 30001, badge: "gold-4.gif"},
{score: 45001, badge: "gold-5.gif"},
{score: 50001, badge: "diamond-1.gif"},
{score: 100001, badge: "diamond-2.gif"},
{score: 150001, badge: "diamond-3.gif"},
{score: 200001, badge: "diamond-4.gif"},
{score: 500001, badge: "diamond-5.gif"},
}
return badge
}
func GetReputationBadgeImprove(score int) string {
badges := initiateBadges()
//search score using binary search
index := BinarySearchBadge(badges, score)
if index == -1 {
return "badges-off.jpg"
}
return badges[index].badge
}
func BinarySearchBadge(badges []Badge, score int) int {
low := 0
high := len(badges) - 1
middle := (high + low) / 2
for low score {
return middle
} else if badges[middle].score >= score {
high = middle - 1
} else {
low = middle + 1
}
middle = (high + low) / 2
}
return -1
}
func GetReputationBadgeImproveSwitchCase(score int) string {
switch {
case score >= 500001:
return "diamond-5.gif"
case score >= 200001:
return "diamond-4.gif"
case score >= 150001:
return "diamond-3.gif"
case score >= 100001:
return "diamond-2.gif"
case score >= 50001:
return "diamond-1.gif"
case score >= 45001:
return "gold-5.gif"
case score >= 30001:
return "gold-4.gif"
case score >= 15001:
return "gold-3.gif"
case score >= 10001:
return "gold-2.gif"
case
Solution
In
(That said, I'm not convinced it matters — the compiler should probably optimize this anyway.)
I tried it and was very surprised to see that the benchmarks were still very poor. Turns out, you called the wrong function in your benchmark :-)
Note that this benchmark is still pretty flawed: you're only testing it with a couple of values, so depending on which they are, the order of the if/else statements are going to matter. You should use much more values, picked among a reasonable distribution instead.
GetReputationBadge, you're needlessly allocating strings by modifying the badge variable. It would be a fairer benchmark to write it in the following way:func GetReputationBadge(score int) string {
if score >= 500001 {
return "diamond-5.gif"
}
if score >= 200001 {
return "diamond-4.gif"
}
// etc.
if score >= 4501 {
return "gold-1.gif"
}
return "badges-off.jpg"
}(That said, I'm not convinced it matters — the compiler should probably optimize this anyway.)
I tried it and was very surprised to see that the benchmarks were still very poor. Turns out, you called the wrong function in your benchmark :-)
BenchmarkGetReputation1If calls benchmarkGetReputation insead of benchmarkGetReputationIf. Retrying it with this fixed leads to the expected result:BenchmarkGetReputation1-4 10000000 188 ns/op
BenchmarkGetReputation2-4 10000000 182 ns/op
BenchmarkGetReputation3-4 10000000 179 ns/op
BenchmarkGetReputation4-4 10000000 192 ns/op
BenchmarkGetReputation1Switch-4 300000000 4.55 ns/op
BenchmarkGetReputation2Switch-4 300000000 4.32 ns/op
BenchmarkGetReputation3Switch-4 300000000 4.63 ns/op
BenchmarkGetReputation4Switch-4 2000000000 0.84 ns/op
BenchmarkGetReputation1If-4 300000000 4.21 ns/op
BenchmarkGetReputation2If-4 300000000 4.19 ns/op
BenchmarkGetReputation3If-4 300000000 4.74 ns/op
BenchmarkGetReputation4If-4 2000000000 0.88 ns/opNote that this benchmark is still pretty flawed: you're only testing it with a couple of values, so depending on which they are, the order of the if/else statements are going to matter. You should use much more values, picked among a reasonable distribution instead.
Code Snippets
func GetReputationBadge(score int) string {
if score >= 500001 {
return "diamond-5.gif"
}
if score >= 200001 {
return "diamond-4.gif"
}
// etc.
if score >= 4501 {
return "gold-1.gif"
}
return "badges-off.jpg"
}BenchmarkGetReputation1-4 10000000 188 ns/op
BenchmarkGetReputation2-4 10000000 182 ns/op
BenchmarkGetReputation3-4 10000000 179 ns/op
BenchmarkGetReputation4-4 10000000 192 ns/op
BenchmarkGetReputation1Switch-4 300000000 4.55 ns/op
BenchmarkGetReputation2Switch-4 300000000 4.32 ns/op
BenchmarkGetReputation3Switch-4 300000000 4.63 ns/op
BenchmarkGetReputation4Switch-4 2000000000 0.84 ns/op
BenchmarkGetReputation1If-4 300000000 4.21 ns/op
BenchmarkGetReputation2If-4 300000000 4.19 ns/op
BenchmarkGetReputation3If-4 300000000 4.74 ns/op
BenchmarkGetReputation4If-4 2000000000 0.88 ns/opContext
StackExchange Code Review Q#149153, answer score: 2
Revisions (0)
No revisions yet.