这与流行的问题有关,为什么GCC不优化a*a*a*a*a*a到(a*a*a)*(a*a*a)?
对于像Haskell这样的惰性函数式编程语言,编译器将如何处理这种情况?
我在C中创建了一个双倍数据类型.我尝试-Ofast
使用GCC并发现它显着更快(例如1.5秒-O3
和0.3 秒-Ofast
)但结果是假的.我追了这个-fassociative-math
.我很惊讶这不起作用,因为我明确定义了操作的关联性.例如,在下面的代码中,我将括号括起来.
static inline doublefloat two_sum(const float a, const float b) {
float s = a + b;
float v = s - a;
float e = (a - (s - v)) + (b - v);
return (doublefloat){s, e};
}
Run Code Online (Sandbox Code Playgroud)
所以我不希望海湾合作委员会改变(a - (s - v))
,((a + v) - s)
甚至改变-fassociative-math
.那么为什么结果如此错误使用-fassociative-math
(并且速度更快)?
我尝试/fp:fast
使用MSVC(在将我的代码转换为C++之后)并且结果是正确的,但它并不快/fp:precise
.
从GCC手册中了解到-fassociative-math
它的状态
允许在一系列浮点运算中重新关联操作数.这可能会改变计算结果,从而违反了ISO C和C++语言标准.注意:重新排序可能会改变零的符号以及忽略NaN并禁止或创建下溢或溢出(因此不能用于依赖于舍入行为的代码,如"(x + 2 ^ …
我尝试使用计算列表的平均值Parallel.For()
.我决定反对它,因为它比简单的串行版本慢大约四倍.然而我很感兴趣的是它并没有产生与序列结果完全相同的结果,我认为了解原因是有益的.
我的代码是:
public static double Mean(this IList<double> list)
{
double sum = 0.0;
Parallel.For(0, list.Count, i => {
double initialSum;
double incrementedSum;
SpinWait spinWait = new SpinWait();
// Try incrementing the sum until the loop finds the initial sum unchanged so that it can safely replace it with the incremented one.
while (true) {
initialSum = sum;
incrementedSum = initialSum + list[i];
if (initialSum == Interlocked.CompareExchange(ref sum, incrementedSum, initialSum)) break;
spinWait.SpinOnce();
}
});
return sum / list.Count;
} …
Run Code Online (Sandbox Code Playgroud) 我做了一个简单的性能比较,侧重于使用C#的浮点运算,针对带有Windows 10 IoT的Raspberry Pi 3 Model 2,我将它与Intel Core i7-6500U CPU @ 2.50GHz进行了比较.
Raspberry Pi 3 Model B V1.2 - 测试结果 - 图表
英特尔酷睿i7-6500U CPU @ 2.50GHz - x64测试结果 - 图表
英特尔酷睿i7 仅比Raspberry Pi 3 快十二倍(x64)! - 根据那些测试.
准确度为11.67,并计算每个平台在这些测试中实现的最佳性能.两个平台在并行运行的四个线程中实现了最佳性能(非常简单,独立的计算).
问题:测量和比较这些平台的计算性能的正确方法是什么?目的是比较优化算法,机器学习算法,统计分析等领域的计算性能.因此,我的重点是浮点运算.
有一些基准测试(如MWIPS)和MIPS或FLOPS等测量.但我没有找到一种方法来比较不同的CPU平台的计算能力.
我找到了Roy Longbottom的一个比较(谷歌"Roy Longbottom的Raspberry Pi,Pi 2和Pi 3基准" - 我不能在这里发布更多链接)但根据他的基准测试,Raspberry Pi 3的速度只比英特尔酷睿i7快4倍(x64)建筑,MFLOPS比较).与我的结果非常不同.
以下是我执行的测试的详细信息:
测试是围绕应该迭代执行的简单操作构建的:
private static float SingleAverageCalc(float seed, long nTimes)
{
float x1 = seed, x2 = …
Run Code Online (Sandbox Code Playgroud) c# ×2
c ×1
compilation ×1
gcc ×1
haskell ×1
intel ×1
interlocked ×1
mean ×1
optimization ×1
precision ×1
raspberry-pi ×1