Cython 中 unsigned int 上的 C 风格算术
C-Style Arithmetic in Cython on unsigned int
是否有一种简单的方法可以像在 C 语言中使用 Cython 对无符号整数进行左移和减法运算?
例如:
def left_shift(unsigned int x, unsigned int shift):
return x << shift
def main():
print left_shift(0xffffffff, 4)
print left_shift(0xffffffff, 8)
print left_shift(0xffffffff, 12)
我希望这会打印
的十进制等价物
0xfffffff0
0xffffff00
0xfffff000
这就是我得到的。
4294967280
4294967040
4294963200
但是,如果我尝试做一些更复杂的事情,例如在大输入上使用 Jenkins 的哈希函数之一,这就是我得到的:
def hash_fcn1(unsigned int key):
key = (key ^ 0xdeadbeef) + (key << 4)
key = key ^ (key >> 10)
key = key + (key << 7)
key = key ^ (key >> 13)
return key
hash_fcn1(0xffffffff)
File "./hash_fcn_test.py", line 94, in <module>
main()
File "./hash_fcn_test.py", line 60, in main
print hash_fcn1(0xffffffff)
File "hash_fcns.pyx", line 6, in hash_fcns.hash_fcn1 (/home/medusa/.pyxbld/temp.linux-x86_64-2.7/pyrex/hash_fcns.c:854)
key = (key ^ 0xdeadbeef) + (key << 4)
**OverflowError: value too large to convert to unsigned int**
当计算结果为负数时,会出现类似的问题。有没有办法解决这些问题?我希望计算的行为与在 C 中的行为一样。这个要求是不是太过分了?我在网上搜索了一下,似乎常见的做法只是 按位和 (&) 每个结果 MAX_INT , 但这是非常沉重的。
是否只有我可以在 Cython 编译器或其他地方设置的标志?
我相信,cython 的算术类型取决于所操作的数字类型。我相信您的代码中的问题出在这一行 key = (key ^ 0xdeadbeef) + (key << 4)
。 Cython 将此行翻译为:
__pyx_t_1 = __Pyx_PyInt_From_unsigned_int(__pyx_v_key); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = PyNumber_Xor(__pyx_t_1, __pyx_int_3735928559); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_1 = __Pyx_PyInt_From_long((__pyx_v_key << 4)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_3 = PyNumber_Add(__pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_4 = __Pyx_PyInt_As_unsigned_int(__pyx_t_3); if (unlikely((__pyx_t_4 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_v_key = __pyx_t_4;
您可能想要的是这个 key = (key ^ <unsigned int> 0xdeadbeef) + (key << 4)
,它被翻译成:
__pyx_v_key = ((__pyx_v_key ^ ((unsigned int)0xdeadbeef)) + (__pyx_v_key << 4));
大不同吧:)。您可能会发现这里需要显式转换令人惊讶,但我认为这是有道理的。在 cython 中,一切行为都与在 pytyhon 中一样,除非明确告诉你做一些不同的事情。这里 cython 将 0xdeadbeef
视为 python int 类型,除非您明确地将其强制转换或将其分配给类型化变量。
如果您还没有使用它,我强烈建议您使用 cython -a
并查看创建的 html 文件。它根据每行可以直接转换为 c 的程度,以不同的黄色阴影突出显示您的代码。它使捕捉像这样微妙的东西变得容易得多。
是否有一种简单的方法可以像在 C 语言中使用 Cython 对无符号整数进行左移和减法运算?
例如:
def left_shift(unsigned int x, unsigned int shift):
return x << shift
def main():
print left_shift(0xffffffff, 4)
print left_shift(0xffffffff, 8)
print left_shift(0xffffffff, 12)
我希望这会打印
的十进制等价物0xfffffff0
0xffffff00
0xfffff000
这就是我得到的。
4294967280
4294967040
4294963200
但是,如果我尝试做一些更复杂的事情,例如在大输入上使用 Jenkins 的哈希函数之一,这就是我得到的:
def hash_fcn1(unsigned int key):
key = (key ^ 0xdeadbeef) + (key << 4)
key = key ^ (key >> 10)
key = key + (key << 7)
key = key ^ (key >> 13)
return key
hash_fcn1(0xffffffff)
File "./hash_fcn_test.py", line 94, in <module>
main()
File "./hash_fcn_test.py", line 60, in main
print hash_fcn1(0xffffffff)
File "hash_fcns.pyx", line 6, in hash_fcns.hash_fcn1 (/home/medusa/.pyxbld/temp.linux-x86_64-2.7/pyrex/hash_fcns.c:854)
key = (key ^ 0xdeadbeef) + (key << 4)
**OverflowError: value too large to convert to unsigned int**
当计算结果为负数时,会出现类似的问题。有没有办法解决这些问题?我希望计算的行为与在 C 中的行为一样。这个要求是不是太过分了?我在网上搜索了一下,似乎常见的做法只是 按位和 (&) 每个结果 MAX_INT , 但这是非常沉重的。
是否只有我可以在 Cython 编译器或其他地方设置的标志?
我相信,cython 的算术类型取决于所操作的数字类型。我相信您的代码中的问题出在这一行 key = (key ^ 0xdeadbeef) + (key << 4)
。 Cython 将此行翻译为:
__pyx_t_1 = __Pyx_PyInt_From_unsigned_int(__pyx_v_key); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_2 = PyNumber_Xor(__pyx_t_1, __pyx_int_3735928559); if (unlikely(!__pyx_t_2)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_2);
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_1 = __Pyx_PyInt_From_long((__pyx_v_key << 4)); if (unlikely(!__pyx_t_1)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_1);
__pyx_t_3 = PyNumber_Add(__pyx_t_2, __pyx_t_1); if (unlikely(!__pyx_t_3)) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_GOTREF(__pyx_t_3);
__Pyx_DECREF(__pyx_t_2); __pyx_t_2 = 0;
__Pyx_DECREF(__pyx_t_1); __pyx_t_1 = 0;
__pyx_t_4 = __Pyx_PyInt_As_unsigned_int(__pyx_t_3); if (unlikely((__pyx_t_4 == (unsigned int)-1) && PyErr_Occurred())) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 13; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
__Pyx_DECREF(__pyx_t_3); __pyx_t_3 = 0;
__pyx_v_key = __pyx_t_4;
您可能想要的是这个 key = (key ^ <unsigned int> 0xdeadbeef) + (key << 4)
,它被翻译成:
__pyx_v_key = ((__pyx_v_key ^ ((unsigned int)0xdeadbeef)) + (__pyx_v_key << 4));
大不同吧:)。您可能会发现这里需要显式转换令人惊讶,但我认为这是有道理的。在 cython 中,一切行为都与在 pytyhon 中一样,除非明确告诉你做一些不同的事情。这里 cython 将 0xdeadbeef
视为 python int 类型,除非您明确地将其强制转换或将其分配给类型化变量。
如果您还没有使用它,我强烈建议您使用 cython -a
并查看创建的 html 文件。它根据每行可以直接转换为 c 的程度,以不同的黄色阴影突出显示您的代码。它使捕捉像这样微妙的东西变得容易得多。