2

I just start to learn Go, and I wrote a prime test program using the ProbablyPrime library.

package main

import (
    "fmt"
    "math/big"
    "math"
    "os"
    "strconv"
)

func prime_test(n int64, certainty int)(bool,float64){
    var probobility float64
    i := big.NewInt(n)
    isPrime := i.ProbablyPrime(certainty)
    probobility = 1 - 1/math.Pow(4,10)
    return isPrime, probobility
}

func why_not_prime(n int64)(int64){
    var i int64 
    for  i=2 ; i<n/2; i++ {
        if n%i == 0 {return i}
    }
    return i
}


func main() {
    var n int64
    var certainty int
    var isPrime bool
    var probobility float64 

    if len(os.Args) > 1 {
    n,_ = strconv.ParseInt(os.Args[1],64,64)
    certainty,_ = strconv.Atoi(os.Args[2])
    }

    isPrime, probobility = prime_test(n,certainty)
    if isPrime {
        fmt.Printf("%d is probably %0.8f%% a prime.", n, probobility*100)
    } else {
        var i int64
        i = why_not_prime(n)
        fmt.Printf("%d is a composite because it can be divided by %d", n, i)
    }
}

The code could be successfully compiled. When I run it, it always return 0 is a composite because it can be divided by 2.

I guess there's something wrong with the command line argument parsing. How to fix it?

cuongle
  • 74,024
  • 28
  • 151
  • 206
Nick
  • 8,451
  • 13
  • 57
  • 106
  • My guess is that `len(os.Args)` is not greater than one, and that that's why `n` is not being set to anything but `0`. I'd insert a print statement in the `if` statement to check whether or not this is the case. – exists-forall Jan 07 '15 at 07:41
  • @SelectricSimian Thank you. I put `fmt.Println("More than 1 arguments")` in the `if` statement, run it with `./prime.exe 39393993 10` and I got `More than 1 arguments 0 is a composite because it can be divided by 2` – Nick Jan 07 '15 at 07:58

1 Answers1

6

The problem is with this line:

n,_ = strconv.ParseInt(os.Args[1],64,64)

The documentation of ParseInt(s string, base int, bitSize int) (i int64, err error) states:

ParseInt interprets a string s in the given base (2 to 36) and returns the corresponding value i.

The base can be 36 at the most and you pass 64. In this case an error will be returned (which you discard by using the blank identifier _), and n will have the zero value which is 0 hence you see the output as

0 is a composite because it can be divided by 2

Solution:

Change the line in question to this:

n, _ = strconv.ParseInt(os.Args[1], 10, 64)

and it should work. Also you should not discard errors because you will run into cases like this. Instead handle them properly like this:

var err error
n, err = strconv.ParseInt(os.Args[1], 10, 64)
if err != nil {
    log.Fatal(err)
}

Note:

Also note that the first argument (os.Args[0] is the name of the executable), and since you expect and work with 2 extra arguments, you should check if the length of os.Args is greater than 2 not 1:

if len(os.Args) > 2 {
    // os.Args[1] and os.Args[2] is valid
}
icza
  • 389,944
  • 63
  • 907
  • 827
  • Thank you very much! After I add `n, err :...`, I got this error: `prog.go:36: n declared and not used` line 36 is the line `n, err: ...` If I remove this line and use `n,_ = ...` instead, the program runs correctly. So there's something wrong with the err handling. – Nick Jan 07 '15 at 08:32
  • @Nick That is because the `:=` assigns the result to new variables and you declared your `n` variable outside of the containing `if` block (so the one created inside the `if` block is not used, only the "outer" one). You can solve this by also declaring the `err` (either outside or inside the `if` block) and just use simple assignment: `n, err = ...`. – icza Jan 07 '15 at 08:36
  • I added `var err error` before `n, err = ...`, it works. Thank you very much! – Nick Jan 07 '15 at 08:48