np.around(x).astype(int)
and x.astype(int)
不产生相同的值。前几轮均匀(与((x*x>=0+0.5) + (x*x<0-0.5)).astype(int)
)而后者四舍五入为零。然而,
y = np.trunc(x).astype(int)
z = x.astype(int)
shows y==z
但计算y
速度要慢得多。所以这是np.trunc
and np.around
缓慢的函数。
In [165]: x.dtype
Out[165]: dtype('float64')
In [168]: y.dtype
Out[168]: dtype('int64')
So np.trunc(x)
从 double 到 double 向零舍入。然后astype(int)
必须将 double 转换为 int64。
在内部,我不知道 python 或 numpy 在做什么,但我知道如何在 C 中执行此操作。让我们讨论一些硬件。使用 SSE4.1,可以使用以下命令从双精度到双精度进行 round、floor、ceil 和 trunc:
_mm_round_pd(a, 0); //round: round even
_mm_round_pd(a, 1); //floor: round towards minus infinity
_mm_round_pd(a, 2); //ceil: round towards positive infinity
_mm_round_pd(a, 3); //trunc: round towards zero
但 numpy 也需要支持没有 SSE4.1 的系统,因此它必须在没有 SSE4.1 的情况下以及有 SSE4.1 的情况下构建,然后使用调度程序。
但是,在 AVX512 之前,使用 SSE/AVX 从 double 直接转换为 int64 的效率并不高。然而,仅使用 SSE2 就可以有效地将 double 舍入为 int32:
_mm_cvtpd_epi32(a); //round double to int32 then expand to int64
_mm_cvttpd_epi32(a); //trunc double to int32 then expand to int64
这些将两个 double 转换为两个 int64。
在您的情况下,这可以正常工作,因为范围肯定在 int32 内。但除非 python 知道 int32 适合的范围,否则它不能假设这一点,因此它必须舍入或截断为 int64,这很慢。另外,无论如何,numpy 都必须构建支持 SSE2 才能做到这一点。
但也许您可以一开始就使用单个浮点数组。在这种情况下你可以这样做:
_mm_cvtps_epi32(a); //round single to int32
_mm_cvttps_epi32(a) //trunc single to int32
这些将四个单数转换为四个 int32。
因此,为了回答您的问题,SSE2 可以有效地从 double 舍入或截断为 int32。 AVX512 将能够有效地从 double 舍入或截断为 int64 以及使用_mm512_cvtpd_epi64(a)
or _mm512_cvttpd_epi64(a)
。 SSE4.1可以有效地从浮动到浮动或双倍到双倍进行舍入/截断/下限/上限。