假设一个有 8 个无符号字符x1,x2,...x8
,我们要计算:
abs((x1 + x2 + x3 + x4) - (x5 + x6 + x7 + x8)) / 4
在不引入大的上溢或下溢错误的情况下,确保最准确结果的最佳方法是什么?
我在模板类中使用它,这就是为什么我不能将无符号值转换为有符号值。
假设一个有 8 个无符号字符x1,x2,...x8
,我们要计算:
abs((x1 + x2 + x3 + x4) - (x5 + x6 + x7 + x8)) / 4
在不引入大的上溢或下溢错误的情况下,确保最准确结果的最佳方法是什么?
我在模板类中使用它,这就是为什么我不能将无符号值转换为有符号值。
operator +
唯一适用于int
和更大的。因此,当您将它与类型char
(小于 int)的对象一起使用时,这些值会在操作发生之前自动转换为 int。
因此
abs((x1 + x2 + x3 + x4) - (x5 + x6 + x7 + x8)) / 4
由编译器转换为:
abs((static_cast<int>(x1) + static_cast<int>(x2) + static_cast<int>(x3) + static_cast<int>(x4)) -
(static_cast<int>(x5) + static_cast<int>(x6) + static_cast<int>(x7) + static_cast<int>(x8))) / 4
因此,除非您添加了很多 char,否则您不太可能溢出。
将结果分配回unsigned char
. 如果表达式的结果为负,那么您将进行转换,使值变为正(但定义明确)。
您似乎想要一个元函数来告诉您在计算中使用什么中间数据类型。
template <class T>
struct arithmetic_type
{
typedef std::int64_t type;
};
template <>
struct arithmetic_type<float>
{
typedef double type;
};
template <>
struct arithmetic_type<double>
{
typedef double type;
};
template <>
struct arithmetic_type<std::uint64_t>
{
typedef std::uint64_t type;
};
typedef typename arithmetic_type<T>::type ar_type;
abs(((ar_type)x1 + x2 + x3 + x4) - ((ar_type)x5 + x6 + x7 + x8)) / 4;
您当然可以根据需要调整专业化和添加/删除,但这应该会给您正确的想法。
与任何固定大小的数据一样,最好的方法是将它们转换为足够大的类型以适应最坏的情况。在这种情况下,将它们强制转换int
就足够了——它将适合任何可能值的范围,并允许处理潜在的下溢。
请注意,您必须小心减法 - 结果将取决于您要附加到它的语义:您假设它永远不会下溢(并且任何负值都是错误或应该以 0 为底)或负value 是有意义的,您确实想从中获取绝对值。