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: GCD support for negative and zero arguments #28878

Open
TuomLarsen opened this Issue Nov 20, 2018 · 6 comments

Comments

Projects
None yet
4 participants
@TuomLarsen

TuomLarsen commented Nov 20, 2018

Please consider adding support for zero and negative arguments to math/big GCD.

As of version 1.11.1, to calculate GCD of two integers one has to write:

new(big.Int).GCD(nil, nil, new(big.Int).Abs(a), new(big.Int).Abs(b))

In other words, one needs two extra allocations (or copies) as the nat field of big.Int is private.

If on the other hand negative inputs were allowed the code would read:

new(big.Int).GCD(nil, nil, a, b)

For negative inputs the resulting GCD could be treated as GCD(|a|, |b|), the precise sign does not really matter as long as it is documented. (For example, "GCD is non-negative".)

While I'm at it, it would be also nice to support zero arguments as it is well defined (GCD(a, 0) = |a|, GCD(0, 0) = 0) and it would simplify the code because there would be no need to special-case zero inputs. Currently it sets the result to zero.

@ianlancetaylor

This comment has been minimized.

Contributor

ianlancetaylor commented Nov 20, 2018

@ianlancetaylor ianlancetaylor added this to the Go1.13 milestone Nov 20, 2018

@bmkessler

This comment has been minimized.

Contributor

bmkessler commented Nov 20, 2018

Note, you can avoid allocation by using:

new(big.Int).GCD(nil, nil, a.Abs(a), b.Abs(b))

Which switches the sign without allocation.

What would be the proposed convention for the signs of the Bezout coefficients?

z = a*x + b*y
or
z = |a|*x + |b|*y

I don't think there is an established convention here.

For zero values, I presume you would set x=0 if a=0 and y=0 if b=0

What is the use case for GCD of negative numbers?

@TuomLarsen

This comment has been minimized.

TuomLarsen commented Nov 21, 2018

That would mutate the arguments, however. I don't think it is desirable to change a or b when asking for new(big.Int).

If it worked as GCD(|a|, |b|) then I think the latter would make more sense. And as you say for the case of zeros.

Normalizing fractions, computing content of polynomials, simplify integer matrices, all these work beyond natural numbers.

@bmkessler

This comment has been minimized.

Contributor

bmkessler commented Nov 21, 2018

Yes, it's not ideal that you would have to track the signs of a and b and restore them after calculating the GCD, I was just noting that you could currently calculate the GCD without allocating by doing some additional bookkeeping.

For reference, GMP uses the first convention for the Bezout coefficients z = a*x + b*y
https://gmplib.org/manual/Number-Theoretic-Functions.html

@TuomLarsen

This comment has been minimized.

TuomLarsen commented Nov 21, 2018

This as well but also accessing a or b from other threads would be unsafe.

@Merovius

This comment has been minimized.

Merovius commented Nov 29, 2018

Disclaimer: No, don't do this ;)

func evilAbs(x *big.Int) *big.Int {
	y := *x
	y.Abs(&y)
	return &y
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment