安全地添加,减去无符号字符

时间:2013-12-10 20:53:19

标签: c++ unsigned integer-arithmetic

假设有一个8个无符号字符x1,x2,...x8,我们想要计算:

abs((x1 + x2 + x3 + x4) - (x5 + x6 + x7 + x8)) / 4

在不引入大量上溢或下溢错误的情况下,确保最准确结果的最佳方法是什么?

我在模板类中使用它,这就是为什么我不能将无符号值转换为有符号值。

3 个答案:

答案 0 :(得分:7)

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时出现问题。如果表达式的结果为负,那么您将获得一个使值为正(但定义良好)的转换。

答案 1 :(得分:1)

您似乎想要一个元函数来告诉您在计算中使用的中间数据类型。

    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;

您当然可以调整专业化并根据您的需要添加/删除,但这应该会给您正确的想法。

答案 2 :(得分:0)

与任何固定大小的数据一样,最好的方法是将它们转换为足够大的类型以适应最坏的情况。在这种情况下,将它们转换为int将足够好 - 它将适合任何可能值的范围,并允许处理潜在的下溢。

请注意,您必须小心减法 - 结果将取决于您要附加到它的语义:要么假设它永远不会下溢(并且任何负值都是错误或者应该被置于0 )或负值有意义,你确实想从中获取绝对值。