gpt4 book ai didi

c++ - 绝对安全的静态/运行时数字转换

转载 作者:行者123 更新时间:2023-11-28 01:50:35 26 4
gpt4 key购买 nike

我正在寻找一个 C++ 特性/代码,我觉得它是非常基本的并且是泛型编程所必需的:能够判断给定数字类型(整数或 float )的某些值是否完全 可由另一个给定的数字类型表示。

长话短说,我有许多模板类,它们对任意数字类型进行操作,并且它们必须正确地互操作。例如,内存流可能使用 32 位大小类型,但文件流具有 64 位大小类型,并且在它们之间传递数据可能会导致溢出。另一个例子是几何类,一个参数化为使用 64 位 float ,另一个参数化为使用 64 位整数:在它们之间传递数据可能会导致舍入错误(整数不能表示分数)和溢出(整数的值范围比相同的更大)大小的 float )。

所以我想知道是否应该自己实现,或者有现成的解决方案(不幸的是,我不能使用像 Boost 这样的重量级库)?

更新:在输入我的问题时,我决定推出我自己的实现:

#include <limits>
#include <array>

enum class NumberClass {
UNKNOWN, INTEGER, FLOAT
};

template <typename T> struct NumberClassResolver {
static const NumberClass value = std::numeric_limits<T>::is_integer ? NumberClass::INTEGER : (std::numeric_limits<T>::is_iec559 ? NumberClass::FLOAT : NumberClass::UNKNOWN);
};

template <typename From, typename To> struct StaticIntegerCastCheck {
static const bool value = std::is_same<From, To>::value || (sizeof(From) < sizeof(To)) || ((std::numeric_limits<From>::is_signed == std::numeric_limits<To>::is_signed) && (sizeof(From) <= sizeof(To)));
};
template <typename From, typename To> struct StaticFloatCastCheck {
static const bool value = std::is_same<From, To>::value || (sizeof(From) < sizeof(To)); // NOTE Here we rely on the fact, that floats are IEEE-754 compliant and bigger ones has both bigger significand and exponent
};


template <NumberClass FromClass, NumberClass ToClass, typename From, typename To> struct StaticNumberCastCheckHelper;
template <typename From, typename To> struct StaticNumberCastCheckHelper<NumberClass::INTEGER, NumberClass::INTEGER, From, To> {
static const bool value = StaticIntegerCastCheck<From, To>::value;
};
template <typename From, typename To> struct StaticNumberCastCheckHelper<NumberClass::INTEGER, NumberClass::FLOAT, From, To> {
static const bool value = sizeof(To) > sizeof(From); // NOTE Here we rely on assumption, that sizes are POTs and significand part of a float never takes up less that half of it's size
};
template <typename From, typename To> struct StaticNumberCastCheckHelper<NumberClass::FLOAT, NumberClass::INTEGER, From, To> {
static const bool value = false;
};
template <typename From, typename To> struct StaticNumberCastCheckHelper<NumberClass::FLOAT, NumberClass::FLOAT, From, To> {
static const bool value = StaticFloatCastCheck<From, To>::value;
};

template <typename From, typename To> struct StaticNumberCastCheck {
static const bool value = StaticNumberCastCheckHelper<NumberClassResolver<From>::value, NumberClassResolver<To>::value, From, To>::value;
};

template <bool isFromSigned, bool isToSigned, typename From, typename To> struct RuntimeIntegerCastCheckHelper {
static bool check(From value) {
return (value >= std::numeric_limits<To>::min()) && (value <= std::numeric_limits<To>::max()); // NOTE Compiler must eliminate comparisson to zero for unsigned types
}
};

template <bool isStaticallySafeCastable, NumberClass FromClass, NumberClass ToClass, typename From, typename To> struct RuntimeNumberCastCheckHelper {
static bool check(From value) {
return false;
}
};
template <NumberClass FromClass, NumberClass ToClass, typename From, typename To> struct RuntimeNumberCastCheckHelper<true, FromClass, ToClass, From, To> {
static bool check(From value) {
return true;
}
};
template <typename From, typename To> struct RuntimeNumberCastCheckHelper<false, NumberClass::INTEGER, NumberClass::INTEGER, From, To> {
static bool check(From value) {
return RuntimeIntegerCastCheckHelper<std::numeric_limits<From>::is_signed, std::numeric_limits<To>::is_signed, From, To>::check(value);
}
};
template <typename From, typename To> struct RuntimeNumberCastCheckHelper<false, NumberClass::FLOAT, NumberClass::FLOAT, From, To> {
static bool check(From value) {
To toValue = static_cast<To>(value);
From fromValue = static_cast<From>(toValue);
return value == fromValue;
}
};
template <typename From, typename To> struct RuntimeNumberCastCheckHelper<false, NumberClass::INTEGER, NumberClass::FLOAT, From, To> {
static bool check(From value) {
To toValue = static_cast<To>(value);
From fromValue = static_cast<From>(toValue);
return value == fromValue;
}
};
template <typename From, typename To> struct RuntimeNumberCastCheckHelper<false, NumberClass::FLOAT, NumberClass::INTEGER, From, To> {
static bool check(From value) {
To toValue = static_cast<To>(value);
From fromValue = static_cast<From>(toValue);
return value == fromValue;
}
};

template <typename From, typename To> struct RuntimeNumberCastCheck {
static bool check(From value) {
return RuntimeNumberCastCheckHelper<StaticNumberCastCheck<From, To>::value, NumberClassResolver<From>::value, NumberClassResolver<To>::value, From, To>::check(value);
}
};

预期用途:

StaticNumberCastCheck<uint8_t, float>::value; // can we safely cast all 8-bit unsigned integers to float?
RuntimeNumberCastCheck<float, uint8_t>::check(42); // can we safely cast 42 from float to 8-bit unsigned integer?

它基于一些广泛的假设,所以我也很高兴听到我是否遗漏了什么(误报、优化等)。

最佳答案

此信息可以在 documentation of the std::numeric_traits template 中找到, 它为您提供每个整数或浮点类型的最小值和最大值(以及给定的数字类型是整数还是浮点)。

通常,整数类型显然不能表达每个浮点值,因此您的首要任务是检查 is_exact。这将排除整数和浮点类型之间的比较。然后,您可以比较 min()max(),看看给定的数值类型是否覆盖了另一种数值类型的范围。

关于c++ - 绝对安全的静态/运行时数字转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43172955/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com