mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 06:30:28 +03:00
Fix issue 20924
This commit is contained in:
parent
d4bb2846e1
commit
653e0e8e86
1 changed files with 63 additions and 48 deletions
111
std/numeric.d
111
std/numeric.d
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue