有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何将32位int移位32(再次)

好的,所以我知道通常的左移位和右移位只针对值0..31定义得很好。我在考虑如何最好地将其扩展到32,从而简化一些算法。我想到了:

 int32 << n & (n-32) >> 5

这似乎有效。问题是,它是否保证在任何体系结构(C,C++,java)上工作,并且能更有效地工作吗?p>


共 (1) 个答案

  1. # 1 楼答案

    在Java中,如果这些变量的类型为int,那么它就可以保证工作,因为Java中的>>会进行算术右移,并且移位超过31也有定义的行为。但要注意运算符优先级

    int lshift(int x, int n)
    {
        return (x << n) & ((n-32) >> 5);
    }
    

    这将适用于班次计数最多32次。但它可以修改为包含移位计数大于31的任何int值返回0

    return (x << n) & ((n-32) >> 31);
    
    <>但是,在C和C++中,^ {< CD1>}的大小和^ {< CD2>}的行为是implementation defined。不过,大多数(如果不是全部的话)现代实现都将其作为有符号类型的算术移位来实现。此外,移动超过可变宽度的行为是undefined。更糟糕的是,有符号溢出调用UB,所以即使左移31也会调用UB(until C++14)。因此,要获得定义良好的输出,您需要

    • 使用像uint32_t这样的无符号固定宽度类型(因此x << 31不是UB)
    • 使用对>>发出算术右移指令的编译器,对n使用有符号类型,或者自己实现算术右移
    • 屏蔽移位量,将int32_t的移位量限制为5位

    结果就是

    uint32_t lshift(uint32_t x, int32_t n)
    {
        return (x << (n & 0x1F)) & ((n-32) >> 31);
    }
    

    如果体系结构支持conditional instructions如x86或ARM,那么下面的方法可能会更快

    return n < 32 ? x << n : 0;
    

    在64位平台上,您可以通过在64位类型中进行移位,然后进行掩码操作,使这一过程变得更加简单。一些32位平台,比如ARM,确实支持32位移位,所以这种方法也很有效

    return ((uint64_t)x << (n & 0x3F)) & 0xFFFFFFFFU;
    

    您可以看到输出程序集here。我看不出还有什么可以改进的