gcd and lcm for big integers

This commit is contained in:
Alexey Milovidov 2021-05-07 03:00:26 +03:00
parent fee0314057
commit 7d93734f54
4 changed files with 44 additions and 15 deletions

View File

@ -1,9 +1,12 @@
#pragma once
#include <string>
#include <ostream>
#include <fmt/format.h>
#include "wide_integer.h"
namespace wide
{
@ -33,3 +36,34 @@ inline std::string to_string(const integer<Bits, Signed> & n)
}
}
template <size_t Bits, typename Signed>
std::ostream & operator<<(std::ostream & out, const wide::integer<Bits, Signed> & value)
{
return out << to_string(value);
}
/// See https://fmt.dev/latest/api.html#formatting-user-defined-types
template <size_t Bits, typename Signed>
struct fmt::formatter<wide::integer<Bits, Signed>>
{
constexpr auto parse(format_parse_context & ctx)
{
auto it = ctx.begin();
auto end = ctx.end();
/// Only support {}.
if (it != end && *it != '}')
throw format_error("invalid format");
return it;
}
template <typename FormatContext>
auto format(const wide::integer<Bits, Signed> & value, FormatContext & ctx)
{
return format_to(ctx.out(), "{}", to_string(value));
}
};

View File

@ -2,7 +2,7 @@
#include <DataTypes/NumberTraits.h>
#include <Common/Exception.h>
#include <numeric>
#include <common/extended_types.h>
#include <limits>
#include <type_traits>
@ -20,8 +20,6 @@ namespace ErrorCodes
extern const int DECIMAL_OVERFLOW;
}
template <class T>
inline constexpr bool is_gcd_lcm_implemeted = !is_big_int_v<T>;
template <typename A, typename B, typename Impl, typename Name>
struct GCDLCMImpl
@ -30,15 +28,7 @@ struct GCDLCMImpl
static const constexpr bool allow_fixed_string = false;
template <typename Result = ResultType>
static inline std::enable_if_t<!is_gcd_lcm_implemeted<Result>, Result>
apply(A, B)
{
throw Exception(ErrorCodes::NOT_IMPLEMENTED, "{} is not implemented for big integers", Name::name);
}
template <typename Result = ResultType>
static inline std::enable_if_t<is_gcd_lcm_implemeted<Result>, Result>
apply(A a, B b)
static inline Result apply(A a, B b)
{
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<A>::Type(a), typename NumberTraits::ToInteger<B>::Type(b));
throwIfDivisionLeadsToFPE(typename NumberTraits::ToInteger<B>::Type(b), typename NumberTraits::ToInteger<A>::Type(a));
@ -50,7 +40,7 @@ struct GCDLCMImpl
/// gcd() internally uses std::abs()
Int a_s = static_cast<Int>(a);
Int b_s = static_cast<Int>(b);
Int min = std::numeric_limits<Int>::min();
Int min = std::numeric_limits<Int>::lowest();
Int max = std::numeric_limits<Int>::max();
if (unlikely((a_s == min || a_s == max) || (b_s == min || b_s == max)))
throw Exception(ErrorCodes::DECIMAL_OVERFLOW, "Intermediate result overflow (signed a = {}, signed b = {}, min = {}, max = {})", a_s, b_s, min, max);

View File

@ -2,6 +2,8 @@
#include <Functions/FunctionBinaryArithmetic.h>
#include <Functions/GCDLCMImpl.h>
#include <boost/math/common_factor.hpp>
namespace DB
{
@ -19,7 +21,7 @@ struct GCDImpl : public GCDLCMImpl<A, B, GCDImpl<A, B>, NameGCD>
static ResultType applyImpl(A a, B b)
{
using Int = typename NumberTraits::ToInteger<ResultType>::Type;
return std::gcd(Int(a), Int(b));
return boost::math::gcd(Int(a), Int(b));
}
};

View File

@ -2,6 +2,9 @@
#include <Functions/FunctionBinaryArithmetic.h>
#include <Functions/GCDLCMImpl.h>
#include <boost/math/common_factor.hpp>
namespace
{
@ -46,7 +49,7 @@ struct LCMImpl : public GCDLCMImpl<A, B, LCMImpl<A, B>, NameLCM>
* (example: throw an exception or overflow in implementation specific way).
*/
Unsigned val1 = abs<Int>(a) / std::gcd(Int(a), Int(b));
Unsigned val1 = abs<Int>(a) / boost::math::gcd(Int(a), Int(b));
Unsigned val2 = abs<Int>(b);
/// Overflow in implementation specific way.