[英]Fastest way to calculate Euclidean distance in c
我需要以最快的方式計算兩點之間的歐幾里得距離。 在 C.
我的代碼是這樣的,看起來有點慢:
float distance(int py, int px, int jy, int jx){
return sqrtf((float)((px)*(px)+(py)*(py)));
}
提前致謝。
編輯:
對不起,我沒有說清楚。 我最好指定上下文:我正在處理圖像,我需要從每個像素到所有其他像素的歐幾里德距離。 所以我必須計算很多次。 我不能用距離的平方。 我將添加更多代碼以更清楚:
for (jy=0; jy<sizeY; jy++) {
for (jx=0; jx<sizeX; jx++) {
if (jx==px && jy==py) {
;
}
else{
num+=rfun(imgI[py][px].red-imgI[jy][jx].red)/distance(py, px, jy, jx);
den+=RMAX/distance(py, px, jy, jx);
}
}
}
float distance(int py, int px, int jy, int jx){
return sqrtf((float)((px-jx)*(px-jx)+(py-jy)*(py-jy)));
}
那是我沒有做的。 我必須用所有像素(px,py)來做
EDIT2:對不起,我不清楚,但我盡量保持問題的普遍性。 我正在編寫一個程序來使用算法處理圖像。 最大的問題是時間,因為我必須做得非常快。 現在我需要優化的是這個函數:`float normC(int py, int px, int color, pixel** imgI, int sizeY, int sizeX){
int jx, jy;
float num=0, den=0;
if (color==R) {
for (jy=0; jy<sizeY; jy++) {
for (jx=0; jx<sizeX; jx++) {
if (jx==px && jy==py) {
;
}
else{
num+=rfun(imgI[py][px].red-imgI[jy][jx].red)/distance(py, px, jy, jx);
den+=RMAX/distance(py, px, jy, jx);
}
}
}
}
else if (color==B){
for (jy=0; jy<sizeY; jy++) {
for (jx=0; jx<sizeX; jx++) {
if (jx==px && jy==py) {
;
}
else{
num+=rfun(imgI[py][px].blue-imgI[jy][jx].blue)/distance(py, px, jy, jx);
den+=RMAX/distance(py, px, jy, jx);
}
}
}
}
else if (color==G){
for (jy=0; jy<sizeY; jy++) {
for (jx=0; jx<sizeX; jx++) {
if (jx==px && jy==py) {
;
}
else{
num+=rfun(imgI[py][px].green-imgI[jy][jx].green)/distance(py, px, jy, jx);
den+=RMAX/distance(py, px, jy, jx);
}
}
}
}
return num/den;
}`
這個函數在每個像素(px; py)的循環中被調用,所以它被調用了很多次並且需要很多時間來計算它。 rfun
函數不可優化,因為它已經非常簡單和快速。 我需要做的是使距離函數更快。
1)我試過hypotf
但它比distance
函數慢
2)我增加了編譯器的優化設置,使過程速度提高了 2 倍!
3)我嘗試了一個宏#define DIST(x, y) sqrtf((float)((x)*(x)+(y)*(y)))
但沒有任何改變(如我所料)
編輯3:
最后我發現最快的方法是計算所有可能的距離並將它們存儲在一個數組中,然后再開始循環計算 normC 函數。 為了使它更快,我計算了距離的倒數,以便我可以使用乘積而不是商:
float** DIST
DIST=malloc(500*sizeof(float*)); //allocating memory for the 2d array
for (i=0; i<500; i++) {
DIST[i]=malloc(500*sizeof(float));
}
for(i=0; i<500; i++){ //storing the inverses of the distances
for (p=0; p<500; p++) {
DIST[i][p]= 1.0/sqrtf((float)((i)*(i)+(p)*(p)));
}
}
float normC(int py, int px, int color, pixel** imgI, int sizeY, int sizeX){
int jx=0, jy=0;
float num=0, den=0;
if (color==R) {
for (jy=0; jy<sizeY; jy++) {
for (jx=0; jx<sizeX; jx++) {
if (jx==px && jy==py) {
;
}
else if (py>=jy && px>=jx){
num+=rfun(imgI[py][px].red-imgI[jy][jx].red)*DIST[py-jy][px-jx];
den+=DIST[py-jy][px-jx];
}
else if (jy>py && px>=jx){
num+=rfun(imgI[py][px].red-imgI[jy][jx].red)*DIST[jy-py][px-jx];
den+=DIST[jy-py][px-jx];
}
else if (jy>py && jx>px){
num+=rfun(imgI[py][px].red-imgI[jy][jx].red)*DIST[jy-py][jx-px];
den+=DIST[jy-py][jx-px];
}
}
}
}
else if (color==B){
for (jy=0; jy<sizeY; jy++) {
for (jx=0; jx<sizeX; jx++) {
if (jx==px && jy==py) {
;
}
else if (py>=jy && px>=jx){
num+=rfun(imgI[py][px].blue-imgI[jy][jx].blue)*DIST[py-jy][px-jx];
den+=DIST[py-jy][px-jx];
}
else if (jy>py && px>=jx){
num+=rfun(imgI[py][px].blue-imgI[jy][jx].blue)*DIST[jy-py][px-jx];
den+=DIST[jy-py][px-jx];
}
else if (jy>py && jx>px){
num+=rfun(imgI[py][px].blue-imgI[jy][jx].blue)*DIST[jy-py][jx-px];
den+=DIST[jy-py][jx-px];
}
}
}
}
else if (color==G){
for (jy=0; jy<sizeY; jy++) {
for (jx=0; jx<sizeX; jx++) {
if (jx==px && jy==py) {
;
}
else if (py>=jy && px>=jx){
num+=rfun(imgI[py][px].green-imgI[jy][jx].green)*DIST[py-jy][px-jx];
den+=DIST[py-jy][px-jx];
}
else if (jy>py && px>=jx){
num+=rfun(imgI[py][px].green-imgI[jy][jx].green)*DIST[jy-py][px-jx];
den+=DIST[jy-py][px-jx];
}
else if (jy>py && jx>px){
num+=rfun(imgI[py][px].green-imgI[jy][jx].green)*DIST[jy-py][jx-px];
den+=DIST[jy-py][jx-px];
}
}
}
}
return num/(den*RMAX);
}
平方根是一個昂貴的函數。 如果您只關心距離的比較方式(此距離是否小於此距離、相等等),則不需要平方根。
這與許多數字信號處理框架(X-Midas、Midas 2k、PicklingTools)具有幅度(這與復數的距離計算基本相同)和幅度 2(省略平方根)的原因基本相同。 有時,您只關心事物的比較方式,而不一定是實際價值。
嘗試類似
double dx = (jx-qx);
double dy = (jy-qy);
double dist = sqrt(dx*dx + dy*dy);
如果您可以只使用正方形(當您只想執行按距離排序之類的操作時這很有用,您可以使用更有效的
double dx = (jx-qx);
double dy = (jy-qy);
double dist = dx*dx + dy*dy;
這取決於你的意思是快速。
首先,正如其他人建議的那樣,您可能會調整您的要求並在某些情況下以平方距離生活。
接下來,您不會從操作上的擠壓和額外循環中獲益多少,而是在需要處理大量此類操作時考慮加快速度——矢量化、優化內存布局、緩存利用率、並行計算等。但那些主題需要更多地了解特定的程序需求。
首先,在您的循環中,您使用相同的參數連續兩次調用“距離”:
{
num += foo / distance(...);
den += bar / distance(...);
}
聲明一個新變量“tmp”並將上面的代碼更改為
{
tmp = 1 / distance(...);
num += foo * distance;
den += bar * distance;
}
應該會大大加快您的代碼速度,盡管這可能是您看到的編譯器優化次數增加的 2 倍。 (請找出來!)另請注意,我將除法交換為乘法——這在計算時間方面也更便宜。
其次,一些編譯器對 1/x^2 甚至 1/sqrt(x) 進行了優化。 為了讓您的編譯器能夠使用這樣的優化,不要計算距離,而是計算距離的反比。 所以你的return語句應該是
return 1 / sqrtf(...);
對於許多優化,運行代碼的 CPU 也很重要。 尤其是如果您希望進行矢量化(您有 SSE 嗎?AVX?)或並行化(您有多少可用內核?他們在此期間忙於做其他事情還是您可以使用它們?)。
不嘗試就很難確定,但看起來您最好進行矢量化而不是並行化(在單獨的內核上運行 - 開銷可能會消耗您可能獲得的任何性能提升)。
如果您正在處理圖像,您可以使用快速精確歐幾里得距離 (FEED) 變換。 https://ieeexplore.ieee.org/abstract/document/6717981/
最優循環
np=length(pixelsCand);
dc=zeros(np);
for(ir=1:np)
for(ic=ir+1:np)
%dc(ir,ir)=0
dc(ir,ic)=sqrt(sum((pixelsCand(ir,:)-pixelsCand(ic,:)).^2));
dc(ic,ir)= dc(ir,ic);
end
end
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.