C++ 优化整数和浮点乘法

C++ 优化整数和浮点乘法,c++,c,floating-point,C++,C,Floating Point,我正在尝试优化以下操作,其中我有大量无符号短输入,需要按一定比例缩小。有没有办法优化它,使其不使用浮点运算 unsigned short val = 65523U; val = val * 0.943; 注意 我将在DSP上运行上述操作,其中浮点操作成本很高您可以乘以943,然后除以1000。您可以保存一个浮点除法(但您可以执行乘法+欧几里得除法) 我得到:61788 只要var*943在unsigned long容量内(unsigned long可用于进一步扩展限制),它就可以工作(即使在i

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

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


我将在DSP上运行上述操作,其中浮点操作成本很高

您可以乘以
943
,然后除以
1000
。您可以保存一个浮点除法(但您可以执行乘法+欧几里得除法)

我得到:
61788

只要
var*943
unsigned long
容量内(
unsigned long
可用于进一步扩展限制),它就可以工作(即使在
int
为16位宽的系统上)


你可以乘
943
,然后除以
1000
。您可以保存一个浮点除法(但您可以执行乘法+欧几里得除法)

我得到:
61788

只要
var*943
unsigned long
容量内(
unsigned long
可用于进一步扩展限制),它就可以工作(即使在
int
为16位宽的系统上)

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


因此
.943*(1平台使用32位
int
或更高,使用

int val = 65523U;
val = val * 943 / 1000;
很难击败。通过改变系数将截断转换为德文四舍五入。如果您的系统具有16位
int
,则可以使用
long
(请注意,943的乘法和1000的除法将在
long
算术中进行),但解决方案需要分析


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

最简单的方法是只使用一个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 );
#包括
uint_fast16_t val=UINT16_C(65523);
val=(uint_fast16_t)((uint_fast32_t)val*(uint_fast32_t)943/(uint_fast32_t)1000);

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

val = ((unsigned)val * 61800) / 65536;
根据您的具体要求,您可以通过四舍五入到最接近的整数来获得更精确的结果:

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

任何其他的二次幂都可以。在64位平台上,可以使用2^48来获得更高的精度。

mult/divide功能很好。但更好的是,可以避免使用二次幂

未签名短款的范围为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位无符号int(以保证对类型的控制),在原始分数的基础上将其乘以2^16,然后将其右移16以将其恢复到正确的比例。

您可以使用。这通常用于没有高性能浮点功能的系统中。为什么需要对其进行优化?您是否对乘法进行了基准测试和测量,以确定乘法是否会变慢?是否会变慢在?您多久做一次?目标平台是什么?如果内存不是问题,查找表可能会有所帮助。(预先计算所有值并存储在数组中)。我理解。但这是关键的、非常相关的信息,应该是问题的一部分。下次请将这些信息包括在问题主体中。如果这是针对一些半模糊的DSP,那么您肯定应该使用
stdint.h
类型。在编写专业嵌入式系统时,它们是强制性的无论如何,固件。@nwellnhof:谢谢。(如果我每次都有一美元的话。)现在都修好了。想当一名代码审查员吗?你不能用int来存储int为-32767到32768的结果,你是在假设这是一个32位系统吗?我确实在假设;我想我已经说清楚了在我的回答中,为了清楚起见,我添加了一个关于论点提升的注释)。具有16位
int
的平台需要单独定制的解决方案。当心具有16位int的系统。你说得对!使用
long
编辑。也许
unsigned long-long
有点过头了?如果可以的话,我想知道使用
int
是否更好。我看不出
val
的演员阵容便宜。@Jean-Françoisfare有可能实现这种避免除法吗?我不除法,我在计算了正确的乘法值后移动了16步。但另一个人同时回答了同样的问题……因为它被转换回16位,所以我认为增加的精度将全部丢失。@JasonLang是的,但使用2^48的比例因子可以更精确地表示因子0.943。只有表示。但是这种表示丢失了,我不确定增加的分辨率是否会转化为结果中的一个位改变,你看,输出是0。。。65535乘以0.943最多可以使输出表示中65536中的1不同。第17位是使用48位表示的额外精度的最高位,其值为1/131072。请注意,此代码在8/16位系统上不起作用<代码>65523*61800=48568
以此类推。OP使用的DSP很可能是16位。虽然这确实可以节省一些执行时间,
val = ((unsigned)val * 61800) / 65536;
val = ((unsigned)val * 61800 + 32768) / 65536;
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));