高效的字节浮点乘法

Slo*_*ton 2 python algorithm python-3.x

在输入上,我有一个有符号的字节数组barr(通常是小尾数,但这可能并不重要)和一个f要相乘的浮点数barr

我的方法是转换barr为整数val(使用int.from_bytes函数),将其相乘,执行溢出检查并val在需要时“裁剪”相乘,然后将其转换回字节数组。

def multiply(barr, f):
        val = int.from_bytes(barr, byteorder='little', signed=True)
        val *= f
        val = int (val)
        val = cropInt(val, bitLen = barr.__len__()*8)
        barr = val.to_bytes(barr.__len__(), byteorder='little', signed=True)
        return barr

def cropInt(integer, bitLen, signed = True):
        maxValue = (2**(bitLen-1)-1) if signed else (2**(bitLen)-1)
        minValue = -maxValue-1 if signed else 0
        if integer > maxValue:
            integer = maxValue
        if integer < minValue:
            integer = minValue
        return integer
Run Code Online (Sandbox Code Playgroud)

然而,当处理大量数据时,这个过程非常慢。有没有更好、更有效的方法来做到这一点?

jsb*_*eno 5

纯Python对于任何数字计算都是相当无效的——因为由于每个数字都被视为一个对象,所以每个操作都涉及很多“幕后”步骤。

另一方面,如果您使用适当的第三方库集,Python 可以非常有效地进行数值计算。

在您的情况下,sice 性能很重要,您可以使用NumPy- 用于数字处理的事实上的 Python 包。

有了它,转换、乘法和重转换将在本机代码中一次完成(并且在比我了解更好的 NumPy 之后,可能需要更少的步骤) - 并且应该使您的速度提高 3-4 个数量级对于此任务:

import numpy as np
def multiply(all_bytes, f, bitlen, signed=True): 

    # Works for 8, 16, 32 and 64 bit integers:
    dtype = "%sint%d" % ("" if signed else "",   bitlen)
    max_value = 2 ** (bitlen- (1 if signed else 0)) - 1

    input_data = np.frombuffer(all_bytes, dtype=dtype)
    processed = np.clip(input_data * f, 0, max_value)
    return bytes(processed.astype(dtype))
Run Code Online (Sandbox Code Playgroud)

请注意,此示例一次获取所有字节数据,而不是在传递给原始“乘法”函数时一次获取一个字节数据。因此,您还必须向其传递整数的大小(以位为单位)。

该行dtype = "%sint%d" % ("" if signed else "", bitlen)创建数据类型名称,由 NumPy 根据传入的位数使用。由于名称只是一个字符串,因此它会插入一个添加或不添加“u”前缀的字符串,具体取决于无符号的数据类型,并将位数放在末尾。NumPy 数据类型可以在以下位置检查:https://docs.scipy.org/doc/numpy/user/basics.types.html

使用 500000 个 8 位有符号整数的数组运行,我得到以下计时:

在[99]中:%time y = numpy_multiply(data, 1.7, 8) CPU时间:用户3.01毫秒,系统:4.96毫秒,总计:7.97毫秒 墙上时间:7.38毫秒

在 [100] 中: %time x = original_multiply(data, 1.7, 8) CPU 时间:用户 11.3 秒,系统:1.86 毫秒,总计:11.3 秒 墙上时间:11.3 秒

(这是在修改你的函数以一次对所有字节进行操作之后) - 加速了 1500 倍,正如我在初稿中所说的那样。