What is the fastest way to set all array elements to '0'
?
This is how I did it. Is there a faster way?
for i := range seg { seg[i] = 0 }
What is the fastest way to set all array elements to '0'
?
This is how I did it. Is there a faster way?
for i := range seg { seg[i] = 0 }
You can try to redefine teh value sin the array. For example:
var a [2]int
// Because 0 is teh default value for an int
fmt.Println(a) // [0 0]
// Let's assign some values to the array
a[0] = 10
a[1] = 20
fmt.Println(a) // [10 20]
// Redefine array
a = [2]int{0, 0}
fmt.Println(a) // [0 0]
Your example is not very practical. Let’s increase the size of the array by a small amount to 1024*1024. Have you finished typing the list of more than a million zeros yet?
A more practical and more general example is:
var a [1024*1024]int
a = [len(a)]int{}
Your example, then becomes
package main
import "fmt"
func main() {
var a [2]int
// Because 0 is the default value for an int
fmt.Println(a) // [0 0]
// Let's assign some values to the array
a[0] = 10
a[1] = 20
fmt.Println(a) // [10 20]
// Redefine array
a = [len(a)]int{}
fmt.Println(a) // [0 0]
}
[0 0]
[10 20]
[0 0]
yes!!!
This won’t work in my case because compiler says seg
isn’t constant array.
go-projects go build twinprimes_ssoz.go
# command-line-arguments
./twinprimes_ssoz.go:232:27: non-constant array bound len(seg)
➜ go-projects
It’s created like this, and is zeroed inside a loop at its end.
seg := make([]uint64, ((kb - 1) >> s) + 1)
You asked about a way to zero an array. Therefore, you received an answer about a way to zero an array.
However, you appear to be confused. In Go, arrays and slices are distinct types.
The Go Programming Language Specification
Array types
Slice types
For slices, post a new question. Be specific and include a full, reproducible example.
Is this what you are looking for?
No. That answer has already been posted by others in a more general form.
I think its very clear from the code I posted what my intent is.
Is there a faster way to fill that slice with all zeroes than the way I showed?
Hi @jzakiya
I believe it’s a tricky question.
Execute the following script with different array size and in different machines and you will get different results
package main
import (
"fmt"
"math"
"runtime"
"sync"
"time"
)
func main() {
var seg [1024 * 1024]int
// Part 1
fillArrayWithOnes(seg[:])
runtime.Gosched()
start := time.Now()
initializeSeq(seg[:])
elapsed := time.Now().Sub(start)
fmt.Printf("Sequential took %v\n", elapsed)
fmt.Println("ns:", int64(elapsed/time.Nanosecond))
// Part 2
fillArrayWithOnes(seg[:])
runtime.Gosched()
start = time.Now()
cleanWg := new(sync.WaitGroup)
numGoroutines := runtime.NumCPU()
sliceSize := int(math.Ceil(float64(len(seg)) / float64(numGoroutines)))
for i := 0; i < numGoroutines; i++ {
start := i * sliceSize
end := (i + 1) * sliceSize
if end > len(seg) {
end = len(seg)
}
partialKeys := seg[start:end]
cleanWg.Add(1)
go initialize(partialKeys, cleanWg)
}
cleanWg.Wait()
elapsed = time.Now().Sub(start)
fmt.Printf("Goroutines took %v\n", elapsed)
fmt.Println("ns:", int64(elapsed/time.Nanosecond))
}
func fillArrayWithOnes(currentArray []int) {
for i := range currentArray {
currentArray[i] = 1
}
}
func initialize(currentArray []int, wg *sync.WaitGroup) {
defer wg.Done()
for i := range currentArray {
currentArray[i] = 0
}
}
func initializeSeq(currentArray []int) {
for i := range currentArray {
currentArray[i] = 0
}
}
Hi @jzakiya
Maybe this can help you
package main
import "fmt"
func main() {
arr := []int{1, 2, 3, 4, 5, 7, 8, 9, 10}
fmt.Println(arr)
value := 0
arrSize := len(arr)
fillArray(arr, arrSize, value)
fmt.Println(arr)
}
func fillArray(arr []int, arrSize, value int) {
arr[0] = value
for i := 1; i < arrSize; i *= 2 {
copy(arr[i:], arr[:i])
}
}
https://play.golang.org/p/wNjQrzJUpSQ
it is the most efficient way to fill an array that I know of. I think it is
O(long(n))
Hey thanks @guille-acosta.
I modified your method to work for unit64
types, for my array type, and simplified it.
func fillArray(arr []uint64, value uint64) {
arr[0] = value
for i := 1; i < len(arr); i *= 2 {
copy(arr[i:], arr[:i])
}
}
However upon testing in my code, it doesn’t provide any measurable performance increase.
FYI, I asked this question in the Rust forum in March 2020, and just happened to ask again today.
They have actually now included a fill
method in their std lib, which they are looking to optimize.
I’m guessing, to make you technique actually faster it has to be implemented at the assembly level too. Also, the Rust method works for various number types, so that’s something else to consider to make it a generic function for all array number types.
I really think adding an optimized fill
method would be very beneficial for Go programmers too, just from the aesthetic benefits alone, to make code easier to read.
Here’s the discussion in the Rust forum today.
The rust fill function is most probably using the c memcpy
function or the assembly equivalent which is the most efficient.
I assume the Go compiler is optimizing the following pattern into using the memcpy
equivalent. This is a very frequent pattern that is certainly optimized because it is a trivial and obvious optimization.
a := make([]int64, 1024*1024)
for i := range a {
a[i] = 0
}
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.