为什么Go语言中的大整数API如此奇怪?

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

Why is big int api in Go so strange?

问题

我试图理解big int api背后的设计决策。

例如,要添加两个大整数,你必须这样做:

a := big.NewInt(10)
b := big.NewInt(20)
c := big.NewInt(0)
d := c.Add(a,b)

其中d在最后与c相同。初始的零没有任何影响。

为什么不直接这样做:

a := big.NewInt(10)
b := big.NewInt(20)
c := big.Add(a,b)

或者更好的是:

a := big.NewInt(10)
b := big.NewInt(20)
c := a.Add(b)

他们选择这样做有什么原因吗?我觉得有点困惑,每次使用时都不得不查阅文档。

英文:

I'm trying to understand the design decisions behind the big int api.

For example to add two big ints you have to:

a := big.NewInt(10)
b := big.NewInt(20)
c := big.NewInt(0)
d := c.Add(a,b)

where d is the same as c at the end. The initial zero does not matter a bit.

Why not just:

a := big.NewInt(10)
b := big.NewInt(20)
c := big.Add(a,b)

Or better yet:

a := big.NewInt(10)
b := big.NewInt(20)
c := a.Add(b)

Is there any reason they chose to do it this way? I find it little confusing and have to look it up whenever I use it.

答案1

得分: 11

Add是一个改变接收器的方法。

所以只需这样做:

c := big.NewInt(0).Add(a,b)

或者

var c big.Int
c.Add(a,b) 

Add方法返回接收器是为了方便函数链式调用,但你不需要使用返回的值。

现在假设一下,如果我们没有一个bigInt作为接收器(c := big.Add(a,b)),或者接收器不会被修改(c := a.Add(b))。在这两种情况下,都需要为操作分配并返回一个big Int(作为指针)。如果你已经有一个已经分配好并准备好的big Int,这样做是浪费的。计算出的整数不仅仅是一个简单的一两个字的结构体,它可能很大。所以最好允许使用预定义的变量,特别是当你经常在计算循环中使用你的big integer时。

c := big.Add(a,b) // 浪费,因为不允许使用预先存在的big int

c := a.Add(b) // 要么修改a(这将强制你每次都要复制它,如果你想保留它),要么像上一个例子一样浪费。
英文:

Add is a method changing the receiver.

So just do

c := big.NewInt(0).Add(a,b)

or

var c big.Int
c.Add(a,b) 

The fact that Add returns the receiver is useful for function chaining but you don't need to use the returned value.

Now suppose a moment that we wouldn't have a bigInt as receiver (c := big.Add(a,b)) or that the receiver wouldn't be modified (c := a.Add(b)). In both cases a big Int would have to be allocated just for the operation and returned (as a pointer). This would be wasteful in case you yet have a big Int allocated and ready. The integer that is computed isn't just a simple one or two words struct, it can be big. So it's better to allow the use of a predefined var, especially as you often would use your big integer in the middle of a computation loop.

c := big.Add(a,b) // wasteful because doesn't allow the use of a preexisting big int

c := a.Add(b) // either modifies a (which would force you to copy it each time if you want to keep it) or is wasteful like the last one

答案2

得分: 3

我想补充一下Denys的回答,如果你考虑使用另一种支持链式调用的API,可以这样写:

x.Add(y).Add(z).Mul(v) 

问题是,这样的写法是否遵循正常的运算符顺序?

x+y+z*v = x+y+(z*v) 

但是第一个链式调用会得到 (x+y+z)*v(在Go语言中是这样,但在其他语言可能不是)- 因此需要小心处理。

这样写:

r = r.AddP(x, y.Add(y, z.Mul(z, v)))

可能有点丑陋,我同意,但它强制了一个明确的顺序,并且还给了我们一个机会,可以在不额外分配内存的情况下保持操作数不变(正如Denys所提到的)。例如(注意每次r都是接收者):

r = r.Add(x, r.Add(y, r.MulInt(z, v)))

这里只有结果值(r)发生了变化,x、y、z保持不变 - 要在第一种风格的API中实现这一点,你需要每次都分配内存。因此,在这种情况下,你要么改变操作数,要么分配内存,在big.Int API中,你可以选择其中一种方式。

顺便说一下,以下是与第一个链式调用等价的写法...

r = r.Mul(r.AddP(x, r.Add(y, z)), v) 

这实际上更明确地表示为 (x+y+z)*v

英文:

I would add to Denys' answer that if you consider the alternative api, which could support chaining as follows:

x.Add(y).Add(z).Mul(v) 

Quickly the question is - does this obey normal operator ordering?

x+y+z*v = x+y+(z*v) 

but the first chain would result in (x+y+z)*v (in go, but possibly not in another language) - hence care is needed.

This:

r = r.AddP(x, y.Add(y, z.Mul(z, v)))

is somewhat uglier, i agree, but it does forces an explicit order, and it also gives us the chance to leave the operands unchanged, with no extra allocation (as mentioned by Denys). e.g. (notice r is the receiver every time):

r = r.Add(x, r.Add(y, r.MulInt(z, v)))

here only the result value (r) is changed, x,y,z are unchanged - to do this in the first style API you need an allocation each time. So in that case you either mutate the operands, or you allocate, in the big.Int api you have the option of either.

Btw, the following would be the equivalent to the first chaining...

r = r.Mul(r.AddP(x, r.Add(y, z)), v) 

Which actually looks a bit more explicitly like (x+y+z)*v

huangapple
  • 本文由 发表于 2012年11月22日 21:46:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/13514082.html
匿名

发表评论

匿名网友

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

确定