我有一个浮点数dtype=np.float32
的numpy数组phase
,我把它转换成整数out
,dtype=np.uint8
,因为速度是个问题,所以应该就地转换。
我使用以前学员的代码,但代码无法正常工作
phase = np.arange(0, 4, dtype=np.float32).reshape(2, 2)
out = np.empty((2, 2), dtype=np.uint8)
# Prepare the 2pi -> integer conversion factor and convert.
factor = -(256 / 2 / np.pi)
phase *= factor
print("array phase with dtype float \n ", phase)
# There is some randomness involved in casting positive floats to integers.
# Avoid this by going all negative.
maximum = np.amax(phase)
if maximum >= 0:
toshift = 256 * 2 * np.ceil(maximum / 256)
phase -= toshift
# Copy and cast the data to the output
np.copyto(out, phase, casting="unsafe")
print("phase array dtype unsigned integer", out)
# This part (along with the choice of type), implements modulo much faster than np.mod().
bw = int(256 - 1)
np.bitwise_and(out, bw, out=out)
print("array module bit depth \n", out)
输出为
array phase with dtype float
[[ -0. -162.97466]
[-325.9493 -488.92395]]
phase array dtype unsigned integer [[ 0 94]
[187 24]]
array module bit depth
[[ 0 94]
[187 24]]
执行此程序会产生我无法理解的结果:
1.例如,为什么-162Map到94?
1.我知道标记casting=unsafe
,但它是就地转换所必需的。
1.我也意识到300 > 256
和np.uint8
数据类型太小了,我想我应该把它增加到np.uint16
?
1.为什么在将正浮点数强制转换为整数时会涉及一些随机性?
我也试过np.astype(np.uint8)
,但结果同样令人失望。
1条答案
按热度按时间lc8prwob1#
由于速度是一个问题,这应该就地进行。
就地操作并不总是需要更快。这取决于目标平台和Numpy的编译方式(需要考虑很多底层影响)。尽管它们通常不会更慢。在某些情况下重用缓冲区就足够了(以避免页面错误)。您是否 * 剖析 * 了您的代码并发现这是一个 * 瓶颈 *?
例如,为什么-162Map到94?
这是因为目标类型的范围(包括0..255)不支持数字-162,实际上也不支持任何负数,因为它是一个8位的无符号整数。
256-162=94
。也就是说,AFAIK,这样做会导致一个 * 未定义的行为 。结果从一个平台到另一个平台可能会改变(实际上是基于过去的Numpy问题)。因此,我强烈建议使用一个更大的类型或更改您的代码,以便值适合目标输出类型范围。我知道标志铸造=不安全,但它需要就地转换。
casting=unsafe
非常明确,它的基本意思是:" 我确切地知道我在做什么,并接受风险和后果 *"。使用它的风险自担;)。我也注意到300〉256,因此np.uint8数据类型太小了,我想我应该把它增加到np.uint16?
因为数字是负数,你应该用
np.int16
来代替。除了这个,是的,这是个好主意。为什么在将正浮点数强制转换为整数时会涉及一些随机性?
这并不是真正的随机,这种操作是确定性的,但结果取决于目标平台和输入的数字(也可能取决于处理器针对特定目标平台的低级状态),实际上,只要输入的数字在目标范围内,并且没有NaN、+Inf、-Inf值等特殊数字,就可以了。
我也尝试过np.astype(np.uint8),但结果同样令人失望。
这是正常的。问题是相同的,在两种情况下都调用了相同的转换函数。
注意,除了
np.bitwise_and(out, bw, out=out)
之外,你所做的操作实际上并不是一个就地操作。也就是说,它对np.uint8
类型是无用的,因为范围被限制在255以内。实现模运算比np.mod()快得多
这对于正数是正确的,但是对于负数不是。对于负数,这取决于目标平台上的整数的底层表示。这对于使用C1表示的处理器不起作用。也就是说,现在所有的主流处理器都使用C2表示。