C语言 Double vs Float vs _Float16(运行时间)



我有一个简单的C语言问题。我正在使用C中的_Float16实现半精度软件(我的mac基于ARM),但运行时间并不比单精度或双精度软件快。我用一个非常简单的代码测试了半,单,双。二分之一的速度比二分之一或二分之一慢。此外,single和double类似。

typedef double FP;
// double - double precision
// float - single precision
// _Float16 - half precision
int main(int argc, const char * argv[]) {
float time;
clock_t start1, end1;
start1 = clock();
int i;
FP temp = 0;
for(i = 0; i< 100; i++){
temp = temp + i;
}
end1 = clock();
time = (double)(end1 - start1)/CLOCKS_PER_SEC;
printf("[] %.16fn", time);
return 0;
}

在我的期望中,半精度比单精度或双精度快得多。如何检查半精度比双精度快,浮点比双精度快?

Please Help Me.

关于浮点数有一个非常令人惊讶的事实:

单精度(float)算法不一定比双精度更快。

这是怎么回事?浮点运算是很难的,所以用两倍的精度来做至少是两倍的困难,而且必须花费更长的时间,对吧?

嗯,没有。是的,以更高的精度进行计算需要更多的工作,但只要工作是由专用硬件(通过某种浮点单元或FPU)完成的,一切都可能并行地进行。实现双倍精度的难度可能是原来的两倍,因此也可能需要两倍的晶体管,但这并不需要更长的时间。

实际上,如果您的系统的FPU同时支持单精度和双精度浮点数,一个好的规则是:总是使用double。这个规则的原因是,float型往往是不够准确的。因此,如果您总是使用double,您将经常避免数值不准确(如果您使用float,这将杀死您),但它不会更慢。

现在,到目前为止,我所说的所有内容都假设您的FPU在硬件上支持您所关心的类型。如果有一个浮点类型在硬件中不支持,如果它必须在软件中模拟,它显然会变慢,通常要慢得多。至少有三个方面会出现这种效果:
  • 如果您使用的是微控制器,根本没有FPU,那么所有浮点数在软件中实现是很常见的,并且速度很慢。(我认为双精度甚至更慢也很常见,这意味着float在那里可能是有利的。)
  • 如果你使用非标准或低于标准的类型,因为这个原因是在软件中实现的,它显然会变慢。特别是:我所熟悉的FPU不支持半精度(16位)浮点类型,所以是的,如果它明显比常规floatdouble,那就不足为奇了。
  • 一些GPU支持单精度或半精度,但不支持双精度。

我已经将代码的相关部分提取到c++中,因此可以轻松地为每种类型实例化:

template<typename T>
T calc() {
T sum = 0;
for (int i = 0; i < 100; i++) {
sum += i;
}
return sum;
}

在Clang中使用优化(-O3)编译此代码并查看godbolt上的程序集清单表明:

  • double版本的内循环指令数最少(4)
  • float版本在内部循环中有5条指令,看起来基本上与double version
  • 相当
  • _Float16版本在内循环中有9条指令,因此可能是最慢的。额外的指令fcvtfloat16和float32格式之间的转换。

注意,计数指令只是性能的粗略指导!例:有些指令需要多个周期才能执行,而流水线执行意味着多个指令可以并行执行。

Clang的语言扩展文档建议在ARMv8.2a上支持_Float16,而M1似乎是v8.4,所以它可能也支持这一点。我不知道如何在Godbolt中启用这个,抱歉!

我将使用clock_gettime(CLOCK_MONOTONIC)在Linux下高精度(即纳秒)计时。OSX似乎没有提供这个功能,但是OSX上的单调时钟似乎是可用的。

最新更新