Go: math/big: add Int.AddInt64, Int.CmpInt64

Created on 26 Jan 2019  路  14Comments  路  Source: golang/go

Please consider adding big.Int methods Inc and Dec which would increase or decrease the given Int by one. It would be similar to the following code, except for the allocation:

x.Add(x, big.NewInt(1))

The motivation is that it is quite common operation and the code using it would be simpler and saving one allocation.

Alternatively, please consider AddInt(64) and SubInt(64), which would still save one allocation when knowing the increment/decrement fits a (64-bit) machine word.

Cursory look at Go source shows that the first alternative could be useful here and here, and the second one here.

Yet another alternative would be to expose intOne from int.go.

NeedsFix Proposal Proposal-Accepted help wanted

Most helpful comment

I would start with none of them. If you add one, you'll end up adding them all, or at best dealing with a string of proposals to add them piecemeal. Please hold the line.

All 14 comments

You can declare some package variables called one, two, etc. and use them throughout.

x.Add(x, one)

This also lets you do things like

x.Cmp(one)

@robpike Yes, package variables are one way of how to approach (although each package would have to possibly allocate the same big.NewInt(1)) this but the proposal is more about avoid allocations and simplifying the notation for arguments which fit machine word. Kind of like GMP _si and ui methods, of which I find that +1/-1 are the most useful.

Int.AddInt64 seems strictly better than Inc/Dec and matches the Int64 and SetInt64 methods. (Probably don't need SubInt64 if we have a general AddInt64. Also probably don't need AddUint64, SubUint64.)

But what else would it require adding? And? AndNot? Cmp? Div? DivMod? Mod? Mul? Or? Quo? QuoRem? Rem? Sub after all? Xor?

Just declaring a few globals with the constants you need seems to be the right answer most of the time. It's not clear that doubling the API surface is a significant enough win.

Perhaps And, AndNot, Xor are not really necessary, Cmp can be worked around with Sign, IsInt64, Int64. So if I may summarize this gives 4 options:

  • Add every arithmetic operator (Add, Sub, Mul, QuoRem, Quo, Rem, DivMod, Div, Mod) and maybe Exp, each for Int64 and Uint64. This would be quite complete (akin to GMP) but it seems too specialized for stdlib to compensate for so many new methods.

  • Add only Add and Sub, for both Int64 and Uint64. I would argue Sub is needed even for Int64 case as the main motivation is to simplify code and to manually check whether an argument is negative or not to suitably change the sign so that it works for Add seems way too much work. And big.Int also has Sub even when it is not strictly necessary. Four methods, and really only two of which need a proper implementation as Int64 may be using Uin64 internally. The drawback is that it somehow "promises" there are more machine word methods like this, as shown by your question.

  • And only Inc and Dec. No need to worry about Uint, Int64, it does not suggest other "missing" machine word methods. Albeit more limited that any option above, perhaps it's still better than nothing.

  • Don't add anything. Clearly this is the easiest option but I believe that the above options have the potential to be generally useful.

Talked to @griesemer, who is inclined to start with just AddInt64 and CmpInt64 and wait for more compelling needs for any of the others. Those are clearly the most common.

I would start with none of them. If you add one, you'll end up adding them all, or at best dealing with a string of proposals to add them piecemeal. Please hold the line.

@rsc If I understood correctly, AddInt64 would need to distinguish positive and negative values as the internal implementation of big.Int uses big.nat, i.e. to add a negative number it subtracts its absolute value. If there would indeed be such mechanism, why not expose it, i.e. to add both AddUint64 and SubUint64? (With or without AddInt64?) It is similar to Int.SetInt64/Int.SetUint64, Rat.SetInt64/Rat.SetUint64, I think unsigned 64-bits are useful.

I don't understand the need for adding these methods to the standard library. As @robpike mentioned, package level variables already handle the proposed use case very well and the big.Int API is already very large.

Since AddInt64(x) would need to distinguish the sign and conver x to nat we can鈥檛 save much on allocations. And may be even more harmful for memory to do so in case of making increment functions. Only convenience I see is symantics. But I think std libs should follow: KISS.
Makes it easy to test, debug and understand

Solution like

  one := big.NewInt(1)
  counter := big.NewInt(0)
   ...
   counter.Add(counter,one)
   ...

are way better approach to issue.

I shall punt to Go1.14 as the jury is still hung on whether to implement it or not, but also there hasn't been movement.

The methods Inc and Dec seem like a nice pendant to ++ and -- for the integer primitive types. Also they would probably have some performance benefits opposed to x.Add(x, one) as less comparisons and allocations are necessary.

Despite this proposal being accepted we have not moved ahead yet. @robpike is likely correct that this will simply invite piecemeal additions of more little helpers. There may be ways to improve performance of the existing code w/o changing the API.

Since there doesn't appear to be a clear consensus on this addition to math/big, should this be moved back into active discussion, with the Accepted label removed?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dominikh picture dominikh  路  3Comments

mingrammer picture mingrammer  路  3Comments

enoodle picture enoodle  路  3Comments

ashb picture ashb  路  3Comments

natefinch picture natefinch  路  3Comments