优化整数和浮点乘法

时间:2017-03-27 13:17:00

标签: c++ c floating-point

我正在尝试优化以下操作,其中我有大量无符号短输入,需要按某个因子按比例缩小。有没有办法优化它以不使用浮点运算

unsigned short val = 65523U;
val = val * 0.943;

注意

我将在浮点运算成本高昂的DSP上运行以上

5 个答案:

答案 0 :(得分:8)

最简单的方法是使用可以保存结果的32位类型:

uint16_t val = 65523U;
val = (uint_fast32_t)val * 943 / 1000;

或者如果你想要更多类型的正确性和可移植性,同时允许编译器为任务使用最好的整数类型:

#include <stdint.h>

uint_fast16_t val = UINT16_C(65523);
val = (uint_fast16_t) ( (uint_fast32_t)val * (uint_fast32_t)943 / (uint_fast32_t)1000 );

答案 1 :(得分:8)

您可以乘以整数近似值0.943 * 2 ^ 16,然后除以2 ^ 16,您的编译器应将其转换为右移。假设16位短路和至少32位整数:

val = ((unsigned)val * 61800) / 65536;

根据您的具体要求,您可以通过四舍五入到最接近的整数来获得更准确的结果:

val = ((unsigned)val * 61800 + 32768) / 65536;

任何其他两种力量都可行。在64位平台上,您可以使用2 ^ 48来获得更高的精度。

答案 2 :(得分:2)

多重/分裂的事情是好的。但更好的是你可以避免分歧。

unisgned short的范围为0 ... 65535.

CPU中的所有数学计算都在内部处理为32位数。但是在计算之后它们会被抛回到16位。如果您将短数乘以大数,则需要避免这种情况。输出将很短,导致它截断该值。所以我把演员阵容展示出去了,并确保编译器没有额外的类型转换。

unsigned short val = 65523U;

const unsigned int mult = 65536 * 0.943; // expressed as a fraction of 2^16

unsigned short output = (unsigned short)(((unsigned int)val * mult) >> 16));

所以这会将值转换为32位无符号整数(以保证对类型的控制),根据原始分数将其乘以最多2 ^ 16,然后将其右移16以将其重新置于正确的位置规模。

答案 3 :(得分:1)

您可以乘以943然后除以1000。你保存一个浮点除法(但是你要做乘法+一个欧几里德除法)。

unsigned short val = 65523U;
val = (val*943UL)/1000;

我得到:61788

只要intvar*943容量范围内(unsigned long可用于扩展限制,

就可以工作(即使在unsigned long long为16位宽的系统上)更进一步)。

您可以乘以943然后除以1000。你保存一个浮点除法(但是你要做乘法+一个欧几里德除法)。

unsigned short val = 65523U;
val = (val*943UL)/1000;

我得到:61788

只要intvar*943容量范围内(unsigned long可用于扩展限制,

就可以工作(即使在unsigned long long为16位宽的系统上)更进一步)。

编辑:你甚至可以避免除法计算比率乘以2的幂,我选择了16:

所以.943*(1<<16) 61800.448

你可以做一次乘法和一次换班操作(非常快)。此时使用unsigned long long会更好,因为中间结果会变得非常大:

val = (val*61800UL)>>16;

获得大致相同的结果:61787。使用61801即可获得61788

答案 4 :(得分:1)

使用32位int或更高版本的平台,使用

int val = 65523U;
val = val * 943 / 1000;

很难被击败。通过更改系数将截断转换为德语舍入。如果您的系统有一个16位int,那么您可以使用long(请注意,乘以943并除以1000将在long算术中进行),但解决方案需要分析

首先除以1000会导致截断问题;需要更大的类型来容纳更大的值。