无符号整数Cython中的C风格算法

时间:2015-11-18 23:10:33

标签: cython bitwise-operators bit-shift integer-arithmetic

是否有一种简单的方法可以使左移和减法像使用Cython中的无符号整数中的C一样工作?

例如:

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中的行为一样。这要求得太多了吗?我已经在网上搜索了,看起来常见的做法只是 按位和(&amp;) 每个结果都有MAX_INT,但这非常繁重。 / p>

我是否可以在Cython编译器或其他地方设置一个标志?

1 个答案:

答案 0 :(得分:3)

我相信,如果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的方式。它可以更容易地捕捉这样微妙的事情。