-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
math/big: add a method to Int for an absolute value comparison #22473
Comments
Why |
Sorry, was in a hurry to leave work. I’m on my phone, but yes just
x.abs.cmp(y.abs) should be needed.
Le ven. 27 oct. 2017 à 18:14, Keith Randall <notifications@github.com> a
écrit :
… Why r = -r? It doesn't follow given the doc comment.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#22473 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AFnwZ0Gh4mF4ErJU9Vo-8eqxGUSWhjSFks5swn_-gaJpZM4QJwmO>
.
|
I'll /cc @griesemer too. |
Zero allocation/aliasing CmpAbs: package main
import (
"fmt"
"math/big"
)
func CmpAbs(a, b *big.Int) int {
x := a.Bits()
y := b.Bits()
if len(x) < len(y) {
return -1
}
if len(x) > len(y) {
return 1
}
if len(x) == 0 && len(y) == 0 {
return 0
}
t := x[len(x)-1]
u := y[len(y)-1]
if t < u {
return -1
}
if t > u {
return 1
}
return 0
}
func n(s string) *big.Int {
n, ok := big.NewInt(0).SetString(s, 10)
if !ok {
panic(ok)
}
return n
}
func main() {
a := n("-1000000000000000000000000000000000000000")
b := n("-100000000000000000000000000000000000000")
fmt.Println(CmpAbs(a, b), CmpAbs(b, a))
fmt.Println()
c := n("1000000000000000000000000000000000000000")
d := n("100000000000000000000000000000000000000")
fmt.Println(CmpAbs(a, c), CmpAbs(a, d))
fmt.Println(CmpAbs(b, c), CmpAbs(b, d))
fmt.Println()
nm1 := n("-1")
n0 := n("0")
n1 := n("1")
fmt.Println(CmpAbs(nm1, nm1))
fmt.Println(CmpAbs(nm1, n0))
fmt.Println(CmpAbs(nm1, n1))
fmt.Println()
fmt.Println(CmpAbs(n0, nm1))
fmt.Println(CmpAbs(n0, n0))
fmt.Println(CmpAbs(n0, n1))
fmt.Println()
fmt.Println(CmpAbs(n1, nm1))
fmt.Println(CmpAbs(n1, n0))
fmt.Println(CmpAbs(n1, n1))
} Output:
edit: fix link |
The code above obviously fails in the general case as I managed to forgot to include the comparison of all but the last words of .Bits(). Hopefully fixed in https://play.golang.org/p/E0HBJlBccV. |
Note
Which is exactly what you're trying to do. I'm not sure extending further the (already big) |
@ALTree yeah, when I first noticed the allocs I wrote my own comparison function like @cznic's. At least in the code I've been writing lately it's common enough. It's a much more efficient way of determining if z is in [-x, x] than creating x and -x and calling Cmp twice. And it's just about the only way to accurately get the length of a It's not too concerning and I understand not wanting to clutter the API. :-) |
@ericlagergren Note that you can do |
@griesemer right. I’ve hesitated to do that since it’s something else to keep track of when, eg, needing abs cmp inside a loop or handing off the big.Ints to other methods, etc. |
@ericlagergren The only thing that matters is whether you have concurrent access to the same big.Int or not. If you don't, you can trivially change the sign locally and then change it back. Factor it out into a CmpAbs function and you're done. But all that said and done, I'm just going to add this function. There are definitively algorithms that care about the relative magnitudes of values, so this is in fact a useful function to have. I've got the CL, will have tests tomorrow. |
Change https://golang.org/cl/74971 mentions this issue: |
Yeah, perhaps I’m too paranoid. :-) Thanks for adding it Robert.
Le mar. 31 oct. 2017 à 22:44, Robert Griesemer <notifications@github.com> a
écrit :
… @ericlagergren <https://github.com/ericlagergren> The only thing that
matters is whether you have concurrent access to the same big.Int or not.
If you don't, you can trivially change the sign locally and then change it
back. Factor it out into a CmpAbs function and you're done.
But all that said and done, I'm just going to add this function. There are
definitively algorithms that care about the relative magnitudes of values,
so this is in fact a useful function to have. I've got the CL, will have
tests tomorrow.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#22473 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AFnwZ94kzI8F0vXkYRQDLZY08ftcBkzfks5syAVNgaJpZM4QJwmO>
.
|
There is a situation where this gets complicated, that is in finding an absolute differential between two unsigned integers. This is how I solved it in my code: // Bast - Bifurcation Array Search Tree organising data structure
type Bast struct {
Weights [2][32]uint32 // Keeps track of the number of elements total in Weights[0,1][0] and rest for each row downwards
Depth uint8 // Depth of the Store in rows of the binary tree (cannot be more than 32 due to golang 32 bit array indices)
Length Index // Length of the array, updated when adding rows to cut some time out of the walk operations
Store []Data
}
/* ... */
// IsBalanced - returns true if balance is within tolerance prescribed by BalanceTolerance
func (b *Bast) IsBalanced() bool {
if b.Weights[0][0] > b.Weights[1][0] {
if b.Weights[0][0]-b.Weights[1][0] > BalanceTolerance {
return false
}
} else if b.Weights[1][0] > b.Weights[0][0] {
if b.Weights[1][0]-b.Weights[0][0] > BalanceTolerance {
return false
}
}
return true
} An |
When writing a couple libraries I've needed to compare the absolute value of two
big.Int
s, but have had my hands tied a bit because the API doesn't allow me to modify them.Right now, the only way to get an absolute comparison without modifying either of the inputs is
The first two allocate a
big.Int
and the second causes aliasing which can cause subtle bugs. The allocations have appeared when benchmarking.It would be very nice to essentially have this
PS: is there a proposal template?
The text was updated successfully, but these errors were encountered: