我需要一个相当于 __builtin_clz
的 Java。
感觉答案应该是Long.numberOfLeadingZeros
,但它们返回的答案完全不同。
我开始怀疑这是否有一个低级的原因——也许是字节序?还是一些未签名的怪癖?
编辑:误报。这纯粹是由打字错误引起的 - 原始代码实际上调用了 __builtin_ctzll
并与 Long.numberOfTrailingZeros
答案 0 :(得分:4)
Long.numberOfLeadingZeros
完全正确。
您得到不同答案的事实是因为 C.C 没有定义 int
的含义。因此,__builtin_clz(a)
给出的答案在您运行它的每个框上都不同:它取决于 int
的位宽,并且根据 C 标准,{{1} } 是对你正在编译的系统方便的任何东西。如果是 32 位(这是很常见的位宽),int
会返回 27。如果是 64 位(也很常见),__builtin_clz(16)
会返回 59。
Java 通常不会“做”整个未定义 的事情。在 java 中,与 C 不同,__builtin_clz(16)
是一个有符号的 32 位数字。无论您在什么 VM、版本、平台或操作系统上运行或编译它。类似地,long 是有符号的 64 位。
尽管如此,int
像 Long.numberOfLeadingZeroes
一样有效地将数字视为无符号数:这意味着 __builtin_clz
,其中 x 是负数,总是返回 0(或者应该,根据C 规范),而 __builtin_clz(x)
的作用完全相同:对于负数,始终返回 0(无前导零位)。
换句话说,在 64 位系统上,Long.numberOfLeadingZeros
与 java 中的 __builtin_clz(x)
完美匹配。在 32 位系统上,Long.numberOfLeadingZeros(x)
返回的值小于 32(64 位上的 __builtin_clz(x)
为 59,但在 32 位上为 27),而在 Java 中,您必须使用 { {1}} 代替。 __builtin_clz(16)
返回 27。就像 Integer.numberOfLeadingZeros()
一样,如果目标是 Integer.numberOfLeadingZeros(16)
定义为 32 位的系统(如果目标是 32 位处理器)。
答案 1 :(得分:1)
误报:由拼写错误引起 - 我实际上需要 __builtin_ctzll
代替,现在更有意义了。
答案 2 :(得分:-1)
__builtin_clz()
计算非零 int
值中前导零的数量。这个数字取决于 int
类型的表示,因此在 java 中没有直接等价,因为 C 标准整数类型中的位数,例如 int
、long
和 long long
是实现定义的,而 Java 规范固定了类型 int
和 long
的大小和表示。
除了 __builtin_clz(int)
之外,gcc 还定义了 __builtin_clzl(long)
和 __builtin_clzll(long long)
。在当前的大多数系统上,C ABI 定义了 32 位的 int
和 64 位的 long long
,使得 Integer.numberOfLeadingZeros(int)
和 Long.numberOfLeadingZeros(long)
分别相当于 __builtin_clz
和 {{ 1}}。但是请注意,Java 函数为 C 内置函数没有的零参数定义了行为,因为它们是作为单个 CPU 指令实现的(在某些体系结构上)。
__builtin_clzll
、__builtin_ctz(int)
和 __builtin_ctzl(long)
计算相应类型的非零参数中尾随零的数量。对于非零值,尾随零的数量仅取决于参数的值,而不取决于其类型大小。对应的java方法是__builtin_ctzll(long long)
和Integer.numberOfTrailingZeros(int)
。这些方法是为所有参数值定义的,对于零参数分别返回 Long.numberOfTrailingZeros(long)
和 32
。