2017-01-13 19:45:18 +00:00
|
|
|
#pragma once
|
2017-02-02 22:08:19 +00:00
|
|
|
|
2018-09-03 13:34:16 +00:00
|
|
|
#include <cmath>
|
2017-02-02 22:08:19 +00:00
|
|
|
#include <limits>
|
2021-10-02 07:13:14 +00:00
|
|
|
#include <base/DecomposedFloat.h>
|
2021-04-25 09:30:43 +00:00
|
|
|
#include <Core/Defines.h>
|
|
|
|
#include <Core/Types.h>
|
2021-10-02 07:13:14 +00:00
|
|
|
#include <base/extended_types.h>
|
2018-09-03 15:55:16 +00:00
|
|
|
#include <Common/NaNUtils.h>
|
2016-11-21 13:21:35 +00:00
|
|
|
|
2017-01-11 13:38:36 +00:00
|
|
|
/** Preceptually-correct number comparisons.
|
|
|
|
* Example: Int8(-1) != UInt8(255)
|
|
|
|
*/
|
|
|
|
|
2016-11-21 13:21:35 +00:00
|
|
|
namespace accurate
|
|
|
|
{
|
|
|
|
|
2021-01-27 00:54:57 +00:00
|
|
|
using namespace DB;
|
2017-02-07 15:38:57 +00:00
|
|
|
|
2016-11-21 13:21:35 +00:00
|
|
|
|
2017-01-11 13:38:36 +00:00
|
|
|
template <typename A, typename B>
|
2021-04-25 09:30:43 +00:00
|
|
|
bool lessOp(A a, B b)
|
2016-11-21 13:21:35 +00:00
|
|
|
{
|
2021-05-06 15:45:58 +00:00
|
|
|
if constexpr (std::is_same_v<A, B>)
|
|
|
|
return a < b;
|
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// float vs float
|
|
|
|
if constexpr (std::is_floating_point_v<A> && std::is_floating_point_v<B>)
|
|
|
|
return a < b;
|
2016-11-21 13:21:35 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// anything vs NaN
|
2021-05-04 23:07:14 +00:00
|
|
|
if (isNaN(a) || isNaN(b))
|
|
|
|
return false;
|
2016-11-21 13:21:35 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// int vs int
|
2021-09-10 11:49:22 +00:00
|
|
|
if constexpr (is_integer<A> && is_integer<B>)
|
2021-04-25 09:30:43 +00:00
|
|
|
{
|
|
|
|
/// same signedness
|
|
|
|
if constexpr (is_signed_v<A> == is_signed_v<B>)
|
|
|
|
return a < b;
|
2016-11-21 13:21:35 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// different signedness
|
2016-11-21 13:21:35 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
if constexpr (is_signed_v<A> && !is_signed_v<B>)
|
2021-05-04 23:07:14 +00:00
|
|
|
return a < 0 || static_cast<make_unsigned_t<A>>(a) < b;
|
2020-08-19 11:52:17 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
if constexpr (!is_signed_v<A> && is_signed_v<B>)
|
2021-05-04 23:07:14 +00:00
|
|
|
return b >= 0 && a < static_cast<make_unsigned_t<B>>(b);
|
2021-04-25 09:30:43 +00:00
|
|
|
}
|
2020-08-19 11:52:17 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// int vs float
|
2021-09-10 11:49:22 +00:00
|
|
|
if constexpr (is_integer<A> && std::is_floating_point_v<B>)
|
2021-04-25 09:30:43 +00:00
|
|
|
{
|
|
|
|
if constexpr (sizeof(A) <= 4)
|
|
|
|
return static_cast<double>(a) < static_cast<double>(b);
|
2020-08-19 11:52:17 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
return DecomposedFloat<B>(b).greater(a);
|
|
|
|
}
|
2020-08-19 11:52:17 +00:00
|
|
|
|
2021-09-10 11:49:22 +00:00
|
|
|
if constexpr (std::is_floating_point_v<A> && is_integer<B>)
|
2021-04-25 09:30:43 +00:00
|
|
|
{
|
|
|
|
if constexpr (sizeof(B) <= 4)
|
|
|
|
return static_cast<double>(a) < static_cast<double>(b);
|
2020-08-19 11:52:17 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
return DecomposedFloat<A>(a).less(b);
|
|
|
|
}
|
2021-05-02 22:42:01 +00:00
|
|
|
|
2021-09-10 11:49:22 +00:00
|
|
|
static_assert(is_integer<A> || std::is_floating_point_v<A>);
|
|
|
|
static_assert(is_integer<B> || std::is_floating_point_v<B>);
|
2021-05-02 22:42:01 +00:00
|
|
|
__builtin_unreachable();
|
2020-08-19 11:52:17 +00:00
|
|
|
}
|
|
|
|
|
2016-11-21 13:21:35 +00:00
|
|
|
template <typename A, typename B>
|
2021-04-25 09:30:43 +00:00
|
|
|
bool greaterOp(A a, B b)
|
2016-11-21 13:21:35 +00:00
|
|
|
{
|
2021-04-25 09:30:43 +00:00
|
|
|
return lessOp(b, a);
|
2016-11-21 13:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename A, typename B>
|
2021-04-25 09:30:43 +00:00
|
|
|
bool greaterOrEqualsOp(A a, B b)
|
2016-11-21 13:21:35 +00:00
|
|
|
{
|
2021-05-05 22:02:00 +00:00
|
|
|
if (isNaN(a) || isNaN(b))
|
|
|
|
return false;
|
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
return !lessOp(a, b);
|
2016-11-21 13:21:35 +00:00
|
|
|
}
|
|
|
|
|
2017-01-11 13:38:36 +00:00
|
|
|
template <typename A, typename B>
|
2021-04-25 09:30:43 +00:00
|
|
|
bool lessOrEqualsOp(A a, B b)
|
2017-01-11 13:38:36 +00:00
|
|
|
{
|
2021-05-05 22:02:00 +00:00
|
|
|
if (isNaN(a) || isNaN(b))
|
|
|
|
return false;
|
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
return !lessOp(b, a);
|
2017-01-11 13:38:36 +00:00
|
|
|
}
|
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
template <typename A, typename B>
|
|
|
|
bool equalsOp(A a, B b)
|
2016-11-21 13:21:35 +00:00
|
|
|
{
|
2021-05-06 15:45:58 +00:00
|
|
|
if constexpr (std::is_same_v<A, B>)
|
|
|
|
return a == b;
|
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// float vs float
|
|
|
|
if constexpr (std::is_floating_point_v<A> && std::is_floating_point_v<B>)
|
|
|
|
return a == b;
|
2016-11-21 13:21:35 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// anything vs NaN
|
2021-05-04 23:09:32 +00:00
|
|
|
if (isNaN(a) || isNaN(b))
|
|
|
|
return false;
|
2017-06-15 09:12:32 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// int vs int
|
2021-09-10 11:49:22 +00:00
|
|
|
if constexpr (is_integer<A> && is_integer<B>)
|
2021-04-25 09:30:43 +00:00
|
|
|
{
|
|
|
|
/// same signedness
|
|
|
|
if constexpr (is_signed_v<A> == is_signed_v<B>)
|
|
|
|
return a == b;
|
2017-06-15 09:12:32 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// different signedness
|
2017-06-15 09:12:32 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
if constexpr (is_signed_v<A> && !is_signed_v<B>)
|
2021-05-04 23:08:42 +00:00
|
|
|
return a >= 0 && static_cast<make_unsigned_t<A>>(a) == b;
|
2018-08-15 16:43:40 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
if constexpr (!is_signed_v<A> && is_signed_v<B>)
|
2021-05-04 23:08:42 +00:00
|
|
|
return b >= 0 && a == static_cast<make_unsigned_t<B>>(b);
|
2021-04-25 09:30:43 +00:00
|
|
|
}
|
2018-08-15 16:43:40 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
/// int vs float
|
2021-09-10 11:49:22 +00:00
|
|
|
if constexpr (is_integer<A> && std::is_floating_point_v<B>)
|
2021-04-25 09:30:43 +00:00
|
|
|
{
|
|
|
|
if constexpr (sizeof(A) <= 4)
|
|
|
|
return static_cast<double>(a) == static_cast<double>(b);
|
2018-08-15 16:43:40 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
return DecomposedFloat<B>(b).equals(a);
|
|
|
|
}
|
2018-08-15 16:43:40 +00:00
|
|
|
|
2021-09-10 11:49:22 +00:00
|
|
|
if constexpr (std::is_floating_point_v<A> && is_integer<B>)
|
2021-04-25 09:30:43 +00:00
|
|
|
{
|
|
|
|
if constexpr (sizeof(B) <= 4)
|
|
|
|
return static_cast<double>(a) == static_cast<double>(b);
|
2018-08-15 16:43:40 +00:00
|
|
|
|
2021-04-25 09:30:43 +00:00
|
|
|
return DecomposedFloat<A>(a).equals(b);
|
|
|
|
}
|
2021-05-02 22:42:01 +00:00
|
|
|
|
2021-05-06 15:45:58 +00:00
|
|
|
/// e.g comparing UUID with integer.
|
|
|
|
return false;
|
2018-08-15 16:43:40 +00:00
|
|
|
}
|
|
|
|
|
2016-11-21 13:21:35 +00:00
|
|
|
template <typename A, typename B>
|
2021-04-25 09:30:43 +00:00
|
|
|
bool notEqualsOp(A a, B b)
|
2016-11-21 13:21:35 +00:00
|
|
|
{
|
2017-04-01 07:20:54 +00:00
|
|
|
return !equalsOp(a, b);
|
2016-11-21 13:21:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-04-17 16:10:40 +00:00
|
|
|
/// Converts numeric to an equal numeric of other type.
|
|
|
|
template <typename From, typename To>
|
|
|
|
inline bool NO_SANITIZE_UNDEFINED convertNumeric(From value, To & result)
|
|
|
|
{
|
2019-05-13 23:44:55 +00:00
|
|
|
/// If the type is actually the same it's not necessary to do any checks.
|
|
|
|
if constexpr (std::is_same_v<From, To>)
|
|
|
|
{
|
|
|
|
result = value;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-12-05 14:55:37 +00:00
|
|
|
if constexpr (std::is_floating_point_v<From> && std::is_floating_point_v<To>)
|
2020-12-05 13:18:56 +00:00
|
|
|
{
|
2020-12-02 10:09:13 +00:00
|
|
|
/// Note that NaNs doesn't compare equal to anything, but they are still in range of any Float type.
|
|
|
|
if (isNaN(value))
|
|
|
|
{
|
|
|
|
result = value;
|
|
|
|
return true;
|
|
|
|
}
|
2020-12-05 13:18:56 +00:00
|
|
|
|
|
|
|
if (value == std::numeric_limits<From>::infinity())
|
|
|
|
{
|
|
|
|
result = std::numeric_limits<To>::infinity();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (value == -std::numeric_limits<From>::infinity())
|
|
|
|
{
|
|
|
|
result = -std::numeric_limits<To>::infinity();
|
|
|
|
return true;
|
|
|
|
}
|
2020-12-02 10:09:13 +00:00
|
|
|
}
|
|
|
|
|
2021-05-04 23:07:14 +00:00
|
|
|
if (greaterOp(value, std::numeric_limits<To>::max())
|
|
|
|
|| lessOp(value, std::numeric_limits<To>::lowest()))
|
2019-04-17 16:10:40 +00:00
|
|
|
{
|
2020-12-02 10:09:13 +00:00
|
|
|
return false;
|
2019-04-17 16:10:40 +00:00
|
|
|
}
|
|
|
|
|
2020-12-05 13:46:14 +00:00
|
|
|
result = static_cast<To>(value);
|
|
|
|
return equalsOp(value, result);
|
2019-04-17 16:10:40 +00:00
|
|
|
}
|
|
|
|
|
2018-09-02 01:12:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
|
|
|
template <typename A, typename B> struct EqualsOp
|
|
|
|
{
|
|
|
|
/// An operation that gives the same result, if arguments are passed in reverse order.
|
|
|
|
using SymmetricOp = EqualsOp<B, A>;
|
|
|
|
|
|
|
|
static UInt8 apply(A a, B b) { return accurate::equalsOp(a, b); }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename A, typename B> struct NotEqualsOp
|
|
|
|
{
|
|
|
|
using SymmetricOp = NotEqualsOp<B, A>;
|
|
|
|
static UInt8 apply(A a, B b) { return accurate::notEqualsOp(a, b); }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename A, typename B> struct GreaterOp;
|
|
|
|
|
|
|
|
template <typename A, typename B> struct LessOp
|
|
|
|
{
|
|
|
|
using SymmetricOp = GreaterOp<B, A>;
|
|
|
|
static UInt8 apply(A a, B b) { return accurate::lessOp(a, b); }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename A, typename B> struct GreaterOp
|
|
|
|
{
|
|
|
|
using SymmetricOp = LessOp<B, A>;
|
|
|
|
static UInt8 apply(A a, B b) { return accurate::greaterOp(a, b); }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename A, typename B> struct GreaterOrEqualsOp;
|
|
|
|
|
|
|
|
template <typename A, typename B> struct LessOrEqualsOp
|
|
|
|
{
|
|
|
|
using SymmetricOp = GreaterOrEqualsOp<B, A>;
|
|
|
|
static UInt8 apply(A a, B b) { return accurate::lessOrEqualsOp(a, b); }
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename A, typename B> struct GreaterOrEqualsOp
|
|
|
|
{
|
|
|
|
using SymmetricOp = LessOrEqualsOp<B, A>;
|
|
|
|
static UInt8 apply(A a, B b) { return accurate::greaterOrEqualsOp(a, b); }
|
|
|
|
};
|
2016-11-21 13:21:35 +00:00
|
|
|
|
|
|
|
}
|