Instead of trying to get a performance increase with a faster solution let's review your program and try to make it a solid one.
The variables
var current_prime int
var prime bool
current_prime = 0
Check this example:
var a int = 0 // 0
var b int // default int value is 0, similar to above
var c = 0 // type is int, similar to above
d := 0 // same
The latter is short and nice, I suggest you to stick to it. var
notation is required in package block (globals), when explicit type is needed and to overcome variable shading.
You've declared the prime variable, but is first used only within the outer loop, so declare it there. Try to introduce new variables first time you need them.
The outer loop
for {
// ...
}
Your for loop is infinite since there is no loop condition or a break statement. The current_prime will overflow and you'll start printing the same/wrong numbers.
As pointed by peterSO, the first prime number is 2, so we can start with it.
for current_prime := 2; i > 0; i++ {
// ...
}
When overflow occurs the loop condition will be falsy and the loop will terminate.
To take it further it is better not to expect int
overflow and use MaxInt* constants from math package. Apart from guaranteed proper uint
overflow there is nothing solid about int
, so it is better not to abuse its behavior.
The inner loop
for i := 2; i < current_prime; i++ {
if current_prime % i == 0 {
prime = false
i = current_prime
}
}
It took me a while to understand the purpose of i = current_prime
line. No. This is not nice, use break
to end the loop.
This one is much cleaner to me:
for i := 2; i < current_prime; i++ {
if current_prime % i == 0 {
prime = false
break
}
}
Let's take it further. After the inner loop you test the prime variable and print the current_prime number. So when you get current_prime % i == 0
as true you already know current_prime is not a prime number and you need to continue the outer loop. For such purpose Golang has labels that perfectly solve the task:
outer:
for prime := 2; prime > 0; prime++ {
for i := 2; i < prime; i++ {
if prime % i == 0 {
continue outer
}
}
fmt.Println(prime)
}
A continue outer
statement will break the inner loop and continue the outer one.
When you place a label one line before the loop you may break and continue right to it. It helps escaping nested loops a lot.
Finally lets choose the appropriate types for our task. Since we don't need the signed numbers we can use uint
instead of int
. Better, lets use uint64
directly to guaranty the maximum available type. The nice thing about unsigned numbers is that Golang guarantees that they will overflow properly so we can check for zero value to terminate the loop.
Example rewrite
Here follows a possible rewrite of your original program:
package main
import "fmt"
func main() {
outer:
for prime := uint64(2); prime > 0; prime++ {
for i := uint64(2); i < prime; i++ {
if prime % i == 0 {
continue outer
}
}
fmt.Println(prime)
}
}
Things accomplished:
- proper types are used
- overflow is handled
- no hacks