当你没有进行索引操作时,如何出现“索引超出范围”的错误?

huangapple go评论142阅读模式
英文:

How can I get "index out of range" when I am not indexing

问题

长期从事编程工作,但对Go语言完全不熟悉。

这是我的代码。这是我第一次尝试生成器。我试图生成一个LFSR序列。基本上,每次循环都向右移动一位。如果刚刚移出一个1位,则与tap值进行异或运算。

package main

import (
	"fmt"
	"math/big"
)

// lfsr返回一个LFSR生成器。
func lfsr(tap, start big.Int) func() big.Int {
	// 跟踪下一个值。
	next := &start
	// 生成器。
	return func() big.Int {
		// 记住当前位置。
		ret := *next
		// 计算下一个值。
		fmt.Println("next", next.String(), "bit(0)", next.Bit(0))
		// 当前值是否为奇数?
		odd := next.Bit(0)
		// 右移一位。
		next = next.Rsh(next, 1)

		// 如果是奇数-进行异或运算!
		if odd != 0 {
			// 异或运算!
			next = next.Xor(next, &tap)
			fmt.Printf("Tap!", next.String())
		}

		// 返回之前的值。
		return ret
	}
}

func main() {
	ten := new(big.Int)
	ten.SetString("10", 32)
	f := lfsr(*ten, *ten)
	for i := 0; i < 10; i++ {
		n := f()
		fmt.Println("lfsr ", n.String())
	}
}

我得到的输出是:

next 32 bit(0) 0
lfsr  16
next 16 bit(0) 0
lfsr  8
next 8 bit(0) 0
lfsr  4
next 4 bit(0) 0
lfsr  2
next 2 bit(0) 0
lfsr  1
next 1 bit(0) 1
Tap! 0
panic: runtime error: index out of range

我做错了什么,为什么看起来是对的?

Play - 有趣的是 - 它输出:

...
next 1 bit(0) 1
Tap!%!(EXTRA string=0)panic: runtime error: index out of range

goroutine 1 [running]:
math/big.nat.string(0xc010045150, 0x1, 0x5, 0x12b23d0, 0xa, ...)
	go/src/pkg/math/big/nat.go:819 +0x67f
math/big.nat.decimalString(0xc010045150, 0x1, 0x5, 0x1, 0x1, ...)
	go/src/pkg/math/big/nat.go:731 +0x8f
math/big.(*Int).String(0x7f851e0eff40, 0xc010045150, 0x1)
	go/src/pkg/math/big/int.go:331 +0xfe
main.main()
	/tmpfs/gosandbox-94dce1ec_430947f1_6360662e_01c3d6ad_a7071d20/prog.go:41 +0x120

这有点不同,并且暗示fmt.Println("lfsr ", n.String())是出错的,但我还没有找出原因。

补充

经过尝试(将ten.SetString("10", 32)更改为ten.SetString("10", 10)),我现在得到:

lfsr  5
next 5 bit(0) 1
Tap!%!(EXTRA string=0)panic: runtime error: index out of range

现在要去睡觉了,希望有人能帮忙解决。

英文:

Long time programmer - total newbie in go.

Here's the code. It is my first attempt at a generator. I am trying to generate an lfsr sequence. Essentially, every time around you shift right one. If you just shifted out a 1 bit, xor with the tap value.

package main

import (
	&quot;fmt&quot;
	&quot;math/big&quot;
)

// lfsr returns an lfsr generator.
func lfsr(tap, start big.Int) func() big.Int {
	// Keep track of next.
	next := &amp;start
	// The generator.
	return func() big.Int {
		// Remember where we are.
		ret := *next
		// Work out next.
		fmt.Println(&quot;next&quot;, next.String(), &quot;bit(0)&quot;, next.Bit(0))
		// Is it currently odd?
		odd := next.Bit(0)
		// Shift right one.
		next = next.Rsh(next, 1)

		// If odd - tap!
		if odd != 0 {
			// Tap!
			next = next.Xor(next, &amp;tap)
			fmt.Printf(&quot;Tap!&quot;, next.String())
		}

		// Return where we were.
		return ret
	}
}

func main() {
	ten := new(big.Int)
	ten.SetString(&quot;10&quot;, 32)
	f := lfsr(*ten, *ten)
	for i := 0; i &lt; 10; i++ {
		n := f()
		fmt.Println(&quot;lfsr &quot;, n.String())
	}
}

The printout I am getting is:

next 32 bit(0) 0
lfsr  16
next 16 bit(0) 0
lfsr  8
next 8 bit(0) 0
lfsr  4
next 4 bit(0) 0
lfsr  2
next 2 bit(0) 0
lfsr  1
next 1 bit(0) 1
Tap! 0
panic: runtime error: index out of range

What am I doing wrong - and why does it look right?

Play - Interestingly - it outputs:

...
next 1 bit(0) 1
Tap!%!(EXTRA string=0)panic: runtime error: index out of range

goroutine 1 [running]:
math/big.nat.string(0xc010045150, 0x1, 0x5, 0x12b23d0, 0xa, ...)
	go/src/pkg/math/big/nat.go:819 +0x67f
math/big.nat.decimalString(0xc010045150, 0x1, 0x5, 0x1, 0x1, ...)
	go/src/pkg/math/big/nat.go:731 +0x8f
math/big.(*Int).String(0x7f851e0eff40, 0xc010045150, 0x1)
	go/src/pkg/math/big/int.go:331 +0xfe
main.main()
	/tmpfs/gosandbox-94dce1ec_430947f1_6360662e_01c3d6ad_a7071d20/prog.go:41 +0x120

which is a) slightly different and b) suggesting that the fmt.Println(&quot;lfsr &quot;, n.String()) is what is failing but I am no nearer working out why.

Added

After experimentation (changing ten.SetString(&quot;10&quot;, 32) to ten.SetString(&quot;10&quot;, 10)) I now get:

lfsr  5
next 5 bit(0) 1
Tap!%!(EXTRA string=0)panic: runtime error: index out of range

Going to sleep now - hope someone can help.

答案1

得分: 1

似乎是由于big.Int上的String()实现引起的。您可以在n上省略String()调用,让Println自己决定如何打印参数:

func main() {
    ten := new(big.Int)
    ten.SetString("10", 32)
    f := lfsr(*ten, *ten)
    for i := 0; i < 10; i++ {
        n := f()
        fmt.Println("lfsr ", n)
    }
}
英文:

It seems to be caused by the String() implementation on big.Int. You can leave out the String() call on n and let Println figure out how to print the argument itself:

func main() {
    ten := new(big.Int)
    ten.SetString(&quot;10&quot;, 32)
    f := lfsr(*ten, *ten)
    for i := 0; i &lt; 10; i++ {
        n := f()
        fmt.Println(&quot;lfsr &quot;, n)
    }
}

答案2

得分: 1

复制big.Int是不安全的。特别是将*big.Int解引用并赋值给一个值是行不通的。底层数组会被别名引用而不是被复制,因为数组可能以破坏不变性的方式发生变化。
ret := *next这一行是你的错误来源。

http://play.golang.org/p/W_qOCDsO2A

i := big.NewInt(1)
j := *i
fmt.Println("i:", *i, "j:", j) // i: {false [1]} j: {false [1]}
i = i.Xor(i, i)
fmt.Println("i:", *i, "j:", j) // i: {false []} j: {false [0]}
//j的状态已经改变,它现在违反了不变性
j.String() //boom

复制big.Int的方法是ret := *new(big.Int).Set(next)。我认为应该有一个func Copy(n *big.Int) *big.Int来完成这个操作,因为语法有点丑陋。此外,我建议完全避免将big.Int用作值,并将lfsr更改为返回指针。

工作示例:http://play.golang.org/p/WEFRnGlU1H。

英文:

It is not safe to copy big.Int. In particular dereferencing a *big.Int and assigning it to a value does not work. The underlying array is aliased instead of copied. as the array can mutate in ways that break the invariants.
The line ret := *next is the source of your bug.

http://play.golang.org/p/W_qOCDsO2A

i := big.NewInt(1)
j := *i
fmt.Println(&quot;i:&quot;, *i, &quot;j:&quot;, j) // i: {false [1]} j: {false [1]}
i = i.Xor(i, i)
fmt.Println(&quot;i:&quot;, *i, &quot;j:&quot;, j) // i: {false []} j: {false [0]}
//j&#39;s state has changed, it now violates the invariants
j.String() //boom

The way to copy a big.Int is ret := *new(big.Int).Set(next). I think there should be func Copy(n *big.Int) *big.Int that does this, as the syntax is a bit ugly. Also I would avoid using big.Int as a value at all and change lfsr to return a pointer.

Working example http://play.golang.org/p/WEFRnGlU1H.

huangapple
  • 本文由 发表于 2013年9月27日 07:06:11
  • 转载请务必保留本文链接:https://go.coder-hub.com/19040138.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定