mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 16:42:05 +00:00
Added numeric limits for UInt128
This commit is contained in:
parent
d636e1618b
commit
4cd5025e83
@ -28,23 +28,28 @@ struct UInt128
|
||||
UInt64 low;
|
||||
UInt64 high;
|
||||
|
||||
/// TODO: Make this constexpr. Currently it is used in unions
|
||||
/// and union cannot contain member with non trivial constructor
|
||||
/// constructor must be non user provided but compiler cannot constexpr constructor
|
||||
/// if members low and high are not initialized, if we default member initialize them
|
||||
/// constructor becomes non trivial.
|
||||
UInt128() = default;
|
||||
explicit UInt128(const UInt64 low_, const UInt64 high_) : low(low_), high(high_) {}
|
||||
explicit constexpr UInt128(const UInt64 low_, const UInt64 high_) : low(low_), high(high_) {}
|
||||
|
||||
/// We need Int128 to UInt128 conversion or AccurateComparison will call greaterOp<Int128, UInt64> instead of greaterOp<Int128, UInt128>
|
||||
explicit UInt128(const Int128 rhs) : low(rhs), high(rhs >> 64) {}
|
||||
explicit UInt128(const Int64 rhs) : low(rhs), high() {}
|
||||
explicit UInt128(const Int32 rhs) : low(rhs), high() {}
|
||||
explicit UInt128(const Int16 rhs) : low(rhs), high() {}
|
||||
explicit UInt128(const Int8 rhs) : low(rhs), high() {}
|
||||
explicit UInt128(const UInt8 rhs) : low(rhs), high() {}
|
||||
explicit UInt128(const UInt16 rhs) : low(rhs), high() {}
|
||||
explicit UInt128(const UInt32 rhs) : low(rhs), high() {}
|
||||
explicit UInt128(const UInt64 rhs) : low(rhs), high() {}
|
||||
explicit UInt128(const Float32 rhs) : low(rhs), high() {}
|
||||
explicit UInt128(const Float64 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const Int128 rhs) : low(rhs), high(rhs >> 64) {}
|
||||
explicit constexpr UInt128(const Int64 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const Int32 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const Int16 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const Int8 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const UInt8 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const UInt16 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const UInt32 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const UInt64 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const Float32 rhs) : low(rhs), high() {}
|
||||
explicit constexpr UInt128(const Float64 rhs) : low(rhs), high() {}
|
||||
|
||||
auto tuple() const { return std::tie(high, low); }
|
||||
constexpr auto tuple() const { return std::tie(high, low); }
|
||||
|
||||
String toHexString() const
|
||||
{
|
||||
@ -53,31 +58,31 @@ struct UInt128
|
||||
return res;
|
||||
}
|
||||
|
||||
bool inline operator== (const UInt128 rhs) const { return tuple() == rhs.tuple(); }
|
||||
bool inline operator!= (const UInt128 rhs) const { return tuple() != rhs.tuple(); }
|
||||
bool inline operator< (const UInt128 rhs) const { return tuple() < rhs.tuple(); }
|
||||
bool inline operator<= (const UInt128 rhs) const { return tuple() <= rhs.tuple(); }
|
||||
bool inline operator> (const UInt128 rhs) const { return tuple() > rhs.tuple(); }
|
||||
bool inline operator>= (const UInt128 rhs) const { return tuple() >= rhs.tuple(); }
|
||||
constexpr bool operator== (const UInt128 rhs) const { return tuple() == rhs.tuple(); }
|
||||
constexpr bool operator!= (const UInt128 rhs) const { return tuple() != rhs.tuple(); }
|
||||
constexpr bool operator< (const UInt128 rhs) const { return tuple() < rhs.tuple(); }
|
||||
constexpr bool operator<= (const UInt128 rhs) const { return tuple() <= rhs.tuple(); }
|
||||
constexpr bool operator> (const UInt128 rhs) const { return tuple() > rhs.tuple(); }
|
||||
constexpr bool operator>= (const UInt128 rhs) const { return tuple() >= rhs.tuple(); }
|
||||
|
||||
bool inline operator == (const Int128 rhs) const { return *this == UInt128(rhs, rhs >> 64) && rhs >= 0; }
|
||||
bool inline operator != (const Int128 rhs) const { return *this != UInt128(rhs, rhs >> 64) || rhs < 0; }
|
||||
bool inline operator >= (const Int128 rhs) const { return *this >= UInt128(rhs, rhs >> 64) || rhs < 0; }
|
||||
bool inline operator > (const Int128 rhs) const { return *this > UInt128(rhs, rhs >> 64) || rhs < 0; }
|
||||
bool inline operator <= (const Int128 rhs) const { return *this <= UInt128(rhs, rhs >> 64) && rhs >= 0; }
|
||||
bool inline operator < (const Int128 rhs) const { return *this < UInt128(rhs, rhs >> 64) && rhs >= 0; }
|
||||
constexpr bool operator == (const Int128 rhs) const { return *this == UInt128(rhs, rhs >> 64) && rhs >= 0; }
|
||||
constexpr bool operator != (const Int128 rhs) const { return *this != UInt128(rhs, rhs >> 64) || rhs < 0; }
|
||||
constexpr bool operator >= (const Int128 rhs) const { return *this >= UInt128(rhs, rhs >> 64) || rhs < 0; }
|
||||
constexpr bool operator > (const Int128 rhs) const { return *this > UInt128(rhs, rhs >> 64) || rhs < 0; }
|
||||
constexpr bool operator <= (const Int128 rhs) const { return *this <= UInt128(rhs, rhs >> 64) && rhs >= 0; }
|
||||
constexpr bool operator < (const Int128 rhs) const { return *this < UInt128(rhs, rhs >> 64) && rhs >= 0; }
|
||||
|
||||
bool inline operator > (const Int256 rhs) const { return (rhs < 0) || ((Int256(high) << 64) + low) > rhs; }
|
||||
bool inline operator > (const UInt256 rhs) const { return ((UInt256(high) << 64) + low) > rhs; }
|
||||
bool inline operator < (const Int256 rhs) const { return (rhs >= 0) && ((Int256(high) << 64) + low) < rhs; }
|
||||
bool inline operator < (const UInt256 rhs) const { return ((UInt256(high) << 64) + low) < rhs; }
|
||||
constexpr bool operator > (const Int256 rhs) const { return (rhs < 0) || ((Int256(high) << 64) + low) > rhs; }
|
||||
constexpr bool operator > (const UInt256 rhs) const { return ((UInt256(high) << 64) + low) > rhs; }
|
||||
constexpr bool operator < (const Int256 rhs) const { return (rhs >= 0) && ((Int256(high) << 64) + low) < rhs; }
|
||||
constexpr bool operator < (const UInt256 rhs) const { return ((UInt256(high) << 64) + low) < rhs; }
|
||||
|
||||
template <typename T> bool inline operator== (const T rhs) const { return *this == UInt128(rhs); }
|
||||
template <typename T> bool inline operator!= (const T rhs) const { return *this != UInt128(rhs); }
|
||||
template <typename T> bool inline operator>= (const T rhs) const { return *this >= UInt128(rhs); }
|
||||
template <typename T> bool inline operator> (const T rhs) const { return *this > UInt128(rhs); }
|
||||
template <typename T> bool inline operator<= (const T rhs) const { return *this <= UInt128(rhs); }
|
||||
template <typename T> bool inline operator< (const T rhs) const { return *this < UInt128(rhs); }
|
||||
template <typename T> constexpr bool operator== (const T rhs) const { return *this == UInt128(rhs); }
|
||||
template <typename T> constexpr bool operator!= (const T rhs) const { return *this != UInt128(rhs); }
|
||||
template <typename T> constexpr bool operator>= (const T rhs) const { return *this >= UInt128(rhs); }
|
||||
template <typename T> constexpr bool operator> (const T rhs) const { return *this > UInt128(rhs); }
|
||||
template <typename T> constexpr bool operator<= (const T rhs) const { return *this <= UInt128(rhs); }
|
||||
template <typename T> constexpr bool operator< (const T rhs) const { return *this < UInt128(rhs); }
|
||||
|
||||
template <typename T> explicit operator T() const
|
||||
{
|
||||
@ -91,15 +96,15 @@ struct UInt128
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
UInt128 & operator= (const UInt64 rhs) { low = rhs; high = 0; return *this; }
|
||||
constexpr UInt128 & operator= (const UInt64 rhs) { low = rhs; high = 0; return *this; }
|
||||
};
|
||||
|
||||
template <typename T> bool inline operator == (T a, const UInt128 b) { return b.operator==(a); }
|
||||
template <typename T> bool inline operator != (T a, const UInt128 b) { return b.operator!=(a); }
|
||||
template <typename T> bool inline operator >= (T a, const UInt128 b) { return b <= a; }
|
||||
template <typename T> bool inline operator > (T a, const UInt128 b) { return b < a; }
|
||||
template <typename T> bool inline operator <= (T a, const UInt128 b) { return b >= a; }
|
||||
template <typename T> bool inline operator < (T a, const UInt128 b) { return b > a; }
|
||||
template <typename T> constexpr bool operator == (T a, const UInt128 b) { return b.operator==(a); }
|
||||
template <typename T> constexpr bool operator != (T a, const UInt128 b) { return b.operator!=(a); }
|
||||
template <typename T> constexpr bool operator >= (T a, const UInt128 b) { return b <= a; }
|
||||
template <typename T> constexpr bool operator > (T a, const UInt128 b) { return b < a; }
|
||||
template <typename T> constexpr bool operator <= (T a, const UInt128 b) { return b >= a; }
|
||||
template <typename T> constexpr bool operator < (T a, const UInt128 b) { return b > a; }
|
||||
|
||||
template <> inline constexpr bool IsNumber<UInt128> = true;
|
||||
template <> struct TypeName<UInt128> { static constexpr const char * get() { return "UInt128"; } };
|
||||
@ -246,4 +251,45 @@ template <> struct hash<DB::UInt128>
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class numeric_limits<DB::UInt128>
|
||||
{
|
||||
public:
|
||||
static constexpr bool is_specialized = true;
|
||||
static constexpr bool is_signed = is_signed<DB::UInt128>::value;
|
||||
static constexpr bool is_integer = is_integer<DB::UInt128>::value;
|
||||
static constexpr bool is_exact = true;
|
||||
static constexpr bool has_infinity = false;
|
||||
static constexpr bool has_quiet_NaN = false;
|
||||
static constexpr bool has_signaling_NaN = false;
|
||||
static constexpr std::float_denorm_style has_denorm = std::denorm_absent;
|
||||
static constexpr bool has_denorm_loss = false;
|
||||
static constexpr std::float_round_style round_style = std::round_toward_zero;
|
||||
static constexpr bool is_iec559 = false;
|
||||
static constexpr bool is_bounded = true;
|
||||
static constexpr bool is_modulo = true;
|
||||
static constexpr int digits = std::numeric_limits<UInt64>::digits * 2;
|
||||
static constexpr int digits10 = digits * 0.30103 /*std::log10(2)*/;
|
||||
static constexpr int max_digits10 = 0;
|
||||
static constexpr int radix = 2;
|
||||
static constexpr int min_exponent = 0;
|
||||
static constexpr int min_exponent10 = 0;
|
||||
static constexpr int max_exponent = 0;
|
||||
static constexpr int max_exponent10 = 0;
|
||||
static constexpr bool traps = true;
|
||||
static constexpr bool tinyness_before = false;
|
||||
|
||||
static constexpr DB::UInt128 min() noexcept
|
||||
{
|
||||
return DB::UInt128(0, 0);
|
||||
}
|
||||
|
||||
static constexpr DB::UInt128 max() noexcept
|
||||
{
|
||||
return DB::UInt128(std::numeric_limits<UInt64>::max(), std::numeric_limits<UInt64>::max());
|
||||
}
|
||||
|
||||
static constexpr DB::UInt128 lowest() noexcept { return min(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -213,17 +213,53 @@ struct ConvertImpl
|
||||
throw Exception("Unexpected inf or nan to big int conversion", ErrorCodes::NOT_IMPLEMENTED);
|
||||
}
|
||||
else
|
||||
vec_to[i] = bigint_cast<ToFieldType>(vec_from[i]);
|
||||
{
|
||||
ToFieldType from = bigint_cast<ToFieldType>(vec_from[i]);
|
||||
|
||||
if constexpr (convert_strategy == ConvertStrategy::Accurate)
|
||||
{
|
||||
if (accurate::greaterOp(std::numeric_limits<ToFieldType>::max(), vec_from[i])
|
||||
|| accurate::greaterOp(vec_from[i], std::numeric_limits<ToFieldType>::min()))
|
||||
{
|
||||
vec_null_map_to[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_to[i] = static_cast<ToFieldType>(from);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_to[i] = static_cast<ToFieldType>(from);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_same_v<ToFieldType, UInt128> && sizeof(FromFieldType) <= sizeof(UInt64))
|
||||
vec_to[i] = static_cast<ToFieldType>(static_cast<UInt64>(vec_from[i]));
|
||||
{
|
||||
UInt64 from = static_cast<UInt64>(vec_from[i]);
|
||||
if constexpr (convert_strategy == ConvertStrategy::Accurate)
|
||||
{
|
||||
if (accurate::greaterOp(vec_from[i], std::numeric_limits<ToFieldType>::max()) ||
|
||||
accurate::greaterOp(std::numeric_limits<ToFieldType>::min(), vec_from[i]))
|
||||
{
|
||||
vec_null_map_to[i] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_to[i] = static_cast<ToFieldType>(from);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
vec_to[i] = static_cast<ToFieldType>(from);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if constexpr (convert_strategy == ConvertStrategy::Accurate)
|
||||
{
|
||||
/// TODO: Add support for big integers
|
||||
if (accurate::greaterOp(std::numeric_limits<ToFieldType>::max(), vec_from[i]) ||
|
||||
accurate::greaterOp(vec_from[i], std::numeric_limits<ToFieldType>::min()))
|
||||
if (accurate::greaterOp(vec_from[i], std::numeric_limits<ToFieldType>::max()) ||
|
||||
accurate::greaterOp(std::numeric_limits<ToFieldType>::min(), vec_from[i]))
|
||||
{
|
||||
vec_null_map_to[i] = true;
|
||||
}
|
||||
@ -2066,7 +2102,8 @@ private:
|
||||
auto function_adaptor = FunctionOverloadResolverAdaptor(std::make_unique<DefaultOverloadResolver>(function))
|
||||
.build({ColumnWithTypeAndName{nullptr, from_type, ""}});
|
||||
|
||||
return [function_adaptor] (ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, const ColumnNullable *, size_t input_rows_count)
|
||||
return [function_adaptor]
|
||||
(ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, const ColumnNullable *, size_t input_rows_count)
|
||||
{
|
||||
return function_adaptor->execute(arguments, result_type, input_rows_count);
|
||||
};
|
||||
@ -2087,7 +2124,7 @@ private:
|
||||
{
|
||||
TypeIndex from_type_index = from_type->getTypeId();
|
||||
WhichDataType which(from_type_index);
|
||||
bool can_apply_accurate_cast = is_accurate_cast_or_null && (which.isNativeInt() || which.isNativeUInt() || which.isFloat());
|
||||
bool can_apply_accurate_cast = is_accurate_cast_or_null && (which.isInt() || which.isUInt() || which.isFloat());
|
||||
|
||||
if (requested_result_is_nullable && checkAndGetDataType<DataTypeString>(from_type.get()))
|
||||
{
|
||||
@ -2102,7 +2139,7 @@ private:
|
||||
return createFunctionAdaptor(function, from_type);
|
||||
}
|
||||
|
||||
return [from_type_index]
|
||||
return [from_type_index]
|
||||
(ColumnsWithTypeAndName & arguments, const DataTypePtr & result_type, const ColumnNullable *, size_t input_rows_count)
|
||||
{
|
||||
ColumnPtr result_column;
|
||||
@ -2112,7 +2149,7 @@ private:
|
||||
using LeftDataType = typename Types::LeftType;
|
||||
using RightDataType = typename Types::RightType;
|
||||
|
||||
if constexpr (IsDataTypeNumber<LeftDataType> && IsDataTypeNumber<RightDataType>)
|
||||
if constexpr (IsDataTypeNumber<LeftDataType> && IsDataTypeNumber<RightDataType>)
|
||||
{
|
||||
result_column = ConvertImpl<LeftDataType, RightDataType, NameCast>::execute(arguments, result_type, input_rows_count, AccurateAdditions());
|
||||
return true;
|
||||
@ -2130,7 +2167,6 @@ private:
|
||||
|
||||
return result_column;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
WrapperType createStringWrapper(const DataTypePtr & from_type) const
|
||||
@ -2168,11 +2204,13 @@ private:
|
||||
which.isFloat() ||
|
||||
which.isDateOrDateTime() ||
|
||||
which.isStringOrFixedString();
|
||||
if (!ok) {
|
||||
if (!ok)
|
||||
{
|
||||
if (is_accurate_cast_or_null)
|
||||
return createToNullableColumnWrapper();
|
||||
else
|
||||
throw Exception{"Conversion from " + from_type->getName() + " to " + to_type->getName() + " is not supported",
|
||||
else
|
||||
throw Exception{
|
||||
"Conversion from " + from_type->getName() + " to " + to_type->getName() + " is not supported",
|
||||
ErrorCodes::CANNOT_CONVERT_TYPE};
|
||||
}
|
||||
|
||||
@ -2198,9 +2236,10 @@ private:
|
||||
{
|
||||
if (is_accurate_cast)
|
||||
return nullable_column_wrapper(arguments, result_type, columnNullable, input_rows_count);
|
||||
else
|
||||
throw Exception{"Conversion from " + std::string(getTypeName(type_index)) + " to " + to_type->getName() +
|
||||
" is not supported", ErrorCodes::CANNOT_CONVERT_TYPE};
|
||||
else
|
||||
throw Exception{
|
||||
"Conversion from " + std::string(getTypeName(type_index)) + " to " + to_type->getName() + " is not supported",
|
||||
ErrorCodes::CANNOT_CONVERT_TYPE};
|
||||
}
|
||||
|
||||
return result_column;
|
||||
|
@ -111,7 +111,7 @@ public:
|
||||
if constexpr (exception_mode == ConvertToFixedStringExceptionMode::Null)
|
||||
return ColumnNullable::create(std::move(column_fixed), std::move(col_null_map_to));
|
||||
else
|
||||
return column_fixed;;
|
||||
return column_fixed;
|
||||
}
|
||||
else if (const auto * column_fixed_string = checkAndGetColumn<ColumnFixedString>(column.get()))
|
||||
{
|
||||
|
@ -1,7 +1,17 @@
|
||||
SELECT cast(-1, 'UInt8');
|
||||
SELECT accurateCastOrNull(-1, 'UInt8');
|
||||
|
||||
SELECT cast(257, 'Int8');
|
||||
SELECT accurateCastOrNull(5, 'UInt8');
|
||||
SELECT accurateCastOrNull(257, 'Int8');
|
||||
SELECT accurateCastOrNull(-1, 'UInt16');
|
||||
SELECT accurateCastOrNull(65536, 'UInt16');
|
||||
SELECT accurateCastOrNull(5, 'UInt16');
|
||||
SELECT accurateCastOrNull(-1, 'UInt32');
|
||||
SELECT accurateCastOrNull(5, 'UInt32');
|
||||
SELECT accurateCastOrNull(4294967296, 'UInt32');
|
||||
SELECT accurateCastOrNull(-1, 'UInt64');
|
||||
SELECT accurateCastOrNull(-1, 'UInt128');
|
||||
SELECT accurateCastOrNull(-1, 'UInt256');
|
||||
|
||||
SELECT accurateCastOrNull(128, 'Int8');
|
||||
SELECT accurateCastOrNull(5, 'Int8');
|
||||
|
||||
SELECT accurateCastOrNull('123', 'FixedString(2)');
|
Loading…
Reference in New Issue
Block a user