Fix issue 20924

This commit is contained in:
Simen Kjærås 2020-06-15 08:39:41 +02:00 committed by The Dlang Bot
parent d4bb2846e1
commit 653e0e8e86

View file

@ -2987,64 +2987,70 @@ if (isIntegral!T)
// This overload is for non-builtin numerical types like BigInt or // This overload is for non-builtin numerical types like BigInt or
// user-defined types. // user-defined types.
/// ditto /// ditto
T gcd(T)(T a, T b) auto gcd(T)(T a, T b)
if (!isIntegral!T && if (!isIntegral!T &&
is(typeof(T.init % T.init)) && is(typeof(T.init % T.init)) &&
is(typeof(T.init == 0 || T.init > 0))) is(typeof(T.init == 0 || T.init > 0)))
{ {
import std.algorithm.mutation : swap; static if (!is(T == Unqual!T))
enum canUseBinaryGcd = is(typeof(() {
T t, u;
t <<= 1;
t >>= 1;
t -= u;
bool b = (t & 1) == 0;
swap(t, u);
}));
assert(a >= 0 && b >= 0);
// Special cases.
if (a == 0)
return b;
if (b == 0)
return a;
static if (canUseBinaryGcd)
{ {
uint shift = 0; return gcd!(Unqual!T)(a, b);
while ((a & 1) == 0 && (b & 1) == 0)
{
a >>= 1;
b >>= 1;
shift++;
}
if ((a & 1) == 0) swap(a, b);
do
{
assert((a & 1) != 0);
while ((b & 1) == 0)
b >>= 1;
if (a > b)
swap(a, b);
b -= a;
} while (b);
return a << shift;
} }
else else
{ {
// The only thing we have is %; fallback to Euclidean algorithm. import std.algorithm.mutation : swap;
while (b != 0) enum canUseBinaryGcd = is(typeof(() {
T t, u;
t <<= 1;
t >>= 1;
t -= u;
bool b = (t & 1) == 0;
swap(t, u);
}));
assert(a >= 0 && b >= 0);
// Special cases.
if (a == 0)
return b;
if (b == 0)
return a;
static if (canUseBinaryGcd)
{ {
auto t = b; uint shift = 0;
b = a % b; while ((a & 1) == 0 && (b & 1) == 0)
a = t; {
a >>= 1;
b >>= 1;
shift++;
}
if ((a & 1) == 0) swap(a, b);
do
{
assert((a & 1) != 0);
while ((b & 1) == 0)
b >>= 1;
if (a > b)
swap(a, b);
b -= a;
} while (b);
return a << shift;
}
else
{
// The only thing we have is %; fallback to Euclidean algorithm.
while (b != 0)
{
auto t = b;
b = a % b;
a = t;
}
return a;
} }
return a;
} }
} }
@ -3085,6 +3091,15 @@ if (!isIntegral!T &&
assert(gcd(BigInt(2), BigInt(1)) == BigInt(1)); assert(gcd(BigInt(2), BigInt(1)) == BigInt(1));
} }
// Issue 20924
@safe unittest
{
import std.bigint : BigInt;
const a = BigInt("123143238472389492934020");
const b = BigInt("902380489324729338420924");
assert(__traits(compiles, gcd(a, b)));
}
// This is to make tweaking the speed/size vs. accuracy tradeoff easy, // This is to make tweaking the speed/size vs. accuracy tradeoff easy,
// though floats seem accurate enough for all practical purposes, since // though floats seem accurate enough for all practical purposes, since
// they pass the "approxEqual(inverseFft(fft(arr)), arr)" test even for // they pass the "approxEqual(inverseFft(fft(arr)), arr)" test even for