参见
http://blog.sina.com.cn/s/blog_476a25110100maem.html
New版有一个问题,当短边为0时,求距离结果会小于长边,这很尴尬
_E版解决了这个问题,保证结果大于任何一边。
因此,在其基础上:
int FastDistance2D(int x, int y)
{
x = abs(x);
y = abs(y);
int mn = min(x, y);
return(x + y - (mn >> 1) - (mn >> 2) + (mn >> 4));
}
// min(x, y) * 11 应小于uintmax,否则会出错
int FastDistance2D_S(int x, int y)
{
x = abs(x);
y = abs(y);
uintptr_t mn = min(x, y);
return int(x + y - int((mn * 11UL) >> 4));
//return(x + y - ((mn * 6) >> 3) + (mn >> 4));
}
int FastDistance2D_New(int x, int y)
{
x = abs(x);
y = abs(y);
int mn = min(x, y);
int mx = x + y - mn;
return (mx - (mx >> 4) + (mn >> 1) - (mn >> 4));
}
int FastDistance2D_New_S(int x, int y)
{
x = abs(x);
y = abs(y);
int mn = min(x, y);
uintptr_t sum = x + y;
return int(sum - (sum >> 4)) - (mn >> 1);
}
//
int FastDistance2D_New_S2(int x, int y) // 和S版差别是防溢出
{
x = abs(x);
y = abs(y);
int mn = min(x, y);
return int(x + y - (x >> 4) - (y >> 4)) - (mn >> 1);
}
int FastDistance2D_E(int x, int y)
{
x = abs(x);
y = abs(y);
int s = min(x, y); //cmovl
int b = max(x, y); //cmovg
int d = (s >> 4) - (b >> 5); //d = max(small - big/2, 0) / 16
if (d < 0) d = 0; //cmovns
return b + (s >> 2) + d * 5;
}
_S版均比对应的无_S后缀版快1/8左右,且与其误差最大为1(原版跟实际误差更大所以无所谓了)
FastDistance2D_S要求min(x,y)<uintmax/11
版本(除了SQRT版其他结果都是int) | x86 1M次耗时(us) | x64 1M次耗时(us) | 误差:与实际值的差/长边 |
---|---|---|---|
(float)lib (sqrtf或sqrt) (intValue) | sqrt(double)4465 float慢50% | sqrt(float)4578 double慢一丁点 | 0.000…… |
(int)sse_sqrt单路( float( intValue)) | 2206 | 2119 | 0.000…… |
(int)sse_sqrt四路( float( intValue)) | 1820 | 1618 | 0.000…… |
最初版 | 3252 | 2549 | 10.15+% |
_S | 2398 | 2352 | 10.15+% |
New | 3310 | 2646 | 6.25% |
New_S | 2762 | 2381 | 6.25% |
New_S2 | 3165 | 2557 | 6.25% |
_E | 3680 | 3219 | 3.33% |