在 64 位处理器上不使用 double(而是使用 float 代替)有什么好处吗?
Is there any benefit of not using double on a 64bit (and using, say, float instead) processor?
我总是使用 double 来进行计算,但 double 提供的精度远远超出我的需要(或者说是有道理的,考虑到我所做的大部分计算都是从近似值开始的)。
但是由于处理器已经是 64 位的,我不认为使用位数较少的类型会有任何好处。
我是 right/wrong,我将如何优化速度(我知道较小的类型会更有效地使用内存)
这里是测试
#include <cmath>
#include <ctime>
#include <cstdio>
template<typename T>
void creatematrix(int m,int n, T **&M){
M = new T*[m];
T *M_data = new T[m*n];
for(int i=0; i< m; ++i)
{
M[i] = M_data + i * n;
}
}
void main(){
clock_t start,end;
double diffs;
const int N = 4096;
const int rep =8;
float **m1,**m2;
creatematrix(N,N,m1);creatematrix(N,N,m2);
start=clock();
for(int k = 0;k<rep;k++){
for(int i = 0;i<N;i++){
for(int j =0;j<N;j++)
m1[i][j]=sqrt(m1[i][j]*m2[i][j]+0.1586);
}
}
end = clock();
diffs = (end - start)/(double)CLOCKS_PER_SEC;
printf("time = %lf\n",diffs);
delete[] m1[0];
delete[] m1;
delete[] m2[0];
delete[] m2;
getchar();
}
double 和 float 之间没有时间差异,但是当不使用平方根时,float 快两倍。
有几种方法可以提高它们的速度:
- 更快 I/O:您只有一半的位可以在 disk/memory/cache/registers
之间移动
- 通常唯一较慢的运算是平方根和除法。例如,在 Haswell 上,
DIVSS
(浮点除法)需要 7 个时钟周期,而 DIVSD
(双除法)需要 8-14(来源:Agner Fog's tables)。
- 如果您可以利用 SIMD 指令,那么每条指令可以处理两倍的数量(即在 128 位 SSE 寄存器中,您可以对 4 个浮点数进行操作,但只能对 2 个双精度数进行操作)。
- 特殊函数(
log
、sin
)可以使用低阶多项式:例如log
uses a degree 7 polynomial, whereas logf
的 openlibm 实现只需要 4 级。
- 如果你需要更高的中间精度,你可以简单地将
float
提升到 double
,而对于 double
你需要 software double-double,或者更慢的 [=19] =].
请注意,这些要点也适用于 32 位体系结构:与整数不同,格式的大小与您的体系结构相匹配并没有什么特别之处,即在大多数机器上,双精度数与 "native"作为浮动。
我总是使用 double 来进行计算,但 double 提供的精度远远超出我的需要(或者说是有道理的,考虑到我所做的大部分计算都是从近似值开始的)。
但是由于处理器已经是 64 位的,我不认为使用位数较少的类型会有任何好处。
我是 right/wrong,我将如何优化速度(我知道较小的类型会更有效地使用内存)
这里是测试
#include <cmath>
#include <ctime>
#include <cstdio>
template<typename T>
void creatematrix(int m,int n, T **&M){
M = new T*[m];
T *M_data = new T[m*n];
for(int i=0; i< m; ++i)
{
M[i] = M_data + i * n;
}
}
void main(){
clock_t start,end;
double diffs;
const int N = 4096;
const int rep =8;
float **m1,**m2;
creatematrix(N,N,m1);creatematrix(N,N,m2);
start=clock();
for(int k = 0;k<rep;k++){
for(int i = 0;i<N;i++){
for(int j =0;j<N;j++)
m1[i][j]=sqrt(m1[i][j]*m2[i][j]+0.1586);
}
}
end = clock();
diffs = (end - start)/(double)CLOCKS_PER_SEC;
printf("time = %lf\n",diffs);
delete[] m1[0];
delete[] m1;
delete[] m2[0];
delete[] m2;
getchar();
}
double 和 float 之间没有时间差异,但是当不使用平方根时,float 快两倍。
有几种方法可以提高它们的速度:
- 更快 I/O:您只有一半的位可以在 disk/memory/cache/registers 之间移动
- 通常唯一较慢的运算是平方根和除法。例如,在 Haswell 上,
DIVSS
(浮点除法)需要 7 个时钟周期,而DIVSD
(双除法)需要 8-14(来源:Agner Fog's tables)。 - 如果您可以利用 SIMD 指令,那么每条指令可以处理两倍的数量(即在 128 位 SSE 寄存器中,您可以对 4 个浮点数进行操作,但只能对 2 个双精度数进行操作)。
- 特殊函数(
log
、sin
)可以使用低阶多项式:例如log
uses a degree 7 polynomial, whereaslogf
的 openlibm 实现只需要 4 级。 - 如果你需要更高的中间精度,你可以简单地将
float
提升到double
,而对于double
你需要 software double-double,或者更慢的 [=19] =].
请注意,这些要点也适用于 32 位体系结构:与整数不同,格式的大小与您的体系结构相匹配并没有什么特别之处,即在大多数机器上,双精度数与 "native"作为浮动。