我有一个简单的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,那么所有浮点数在软件中实现是很常见的,并且速度很慢。(我认为双精度甚至更慢也很常见,这意味着
float
在那里可能是有利的。) - 如果你使用非标准或低于标准的类型,因为这个原因是在软件中实现的,它显然会变慢。特别是:我所熟悉的FPU不支持半精度(16位)浮点类型,所以是的,如果它明显比常规
float
或double
慢,那就不足为奇了。 - 一些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条指令,因此可能是最慢的。额外的指令fcvt
float16和float32格式之间的转换。
注意,计数指令只是性能的粗略指导!例:有些指令需要多个周期才能执行,而流水线执行意味着多个指令可以并行执行。
Clang的语言扩展文档建议在ARMv8.2a上支持_Float16
,而M1似乎是v8.4,所以它可能也支持这一点。我不知道如何在Godbolt中启用这个,抱歉!
我将使用clock_gettime(CLOCK_MONOTONIC)
在Linux下高精度(即纳秒)计时。OSX似乎没有提供这个功能,但是OSX上的单调时钟似乎是可用的。