为了了解if语句与选择性乘法之间的关系,我尝试了下面的代码,发现将结果乘以0而不是失败的if语句(false),并乘以1而不是传递的if语句(true),if语句更慢,如果只有3-4次双精度乘法,计算总是更快。
问题:虽然这种乘法即使在cpu上也更快,但它在GPU(opencl/cuda)上会如何执行?我投票赞成绝对加速。单精度乘法的精度损失如何?我知道不可能总是有1.00000,乘以0.999999。比方说,我不介意第五位的sp精度损失。
这更适合整数,但这至少对浮点值有意义吗?如果float/shalf比doubles更快/更快地相乘,那么这将更快。
结果:
no if: 0.058515741 seconds
if(){}: 0.073415743 seconds
有人能重现类似的结果吗?if(){}是第二个测试,所以JIT不会作弊?
代码:
public static void main(String[] args)
{
boolean[]ifBool=new boolean[10000000];
byte[]ifThen=new byte[10000000];
double []data=new double[10000000];
double []data1=new double[10000000];
double []data2=new double[10000000];
for(int i=0;i<ifThen.length;i++)
{
ifThen[i]=(byte)(0.43+Math.random()); //1 =yes result add, 0= no result add
ifBool[i]=(ifThen[i]==1?true:false);
data[i]=Math.random();
data1[i]=Math.random();
data2[i]=Math.random();
}
long ref=0,end=0;
ref=System.nanoTime();
for(int i=0;i<data.length;i++)
{
// multiplying by zero means no change in data
// multiplying by one means a change in data
double check=(double)ifThen[i]; // some precision error 0.99999 ?
data2[i]+=(data[i]*data1[i])*check; // double checked to be sure
data[i]+=(data2[i]*data1[i])*check; // about adding the result
data1[i]+=(data[i]*data2[i])*check; // or not adding
//(adding the result or adding a zero)
}
end=System.nanoTime();
System.out.println("no if: "+(end-ref)/1000000000.0+" seconds");
ref=System.nanoTime();
for(int i=0;i<data.length;i++)
{
if(ifBool[i]) // conventional approach, easy to read
{
data2[i]+=data[i]*data1[i];
data[i]+=data2[i]*data1[i];
data1[i]+=data[i]*data2[i];
}
}
end=System.nanoTime();
System.out.println("if(){}: "+(end-ref)/1000000000.0+" seconds");
}
CPU为FX8150@4GHz
无法重现结果(仅限CPU)。
原始代码:否,如果:0.11589088秒。if(){}:0.115732277秒。
按相反顺序:if(){}:0.1154809秒。否,如果:0.115531714秒。
多次运行会产生不同的结果,但if/no_if块实际上是奇偶校验的。
你需要一个更详细的基准来得出一些有意义的结论。使用热身,稳定的随机种子,在很多通话中平均。
我也可能(几乎)对java代码的微观管理毫无用处。它只能在特定的硬件和特定的VM版本上工作。VM代码优化现在非常先进,你不会相信它能做什么。请确保执行的代码与你的字节码非常不同。