• ベストアンサー

3次元の最短距離計測  MFC6.0 使用

今 3次元における 最短距離の測定を しています 現状を説明します struct POINT { double x; double y; double z; } //グローバル宣言 POINT upper[18000]; POINT lower[18000]; int main (void){   double min=10000000000000000000.0;//あからさまに 大きくしておく   double differ;   for(int i=0;i<18000;i++){    for(int k=0;k<18000;k++){    differ = (upper[i].x-lower[k].x)^2+(upper[i].y-lower[k].y)^2+(upper[i].z-lower[k].z)^2;    if(min>differ){    min = differ;    }    }   //ここで 準備していたMeasure に min を代入   Measure[i]=min;  } } 大体これで 2分かかります。 この 単純な方法で 今までよかったのですが、少々 時間が かかりすぎているので 不都合が 生じています。 もっと 早く処理できる アルゴリズムを 教えてください。 お願いします

質問者が選んだベストアンサー

  • ベストアンサー
  • matyrcry
  • ベストアンサー率47% (101/213)
回答No.3

前の方とほとんど同じですが、 発見済みの最短距離とその2乗を控えておいて、 1)X座標の差分が最短距離よりも大きい 2)Y座標の差分が最短距離よりも大きい 3)Z座標の差分が最短距離よりも大きい 4)XとYの2乗合計が最短距離の2乗よりも大きい と演算途中でループを抜ける処理を組み込んで いってはどうでしょうか。 浮動小数の乗除算は整数乗除に比べて遙かに重いので、 かける前に比較で分かるものはハネたほうがいいと思います。

その他の回答 (6)

回答No.7

大小判断はNo.6の方に賛成です。 で、よけいなお世話なのですが、どうもminの初期化 が気になります。 double min = (upper[0].x-lower[0].x) * (upper[0].x-lower[0].x); min += (upper[0].y-lower[0].y) * (upper[0].y-lower[0].y); min += (upper[0].z-lower[0].z) * (upper[0].z-lower[0].z); とするか、for分の中でi==0 && k==0ならminに代入、 それ以外は大小判別する方が、汎用性があります。

回答No.6

計算量を減らすアルゴリズムを研究するのが目的ではなくて計算時間を短縮したいのであれば、計算機を高速なものに変更することをお勧めします。 プログラム上で高速化する手として思いつくのは、 ・構造体の配列をバラの配列にする ・2乗和の計算を3つに分けて途中で最小値と比較する ぐらいです。。 サンプルプログラム #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> //グローバル宣言 double upper_x[18000]; double upper_y[18000]; double upper_z[18000]; double lower_x[18000]; double lower_y[18000]; double lower_z[18000]; double ans; void f1(void){ int i,k; double min=10000000000000000000.0;//あからさまに 大きくしておく double differ; for(i=0; i<18000; i++) { for(k=0; k<18000; k++) { differ = (upper_x[i]-lower_x[k])*(upper_x[i]-lower_x[k]); if (differ>min) continue; differ += (upper_y[i]-lower_y[k])*(upper_y[i]-lower_y[k]); if (differ>min) continue; differ += (upper_z[i]-lower_z[k])*(upper_z[i]-lower_z[k]); if (differ>min) continue; min = differ; } } ans=min; } void ini(void) { int i; srand(13); for (i=0; i<18000; i++) { /* 擬似乱数 -RAND_MAX/2 ~ RAND_MAX/2 */ upper_x[i] = (double)(rand()-RAND_MAX/2); upper_y[i] = (double)(rand()-RAND_MAX/2); upper_z[i] = (double)(rand()-RAND_MAX/2); lower_x[i] = (double)(rand()-RAND_MAX/2); lower_y[i] = (double)(rand()-RAND_MAX/2); lower_z[i] = (double)(rand()-RAND_MAX/2); } } int main(void) { clock_t begin, end; ini(); begin=clock(); f1(); end=clock(); printf("ans=%g %f sec.\n",sqrt(ans),(end-begin)/CLOCKS_PER_SEC); return 0; }

  • keikan
  • ベストアンサー率42% (75/176)
回答No.5

doubleではなくてlong intにてはいかが?^^

  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.4

インラインアセンブラで SSE命令を使ってはどうでしょうか? SSE命令を使えば 複数の浮動小数点の計算を同時で行えます ただしCPUがPentium3以上である必要があります。

参考URL:
http://www1.kcn.ne.jp/~robe/pf/pf009.html,http://home.netyou.jp/gg/ugpop/academy002-047.htm
akagenoanfan
質問者

お礼

どうやら つかえないようです。 ありがとうございました。

  • ranx
  • ベストアンサー率24% (357/1463)
回答No.2

何をなさりたいのかが今一つ分からないのですが、 18000個の各点について、別の18000個の点のうち最も近いものまでの 距離を求めるということでしょうか。 18000個の点がランダムなものなら、X,Y,Z各方向の差分値が大きなものを 除外して、自乗和を計算する時間を省くことができると思います。 18000個の座標値に何らかの規則性があるのなら、それを利用してさらに 計算を省くことができるかもしれません。 いずれにせよ、現状は18000×18000=324000000回も自乗和を計算している わけですから、何とか工夫して、この回数を減らす必要があるのだと 思います。

akagenoanfan
質問者

補足

>>何をなさりたいのかが今一つ分からないのですが、 18000個の各点について、別の18000個の点のうち最も近いものまでの 距離を求めるということでしょうか。 はい。そのとおりです。 >>18000個の点がランダムなものなら、X,Y,Z各方向の差分値が大きなものを 除外して、自乗和を計算する時間を省くことができると思います。 差分地が大きいものを除外 というのは どういうことでしょうか?X Y Z すべての差が おおきいものですか?どれか おおきいものですか? >>18000個の座標値に何らかの規則性があるのなら、それを利用してさらに 計算を省くことができるかもしれません。 今のところZ方向のみ 小→大 という順番にならんでいます。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.1

「2分かかる」といわれてもスペックもわからなければどのくらい最適化しているかもわからないので, 「本当にそれだけかかってしまう」のか「単にプログラムが遅いだけ」なのか判断のしようがないんですが. ちなみに ^ を使うのは変ですね.

akagenoanfan
質問者

補足

スペック??とは なんでしょうか? 最適化? 現在 Z 方向のみに注目して 小→大に ならんでいます。

関連するQ&A

  • 一番近い点を見つけたい。

    今  struct POINT{ double x;//x座標 double y;//y座標 } struct Model{ POINT point[18000]; } というふうな 構造体を宣言し、 Model upper; Model lower; を 宣言します。 upper.point[0] から 一番近い点 を lowerから みつけたいのですが、lower.point[0]からlower.point[17999]まで 順番に探して より小さいものがみつかれば それを (例えば)m に 代入すると いった風にしています。しかし それをupperの点すべてにそれぞれ 一番近いてんをlowerから 探そうと すると プログラムが 固まってしまって うまく うごきません。 なにか いいアイデアは ありませんでしょうか?アルゴリズム など なにか 知っている方が いれば 教えて下さい。

  • このプログラミングって正しい?

    与えられた実行列X,Y,Z(配列名x、y、z)から、X-YZを計算して、行列W(配列名w)に格納するメソッドを完成する。 Public static void XminusXY( double[][] x,double[][] y,double[][] z, double[][] w){ double wij; int el=z[0].length, m=y.length, n=z.length; for(int i = 0; i<m; i++){ for(int j = 0; j<n-1; j++){ wij=xij for(int k=0; k<el; k++) wij += -y[i][k]*z[k][j]; w[i][j]=wij; } } }

  • 構造体の要素すべてに対する四則演算の方法を教えてください.

    構造体の要素すべてに対する四則演算の方法を教えてください. たとえば、 2点a,bの座標成分x,y,zをそれぞれの座標ごとに足す方法を教えてください. 下のようにx,y,z成分を持ったa,bがあります。 struct point{ int x; int y; int z; }; struct point a; struct point b; struct point c; この場合, c=a+b; と書くことができず, それぞれの成分ごとに以下のように足さなくてはなりません. c.x=a.x+b.x; c.y=a.y+b.y; c.z=a.z+b.z; この方法でできるのですが, 非常に効率的でないのでなにかもっと簡単に記述する方法を教えてください. お願いいたします.

  • 三次元を二次元に・・・

    ヘッダーファイルの中にXeasyGraphic.hと言うのがあり、立方体を表示させ回転たいのです。 そして、三次元で回転させ、二次元に落とすという方法をしたかったのですが、どうしても、ゆがんでしまいます。どうしたらいいでしょうか? -------ソース------- #include<stdio.h> #include<XeasyGraphics.h> #include<math.h> int main(){ /*立方体の宣言*/ float box_x[8]={10,10,10,-10,10,-10,-10,-10};/*X軸*/ float box_y[8]={10,10,-10,10,-10,10,-10,-10};/*Y軸*/ float box_z[8]={10,-10,10,-10,-10,10,10,-10};/*Z軸*/ /*立方体のキャッシュ*/ float box_x2[360][8],box_y2[360][8],box_z2[360][8]; /*平面に落とした時のキャッシュ*/ float flat_x[360][8],flat_y[360][8]; /*回転用*/ int j,i; float th,x,y,x2,y2; /*回転プログラム*/ for(j=1;j<=360;j++){ for(i=0;i<8;i++){ x=box_x[i]; y=box_y[i]; th=(PAI/180)*j; box_x2[j-1][i]=x*cos(th)-y*sin(th); box_y2[j-1][i]=x*sin(th)+y*cos(th); box_z2[j-1][i]=box_z[i]; } } /*三次元から二次元へ*//*ここが間違えていると思われる*/ for(j=0;j<360;j++){ for(i=0;i<8;i++){ flat_x[j][i]=box_x2[j][i]-box_z2[j][i]; flat_y[j][i]=box_y2[j][i]-box_z2[j][i]; } } /*この後に表示が入る予定*/ getchar(); exit(0); }

  • VB6からDLLへの構造体受け渡し

    VB6からCで作成したDLLに構造体を受け渡したいのですが上手くいきません。 構造体にはLong型やDouble型、それに他の構造体も含まれておりC側も同様にしているつもりなのですが文字化けしてしまいます。下記に入力しているのコードを記載しましたので分かる方がいましたら助けてください。 尚、下記の構造体の「method」までは問題無く取得できるのですが「success_interlinkage」のDouble型からの変数は文字化けした数字になってしまいます。宜しくお願い致します。 [VB側] Public Type PackageProcessingInfo_i brightness As Long contrast As Long smoothtype As Long smoothlevel As Long method As Long success_interlinkage As Double min_interlinkage As Double max_interlinkage As Double min_point As CvPoint max_point As CvPoint corner_point As CvPoint End Type Public Type CvPoint_i x as Long y as Long End Type [C側] typedef struct _PackageProcessingInfo { int brightness; int contrast; int smoothtype; int smoothlevel; int method; double success_interlinkage; double min_interlinkage; double max_interlinkage; CvPoint min_point; CvPoint max_point; CvPoint corner_point; } PackageProcessingInfo; typedef struct _CvPoint { int x; int y; } CvPoint;

  • 配列のエラーに関して

    java言語を用いて,Householder変換を用いた固有値の数値計算に挑戦してみました.しかし,次のようなエラーが発生し上手くいきません.どなたかこの問題を解決するためにお力をかしていただけないでしょうか. ----------エラー内容-------------------------------------------------------------------------------- Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0 at Out.Mhouse(House.java:90) at House.main(House.java:10) ---------------------------------------------------------------------------------------------------- //Householder変換 public class House{ public static void main(String[] args){ double[][] A = new double[3][3]; int n = A.length; Out out = new Out(); for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ if(j < n-1){ System.out.print(out.Mhouse(A)[i][j] + " "); }else if (j == n-1) System.out.println(out.Mhouse(A)[i][j]); }; }; }; }; class Out{ double[][] outpro(double[] x){ int n; n = x.length; double[][] A = new double[n][n]; for(int i = 0;i < n;i++ ){ for(int j = 0;j < n;j++){ A[i][j] = x[i] * x[j]; } } return A; }; double[][] Msca(double a,double[][] A){ int n = A.length; for(int i = 0;i < n; i++){ for(int j = 0;j < n;j++){ A[i][j] = a * A[i][j]; } } return A; }; double selfpro(double[] x){ double a = 0; int n = x.length; for(int i = 0;i < n; i++){ a = a + x[i] * x[i]; }; return a; }; double[] minus(double[] x, double[] y){ int n = x.length; double[] z = new double[n]; for(int i = 0;i < n;i++){ z[i] = x[i] - y[i]; }; return z; }; double[][] house_1(double[] x){ int n = x.length; double[][] A = new double[n][n]; for(int i=0;i < n;i++){ for(int j = 0;j < n;j++){ if(i == j){ A[i][j] = 1 - Msca(2/selfpro(x),outpro(x))[i][j]; }else{ A[i][j] = - Msca(2/selfpro(x),outpro(x))[i][j]; }; }; }; return A; }; double[][] house_2(double[] x){ double[][] z = new double[1][1]; z[1][1] = 1 - 2; return z; }; double[][] Mhouse(double[][] A){ int n = A.length; double[][] H = new double[n][n]; for(int i = 0;i < n;i++){ double[] x = new double[n-i]; double[] y = new double[n-i]; double[][][] L = new double[i][n-i][n-i]; for(int j = 0;j < n-i;j++){ x[j] = A[i][i+j]; if(j == 0){ y[j] = 1; }else{ y[j] = 0; }; x[j] = y[j] - x[j]; }; if(i < n-1){ L[i] = house_1(x); for(int k = 0;k < n-i;k++){ for(int l = 0;l < n-i;l++){ H[i+k][i+l] = L[i][k][l]; }; }; }else if(i == n-1){ L[i] = house_2(x); for(int k = 0;k < n-i;k++){ for(int l = 0;l < n-i;l++){ H[i+k][i+l] = L[i][k][l]; }; }; }; }; double[][] B = new double[n][n]; for(int i = 0;i < n;i++){ for(int j = 0;j < n;j++){ for(int k = 0;k < n;k++){ B[i][j] = H[i][k] * A[k][j]; }; }; }; return A; }; };

    • ベストアンサー
    • Java
  • c 言語 B tree

    C言語で B-treeを実装するプログラムを書きました。 まだtreeに挿入する関数しか書いておりませんが。。 まず空の根を作ってからそこにどんどん要素を挿入していくのですが、どうも要素が 挿入されていないように思えます。 どこがいけないのか分かる方いらっしゃいませんか? よろしくお願いします。 #include <stdio.h> #define T 10 struct b_tree{ int key[2*T-1]; struct b_tree *node[2*T]; int size; int leaf;//この節点が葉であったら1とする }; void BTreeCreate(void); void BTreeSplitChild(struct b_tree x,int i,struct b_tree y); void BTreeInsert(struct b_tree t,int k); void BTreeInsertNonfull(struct b_tree x,int k); void PrintBtree(struct b_tree x); struct b_tree root; int main (int argc, const char * argv[]) { // insert code here... /*int t;*/ char command; int key; BTreeCreate(); /*scanf("%d",&t);*/ while (1) { scanf("%c %d",&command,&key); if (command=='E') break; if(command=='I') BTreeInsert(root,key);//木にkeyを挿入 } PrintBtree(root); //木を表示 return 0; } void BTreeCreate(void){//空のB-木の生成 struct b_tree x; x.leaf=1; x.size=0; root=x; } void BTreeSplitChild(struct b_tree x,int i,struct b_tree y){ /*B-木における節点の分割をする節点xのi番目の枝の先にある節点yが飽和であった 場合にyをyの中央値で分ける。yの中央値はxの新たなkeyとなりxの枝数は1つ増える*/ int j; struct b_tree z; z.leaf=y.leaf; //zが葉であるかどうかはyが葉であるかどうかに依る z.size=T-1; //また新しくできるxの子zは最小数のkey(T-1)を持たせる for (j=1; j<= T-1; j++) { z.key[j]=y.key[j+1]; //yの中央値よりおおきい値(T-1個)をzに渡す } if(y.leaf==0){ //またyが個をもつ場合は枝もzに渡す for (j=1; j<=T; j++) z.node[j]=y.node[T+j]; } y.size=T-1; //そしてyのサイズも中央値とzに渡した分小さくなる for (j= x.size+1; j>=i+1; j--) { //xにyの中央値を渡すのでx枝の右半分を1つずつ右へずらす x.node[j+1]=x.node[j]; } x.node[i+1]=&z; //i+1番目の枝に新たな子zのポインタを与える for (j=x.size; j>=i; j--) { //値も右へずらす x.key[j+1]=x.key[j]; } x.key[i]=y.key[T]; //xのi番目の値をyの中央値とする。 x.size=x.size+1; //xは1サイズup } void BTreeInsert(struct b_tree t,int k){ int Tsub=T; //条件部にTが使えなかったのでTsubに退避 struct b_tree r,s; r=t; if (r.size == Tsub) { /*根が飽和だった場合を考える新たな親を必要とするため それをsとする。するとsは葉ではなく、sizeは0, そして元々の根rのポインタを与える*/ s.leaf=0; s.size=0; s.node[1]=&r; root=s; BTreeSplitChild(s,1,r); BTreeInsertNonfull(r,k); } else { BTreeInsertNonfull(r,k); } } void BTreeInsertNonfull(struct b_tree x,int k){ /*未飽和の節点xにkを挿入しようと考える。*/ int i; int Tsub=T; if (x.leaf==1) { /*もし、xが葉であれば大小関係を考えて挿入。その際他のkey を右へ1つずつずらす。またxのサイズを1up*/ while (i>=1 && k<x.key[i]) { x.key[i+1]=x.key[i]; i--; } x.key[i+1]=k; x.size++; } else { /*もしxが葉でなければどこの枝をたどればいいのか考える*/ while (i>=1 && k<x.key[i]) { i--; } i++; if ((*x.node[i]).size == 2*Tsub-1) { /*たどる枝の先が飽和であった場合分割する*/ BTreeSplitChild(x, i, *x.node[i]); if (k > x.key[i]) { i++; } } BTreeInsertNonfull(*x.node[i],k);//枝をたどる } } void PrintBtree(struct b_tree x){ printf("abc"); printf("%d",x.leaf);//実行するとleafが1のままなので、数が挿入されていない? int i,l;        if(x.leaf==1){ for (i=1; i<=x.size; i++) { printf("%d def",x.key[i]); } if(l==0)printf("\n"); }else { for (i=1; i<=x.size; i++) { printf("%d ghi",x.key[i]); } if(l==0)printf("\n"); l++; printf(" jkl"); for (i=1; i <= x.size+1; i++) { PrintBtree(*x.node[i]); } } printf("\n"); }

  • プログラミングのことで困っています。助けて下さい。

    プログラミングの問題がどうしても分からず、本当に困っています。 ・2x+y+3z=13 ・x+3y+2z=13 ・3x+2y+z=10 (解:x=1,y=2,z=3) を掃き出し法で解くプログラミングの問題で、次の(1)~(5)が何が当てはまるかどうしても分からないんです。 #include <stdio.h> #define N 3 /*未知数の個数*/ int main(void) { int i,j,k; double pivot,del; double a[N][n+1]={{2,1,3,13},{1,3,2,13},{3,2,1,10}}; /*係数行列*/ for(i=0;i<N;i++) { (1)____ /*ピボット係数*/ for(j=0;j<N+1;j++) /*ピボット行をピボットで割る*/ (2)____ for(k=0;k<N;k++) /*ピボット列の掃き出し*/ { if((3)____) { del=a[k][i]; for(j=i;j<N+1;j++) (4)____ } } } for(i=0;i<N;i++) (5)____ /*計算結果の表示*/ return 0; } 実行結果は x0=1.00 x1=2.00 x2=3.00 と表示させたいのですが、(1)~(5)の所がどうしても分からず、困っています。どなたか助けて下さい。お願いします。

  • 配列の中身を入れ替える方法を教えてください

    配列の中身を入れ替える方法をどなたかおしえてください。下のプログラムはちゃんと実行されるんですが、いまいち納得できません。 特に・・・↓↓ void sort(int a[]) { int x,y,z,min; for(x=0;x<10;x++) { min=x; for(y=x;y<10;y++) { if(a[min]>a[y]) { min=y; } } z=a[min]; a[min]=a[x]; a[x]=z; } } 上の部分でなぜfor文を2回使うのか?2回目のfor文のところはなぜ y=xなのか?0ではいけないのか?よくわかりません。一番最後の入れ替え作業のところは納得できたんですが、for文のところがよくわからないのでどなたか分かる方教えてください! #include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <time.h> void sort(int a[]) { int x,y,z,min; for(x=0;x<10;x++) { min=x; for(y=x;y<10;y++) { if(a[min]>a[y]) { min=y; } } z=a[min]; a[min]=a[x]; a[x]=z; } } int main(int argc, char* argv[]) { int a[10],b,c; srand((unsigned)time(NULL)); for(b=0;b<10;b++) { a[b]=rand(); c=a[b]; printf("a[%d]=%d\n",b,a[b]); } sort(a); for(b=0;b<10;b++) { printf("小さい順a[%d]=%d\n",b,a[b]); } return 0; }

  • sqrtの計算

    ルートの値を返す関数を以下のように作ります。 double sqrt(double x){ double lower,upper,middle,y; lower = 0.0; upper = x; while(1){ middle =(lower+upper)/2.0; y=midde*middle; if(y<0.999*x){ lower=middle; }else if (y>1.001*x){ upper=middle; }else{ return middle; } } } この関数に十分に大きい引数xを関数sqrtに与えたとき、while文による繰り返しは最大何回実行されるか。おおよその回数をxの式で表し、理由を述べよ。 この問題が解ける方は教えて頂きたいです。