Skip to content

Commit e018c0e

Browse files
committed
Add MSVC x86 release mode workaround impl
1 parent 7896af6 commit e018c0e

File tree

1 file changed

+42
-0
lines changed

1 file changed

+42
-0
lines changed

include/boost/int128/numeric.hpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include <limits>
1414
#include <iostream>
15+
#include <limits>
1516

1617
#endif
1718

@@ -288,6 +289,11 @@ constexpr int128_t gcd(const int128_t a, const int128_t b) noexcept
288289
return static_cast<int128_t>(gcd(static_cast<uint128_t>(abs(a)), static_cast<uint128_t>(abs(b))));
289290
}
290291

292+
// For unknown reasons this implementation fails for MSVC x86 only in release mode
293+
// Directly calculating leads to the same failures, so unfortunately we have a viable,
294+
// but very slow impl that we know works.
295+
#if !(defined(_M_IX86) && !defined(_NDEBUG))
296+
291297
constexpr uint128_t lcm(const uint128_t a, const uint128_t b) noexcept
292298
{
293299
if (a == 0U || b == 0U)
@@ -302,6 +308,42 @@ constexpr uint128_t lcm(const uint128_t a, const uint128_t b) noexcept
302308
return (a / g) * b;
303309
}
304310

311+
#else
312+
313+
constexpr uint128_t lcm(uint128_t a, uint128_t b) noexcept
314+
{
315+
if (a == 0U || b == 0U)
316+
{
317+
return 0;
318+
}
319+
320+
321+
unsigned shift{};
322+
while ((a & 1U) == 0U && (b & 1U) == 0U)
323+
{
324+
a >>= 1U;
325+
b >>= 1U;
326+
shift++;
327+
}
328+
329+
// Ensure a >= b
330+
if (a < b)
331+
{
332+
std::swap(a, b);
333+
}
334+
335+
uint128_t lcm{a};
336+
337+
while (lcm % b != 0U)
338+
{
339+
lcm += a;
340+
}
341+
342+
return lcm << shift;
343+
}
344+
345+
#endif
346+
305347
constexpr int128_t lcm(const int128_t a, const int128_t b) noexcept
306348
{
307349
return static_cast<int128_t>(lcm(static_cast<uint128_t>(abs(a)), static_cast<uint128_t>(abs(b))));

0 commit comments

Comments
 (0)