代码之家  ›  专栏  ›  技术社区  ›  Öö Tiib

两个有符号数字之间的距离

  •  5
  • Öö Tiib  · 技术社区  · 7 年前

    两个数字之间的距离通常是这样计算的:

    long distance(long x, long y)
    {
         return x > y ? x - y : y - x;
    }
    

    但是有签名 x y 这些减法可能会溢出,因此函数可以在C和C++中调用未定义的行为。

    解决这个问题的一种方法是使用unsigned类型来表示结果距离。距离不能为负,因此不需要有符号类型。有符号类型的最小值和最大值之间的距离应适合相同大小的无符号类型( 编辑:

    unsigned long distance(long x, long y)
    {
        return (x > y) ? (unsigned long)x - (unsigned long)y
                       : (unsigned long)y - (unsigned long)x;
    }
    

    3 回复  |  直到 7 年前
        1
  •  8
  •   chux    7 年前

    它现在是否以符合标准和可移植的方式正确计算两个有符号长之间的距离?

    对。

    罕见的例外 1


    考虑以下三种情况: x > y

    x>=0,y>=0

    .

    (unsigned long)x - (unsigned long)y
    

    x,y值都增加了 ULONG_MAX + 1 由于 (unsigned long)

    // is akin to 
    ((unsigned long)(x + ULONG_MAX + 1) - (unsigned long)(y + ULONG_MAX + 1))
    // or
    x - y // with unsigned math.
    

    x>=0,是<0

    (unsigned long)y 有价值的 y + ULONG_MAX + 1 ,比 x . (假设 ULONG_MAX/2 >= LONG_MAX 1 )差别是负的。然而 数学绕过去,再加回来 乌龙最大值+1

    // is akin to 
    ((unsigned long)x - (unsigned long)(y + ULONG_MAX + 1)) + (ULONG_MAX + 1).
    // or
    x - y // with unsigned math.
    

    x<0,y>=0

    这种情况是不可能的 x>y


    1 :C未指定 ULONG_MAX/2 == LONG_MAX 尽管这非常普遍。我在很久以前只见过一次,它并不适用。就是那个案子 ULONG_MAX == LONG_MAX ULONG\u MAX/2==长\u MAX 我怀疑一个现代化的平台会冒险不这么做。C没有具体说明 ULONG_MAX >= LONG_MAX .

    有符号整数类型的非负值范围是

    代码可以使用下面的代码来检测这些罕见的平台。

    #if ULONG_MAX/2 < LONG_MAX
      #error `unsigned long` too narrow.  Need new approach.
    #endif
    
        2
  •  0
  •   izac89    7 年前

    因为C和C++中定义了无符号溢出(和下溢),所以当使用2的补码算法时,修改后的函数就非常好了。

        3
  •  -1
  •   0___________    7 年前

    假设sizeof(unsigned long long)>sizeof(unsigned long)可以安全地声明为: unsigned long long distance(long x, long y)

    但是由于现在一个补码或另一个异国格式的数字已经不常用了(实际上,在这样的机器上编写C代码的可能性很小) unsigned long 类型可以容纳所有可能的距离。