- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我将一些使用 NumPy 的代码移植到 Cython 中以获得一些性能提升。我取得了相当大的进步,但我遇到了一个问题。
Cython 得到的结果与Python 得到的结果不同。我不知道为什么会这样,所以我决定查看将什么推送到 Cython 模块。
在到达 Cython 之前,数据如下所示:
azimuth = 0.000349065850399
rawDistance = [ 2.682 7.234 2.8 7.2 2.912 7.19 3.048 7.174 3.182 7.162
3.33 7.164 3.506 7.158 3.706 7.154 3.942 7.158 4.192 7.158
4.476 7.186 4.826 7.19 5.218 7.204 5.704 7.224 6.256 7.248
6.97 7.284]
intensity = [19 34 25 28 26 48 21 56 21 60 31 49 24 37 26 37 34 37 23 84 15 59 23 45
18 47 20 55 18 36 15 39]
一旦它进入 Cython,同样的数据看起来像:
azimuth = 0.000349065850399
rawDistance = [2.686, 7.23, 2.7960000000000003, 7.204, 2.91, 7.188, 3.044, 7.174, 3.19,
7.16, 3.3280000000000003, 7.16, 3.5, 7.154, 3.704, 7.144, 3.936, 7.158,
4.196, 7.156000000000001, 4.478, 7.19, 4.8260000000000005, 7.192, 5.22,
7.204, 5.708, 7.22, 6.256, 7.252, 6.97, 7.282]
intensity = [19, 34, 27, 28, 26, 48, 22, 52, 21, 60, 31, 49, 24, 37, 28, 34, 32, 37,
23, 84, 15, 59, 23, 45, 18, 47, 20, 58, 18, 36, 15, 36]
这就解释了为什么结果与纯Python方法计算的结果不完全一样。
这是信息被传输到的 Cython 模块:
from libc.math cimport sin, cos
import numpy as np
cimport numpy as np
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.nonecheck(False)
def calculateXYZ(list frames, double[:] cosVertCorrection, double[:] sinVertCorrection):
cdef long numberFrames = len(frames)
cdef long i, j, k, numberBlocks
cdef list finalResults = []
cdef list intensities = []
cdef list frameXYZ = []
cdef double azimuth, xy, x, y, z, sinRotational, cosRotational
cdef double[32] rawDistance
cdef int[32] intensity
cdef double[:] tempX
cdef double[:] tempY
cdef double[:] tempZ
cdef int positionsFilled = 0
for i in xrange(numberFrames):
numberBlocks = len(frames[i])
tempX = np.zeros(numberBlocks * 32, dtype=np.double)
tempY = np.zeros(numberBlocks * 32, dtype=np.double)
tempZ = np.zeros(numberBlocks * 32, dtype=np.double)
frameXYZ = [[] for i in range(3)]
positionsFilled = 0
for j in xrange(numberBlocks):
# This is where I tested for the data in Cython
# This is the information that is different.
# It is reading from what was passed to it from python.
azimuth = frames[i][j][0]
rawDistance = frames[i][j][1]
intensity = frames[i][j][2]
sinRotational, cosRotational = sin(azimuth), cos(azimuth)
for k in xrange(32):
xy = rawDistance[k] * cosVertCorrection[k]
x, y = xy * sinRotational, xy * cosRotational
z = rawDistance[k] * sinVertCorrection[k]
if x != 0 or y != 0 or z != 0:
tempX[positionsFilled] = x
tempY[positionsFilled] = y
tempZ[positionsFilled] = z
intensities.append(intensity[k])
positionsFilled = positionsFilled + 1
frameXYZ[0].append(np.asarray(tempX[0:positionsFilled].copy()).tolist())
frameXYZ[1].append(np.asarray(tempY[0:positionsFilled].copy()).tolist())
frameXYZ[2].append(np.asarray(tempZ[0:positionsFilled].copy()).tolist())
finalResults.append(frameXYZ)
return finalResults, intensities
这是它的纯 Python 版本:
documentXYZ = []
intensities = []
# I tested to see what the original data was in here adding prints
for frame in frames:
frameXYZ = [[] for i in range(3)]
frameX, frameY, frameZ = [], [], []
for block in frame:
sinRotational, cosRotational = np.math.sin(block[0]), np.math.cos(block[0])
rawDistance, intensity = np.array(block[1]), np.array(block[2])
xy = np.multiply(rawDistance, cosVertCorrection)
x, y, z = np.multiply(xy, sinRotational), np.multiply(xy, cosRotational), np.multiply(rawDistance, sinVertCorrection)
maskXYZ = np.logical_and(np.logical_and(x, x != 0), np.logical_and(y, y != 0), np.logical_and(z, z != 0))
frameX += x[maskXYZ].tolist()
frameY += y[maskXYZ].tolist()
frameZ += z[maskXYZ].tolist()
intensities += intensity[maskXYZ].tolist()
frameXYZ[0].append(frameX), frameXYZ[1].append(frameY), frameXYZ[2].append(frameZ)
documentXYZ.append(frameXYZ)
我知道浮点值的精度可能存在差异(尽管我认为不应该存在,因为我在所有结构中都使用了 doubles
),但我不明白为什么作为整数的 intensity
值也被更改。我希望精度与 Python 中的精度相同。
关于如何改进这个的任何想法?
谢谢。
最佳答案
解决问题的前两个步骤是:
确定 NumPy 在您的平台上使用的特定整数类型(例如 int32
、int64
...),例如检查 dtype
整数数组的属性或其值之一。
确定int
的位宽在您的平台上使用您选择的 C 实现。通常它是 32 位,但并非总是如此(例如使用 sizeof
检查)。
一旦了解了这两个细节,您就可以确定以何种方式进行普通 (C) int
无法匹配 NumPy 一直使用的整数精度。一个常见的猜测是 NumPy 使用的是 int64
但在 C 中你使用的是 int
这可能是 int32
为您的平台/实现。另一个常见的情况是 NumPy 使用无符号整数,而在 C 中 int
将被签名,即使具有相同的位数也会导致不同的表示。
在Cython中可以很方便的引用定宽整数,至少有以下三种方式:
自从您使用了cimport numpy as np
可以引用NumPy的定宽整数类型,比如np.int64_t
或 np.uint8_t
. “_t”类型定义在 NumPy 的 Cython 支持中可用。
您可以尝试从您的 C 实现和平台中找出标准类型名称,例如 cython.longlong
对于 64 位整数或 cython.uchar
对于一个无符号的 8 位整数,它恰好对应于整数的正确位数和正确的符号性,以匹配 NumPy 使用的任何类型的精度和符号性。
也可以从C标准库导入,比如from libc.stdint import int64_t, uint8_t
如果您更喜欢将 C 的标准头文件用于指定大小的固定宽度整数。
假设您选择了合适的整数类型,然后您可以声明您的 intensity
具有正确类型的数组,例如以下任何一种,具体取决于您选择用于表达正确整数类型的方法:
cdef np.uint8_t[32] intensity # If using NumPy integer types
cdef uint8_t[32] intensity # If importing from libc.stdint
cdef cython.uchar[32] intensity # If using Cython integer types
最后一点,最好记住常规 Python 整数是无限精度的,所以如果您设法获得 int
的 NumPy 数组类型(不是 C int
,而是 Python int
),在 Cython 中工作时,您必须决定不同的固定精度表示,或者使用包含 Python int
的数组或类型化内存 View 。类型(这通常违背了首先使用 Cython 的目的)。
关于python - 一旦数据进入 Cython 模块,精度就会丢失/更改,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37625628/
c 不做边界检查。那么cython是如何检查是否编译成c的呢? %%cython --annotate cimport cython @cython.boundscheck(True) cpdef m
可以直接声明用于 Cython 构造函数? 据我了解,这是可能的: # Cython cdef int[3] li = [1, 2, 3] # C++ int[3] li = {1, 2, 3} 但
所以,如果你有一个头文件。 %%file test.h struct mystruct{ int i; int j; }; 然后你将它包装在 Cython 中: cdef extern fr
我正在构建一个独立于平台的 cython 项目,我想根据正在使用的编译器传递编译器参数。我可以猜测基于平台的编译器,或者假设它与用于 Python 的编译器相同,但不能保证匹配。通常我注入(injec
我使用诗歌构建我的 cython 包。我在所有函数和类中都有 NumPy 风格的文档字符串。我现在要做的是添加 Sphinx 自动文档并发布在 Read the Docs。 我已阅读此主题 How d
赛通 libcpp模块包含 priority_queue 的模板,这很好,除了一件事:我不能通过自定义比较器(或者,至少,我不知道如何)。 我需要这个,因为我需要 priority_queue做一个a
以下代码定义了一个简单的 Cython 函数(为方便起见,使用 Ipython 魔法)。 %load_ext cython %%cython def f(float x, float y=2):
我正在尝试使用 cython 进行复数计算。在示例代码中,我想计算复数的复指数函数。问题是我不知道如何将我的整数乘以虚数单位。python的虚数单位1.0j乘以cython执行时报错。 这是我的代码:
在这里停留在一些基本的 Cython 上 - 在 Cython 中定义字符串数组的规范且有效的方法是什么? 具体来说,我想定义一个定长常量数组char . (请注意,此时我不想引入 NumPy。) 在
是否有可能,如果是,如何确定 Cython 中整数数据类型的大小(以位为单位)? 我正在尝试做这样的事情,以获得整数大小: cdef WORD_BITS = 0 IF sizeof(unsigned
我只是想打印 cython 变量的地址,但我无法绕过错误消息: cdef int myvar print &myvar 抛出 Cannot convert 'int *' to Python obje
我有一个 C 头文件,它在宏中定义了一个函数。我需要从 Cython 调用它。有没有办法在 Cython 中使用宏并使其完全扩展?我已经有了 C 类型的参数。 我尝试像使用函数一样使用 cdef,我认
令人惊讶的是,我似乎找不到通过名称获取结构体元素的单个示例(无论是在网络上还是在 cython 示例中)。 所以我收到了一个指向 C 函数结构体的指针,并且想要一一访问这些元素并将它们重新打包到 py
我尝试围绕 C++ 库编写一个 Cython 包装器 http://primesieve.org/ 它包装了一个函数count。到目前为止,它可以正确安装 python setup.py instal
我正在尝试将 cython 模块 data.pyx 导入另一个 cython 模块 user.pyx。一切都编译得很好,但是当我尝试在 python 模块中调用 user.pyx 时,我收到错误“Im
更新:内存 View 获胜。Cython 使用类型化内存 View :0.0253449 特别感谢 lothario,他指出了几个关键的变化。 荒谬。当然现在的问题是,似乎不能对它们做太多算术(加法和
我有一个使用 memoryview 数组的 cython 模块,即... double[:,:] foo 我想使用多处理并行运行这个模块。但是我得到了错误: PicklingError: Can't
我正在尝试使用 Cython 加速 PEP 484 类型的 python 脚本。我想保持一些语义和可读性。 之前,我有一个 Flags = int def difference(f1: Flags,
这个问题已经有答案了: Collapse multiple submodules to one Cython extension (5 个回答) 已关闭 3 年前。 我在一个包中有多个 .py 文件
我已经能够在我的 .pyx 脚本上使用 cython 在 linux 上创建一个 .so 文件。我也可以成功地在我的 python 解释器上进行导入。 我的问题是如何在不使用 cython 的情况下将
我是一名优秀的程序员,十分优秀!