在我正在编写的软件中,我正在进行数百万乘法或除以2(或2的幂)的值.我真的希望这些值int能够访问bitshift运算符
int a = 1;
int b = a<<24
Run Code Online (Sandbox Code Playgroud)
但是,我不能,而且我必须坚持双打.
我的问题是:由于存在双精度(符号,指数,尾数)的标准表示,是否有一种方法可以与指数一起使用以2的幂来获得快速乘法/除法?
我甚至可以假设位数将被修复(该软件将在总是具有64位长的双倍的机器上工作)
PS:是的,该算法主要只执行这些操作.这是瓶颈(它已经是多线程的).
编辑:或者我完全错了,聪明的编译器已经为我优化了一些东西?
临时结果(用Qt测量时间,矫枉过正,但我不在乎):
#include <QtCore/QCoreApplication>
#include <QtCore/QElapsedTimer>
#include <QtCore/QDebug>
#include <iostream>
#include <math.h>
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
while(true)
{
QElapsedTimer timer;
timer.start();
int n=100000000;
volatile double d=12.4;
volatile double D;
for(unsigned int i=0; i<n; ++i)
{
//D = d*32; // 200 ms
//D = d*(1<<5); // 200 ms
D = ldexp (d,5); // 6000 ms
} …Run Code Online (Sandbox Code Playgroud) 考虑到这个功能,
float mulHalf(float x) {
return x * 0.5f;
}
Run Code Online (Sandbox Code Playgroud)
以下函数与正常输入/输出产生相同的结果。
float mulHalf_opt(float x) {
__m128i e = _mm_set1_epi32(-1 << 23);
__asm__ ("paddd\t%0, %1" : "+x"(x) : "xm"(e));
return x;
}
Run Code Online (Sandbox Code Playgroud)
这是带有 的汇编输出-O3 -ffast-math。
mulHalf:
mulss xmm0, DWORD PTR .LC0[rip]
ret
mulHalf_opt:
paddd xmm0, XMMWORD PTR .LC1[rip]
ret
Run Code Online (Sandbox Code Playgroud)
-ffast-math启用-ffinite-math-only“假设参数和结果不是 NaN 或 +-Infs” [1]。
因此,如果在 的容差下生成更快的代码,则的编译输出可能会更好地与onmulHalf一起使用。paddd-ffast-math-ffast-math
我从Intel Intrinsics Guide中获得了下表。
(MULSS)
Architecture Latency Throughput (CPI)
Skylake 4 0.5 …Run Code Online (Sandbox Code Playgroud) 可疑的代码如下:
float32_t f = someValueFromSomewhere;
f = f * 4;
Run Code Online (Sandbox Code Playgroud)
编译器会优化这个吗?根据C-Standard(如果我理解正确的话),必须将第二个操作数提升为float32_t; 因此,乘法必须使用FPU(或fp仿真)完成.
从理论上讲,只需添加一个立即(可能是溢出检查),就可以在普通硬件寄存器中完成操作.编译器是否允许进行此优化?是否有编译器可以这样做?如果是这样,他们也会认出这个表达
f = f * 4.0f;
Run Code Online (Sandbox Code Playgroud)
这是避免静态代码检查器有关隐式转换的警告所必需的吗?
一些补充:我知道从标准的角度来看两条线都是等价的.但显然编译器可以区分它们.所以问题是在哪个时候允许优化器第一次看到代码(或更好的内部表示).