Like Max, my strong suspicion was that the slowness in Go was related to poor I/O performance. I tested this hypothesis:
package main
import "fmt"
import "os"
import "time"
func main(){
now := time.Now()
input,_ := os.Open("testing/test_cases.txt")
defer input.Close()
output,_ := os.Create("testing/Goutput.txt")
defer output.Close()
var ncases int
var p float64
fmt.Fscanf(input,"%d",&ncases)
fmt.Println("Opened files in ", time.Since(now), "seconds")
now = time.Now()
cases := make([]float64, ncases)
fmt.Println("Made array in ", time.Since(now), "seconds")
now = time.Now()
for i := 0; i < ncases; i++ {
fmt.Fscanf(input,"%f",&cases[i])
}
fmt.Println("Read data in ", time.Since(now), "seconds")
now = time.Now()
for i := 0; i < ncases; i++ {
p = cases[i]
if p >= 0.5 {
cases[i] = 10000 * (1-p) * (2*p-1) + 10000
} else {
cases[i] = p*(1-2*p)*10000 + 10000
}
}
fmt.Println("Processed data in ", time.Since(now), "seconds")
now = time.Now()
for i := 0; i < ncases; i++ {
fmt.Fprintln(output, cases[i])
}
fmt.Println("Output processed data in ", time.Since(now), "seconds")
}
Running it produced this output:
Opened files in 2.011228ms seconds
Made array in 109.904us seconds
Read data in 4.524544608s seconds
Processed data in 10.083329ms seconds
Output processed data in 1.703542918s seconds
So it appears that on my machine, all of the math occurs in about 10ms, but the I/O is slow, confirming the hypothesis. As pointed out by Janne in the comments, there are likely faster options than fmt
.
Update: For example, wrapping input
and output
with bufio
's Readers and Writers:
binput := bufio.NewReader(input)
boutput := bufio.NewWriter(output)
and using binput
and boutput
for buffered I/O, your original version runs in 2.1 seconds on my machine, somewhat faster than Python's 2.7.
Update 2: I noticed that I was getting different results by just switching to buffered I/O.
It turns out that you also need to adjust your format strings to include the
, as you do in the C version. I think this is actually more correct either way, but it looks like you can get away with it while unbuffered.
It's also important to Flush()
your buffered output, which I did but didn't mention before.
Here's my complete buffered solution:
package main
import "fmt"
import "os"
import "bufio"
import "time"
func main(){
now := time.Now()
nbinput, _ := os.Open("testing/test_cases.txt")
defer nbinput.Close()
nboutput, _ := os.Create("testing/Goutput.txt")
defer nboutput.Close()
binput := bufio.NewReader(nbinput)
boutput := bufio.NewWriter(nboutput)
var ncases int
var gain, p float64
fmt.Fscanf(binput,"%d
",&ncases)
for i := 0; i < ncases; i++ {
fmt.Fscanf(binput, "%f
", &p)
if p >= 0.5 {
gain = 10000 * (1-p) * (2*p -1)
} else {
gain = p*(1-2*p)*10000
}
fmt.Fprintln(boutput, gain+10000)
}
boutput.Flush()
fmt.Println("Took ", time.Since(now), "seconds")
}