• ベストアンサー

データコピー

unsigned short型の配列から別のunsigned short型の配列へ、データをコピーするときに、オーバーヘッドを少なく、いかに処理時間を高速にデータをコピーするかというお話です。 たとえば↓のようなデータがあったとします。 unsigned short a[100],b[100]; 配列aから配列bへどのようにしたら、高速にメモリコピーできるんでしょうか? memcopyを使用すると一番手っ取り早いのですが、ものすごくオーバーヘッドが高いと聞きます。memcopyを行うとどのような処理をしているのでしょうか? memcpyを使用しないなら、for文を使って for(i=0;i<100;i++){  a[i]=b[i]; } と私はしてしまいたいのですが、知人曰く、メモリアクセスには時間がかかるので避けたいとのことでした。 たとえば、aからbへの代入に一旦ポインタを使用して、double型でキャストして代入を行い、メモリアクセスの回数を減らして、for文のループも減らすという対策も出来るとおもいますが、一体どれが一番高速にaからbへデータをコピーできるのでしょうか? a[100],b[100]としましたが、サイズは任意です。大きい場合もあるし、小さい場合もあります。 なにか良いアイデア&memcopyの内部処理などを知っている方いましたら、教えてください。

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

  • ベストアンサー
  • drmoreau
  • ベストアンサー率41% (33/79)
回答No.4

推測ですが、インテルの石では、中心部分は大体こんな感じではないですか。RISCチップやモトローラはわかりません。インテル一筋なもんで。 MOV EAX,CS MOV DS,EAX MOV ES,EAX POP SI POP DI POP ECX CLD REP MOVSB このソースの前後にCライブラリ特有の処理が必要になります。 ただ、関数のオーバーヘッドが気になるのでしたら、全体のアルゴリズムを見直して、データ転送ではなく、ポインタを使うようにしたほうがいいと思います。

kokin_go_go_go
質問者

お礼

丁寧なご回答どうもありがとうございます。 実はこのプログラムは特定機器向け用に知人がC言語で作っている最中で 高速化をはかるために、ほとんどのアルゴリズムの改良を行なったらしいです。 で、残りはこの部分のみとのことでした...。 入出力は外部かららしく、それを自分のところのどうしてもポインタを使用せず、 メモリにコピーをしたいらしいです。 memcopyを使用せずに、高速にコピーできる方法で、 なにか良いアイデアありませんか~?? あったらどうぞよろしくお願いいたします。

その他の回答 (6)

  • drmoreau
  • ベストアンサー率41% (33/79)
回答No.7

インテル系の石の場合、アセンブラレベルで、メモリからメモリへのコピーをする命令は、ストリング命令、MOV命令しか用意されていないと思います。 関数のオーバーヘッドが気になるなら、インラインアセンブルしかないのでは。

kokin_go_go_go
質問者

お礼

ご回答、有難うございます。 相談を持ちかけてきた知人にそういってみます。 どうも私のレベルでは、無理みたいです・・・。 しかし、とても参考になりました。 ありがとうございました。

  • notnot
  • ベストアンサー率47% (4848/10261)
回答No.6

>実はこのプログラムは特定機器向け用に知人がC言語で作っている最中らしいです。 >先ほどその知人に聞いたところ、memcopyは使用できないとのことでした...。 memcopyも実装されてないような特定機器の話なら、こんな一般論的な質問をしても解決しないと思います。コンパイラの最適化能力もわからないし。具体的な機器名やコンパイラ名を書くと、それを知っている人なら回答できるかも。

kokin_go_go_go
質問者

お礼

ご回答、ありがとうございます。 実は知人からの相談なので、まったく環境がわかりません。 わかりましたら、お知らせしたいと思います。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.5

『車輪を再発明してはいけない』 ソフトウェア工学ではよく言われる言葉ですが、その言葉には「効率を追い求めるだけのために標準ライブラリを再開発するな!」という意味が含まれます。 あえて車輪の再発明を望むならCPUのアーキテクチャ、CPUに内蔵されていないデータキャッシュのアルゴリズム、メモリBUSの仕様、仮想記憶のアルゴリズム、ページングデータセットのサイズなどなど考慮すべきポイントが山ほどあります。 少なくとも処理系依存の標準ライブラリはこれらを考慮して実装されているはずだからです。

kokin_go_go_go
質問者

お礼

ありがとうございます。 とりあえず、私のレベルではどうにもならなそうです。 でも、とても参考になりました。 どうもありがとうございました。

  • uyama33
  • ベストアンサー率30% (137/450)
回答No.3

アセンブラで書くのが早くなると言う話を 聞きました。 データの形がはっきり決まっているなら アセンブラの形の出力をつくり それから、一つ一つの演算の速度表と 回数を見て調整するのかな?  以前、私が書いたソフトと商売用に直して使っていた 友人がそのようなことをいっていました。 でも、私はmemcpy() を使います。 この時間が問題になるなら新しいコンピュータにすれば 速度の問題はすぐ解決するからです。 それに、簡単だし!!

kokin_go_go_go
質問者

お礼

ご回答どうもありがとうございます。 実はこのプログラムは特定機器向け用に知人がC言語で作っている最中らしいです。 先ほどその知人に聞いたところ、memcopyは使用できないとのことでした...。 マシーンのスペックも決まっているとのことです。 memcopyを使用せずに何か良いアイデアありませんか~? よろしくお願いします。

  • taka_tetsu
  • ベストアンサー率65% (1020/1553)
回答No.2

>memcopyを使用すると一番手っ取り早いのですが、ものすごくオーバーヘッドが高いと聞きます。 そうなんですか? できる限り高速化されてるはずなんですけどね。 ループなんかよりずっと速いはずなんですけど。 >memcopyを行うとどのような処理をしているのでしょうか? コンパイラ依存でしょうね。 VC++であれば、Cランタイムのソースも付属しているので中を確認することもできます。 おそらくアセンブラを使用していると思われますが。

kokin_go_go_go
質問者

お礼

ご回答どうもありがとうございます。 memcopyがオーバーヘッドが高いと知人が言っていたので、 本当かどうかは確かめていません。 しかし、それは依存するものだということを知れただけでも 大きな収穫です。どうもありがとうございました。

  • toysmith
  • ベストアンサー率37% (570/1525)
回答No.1

memcpyなどの関数は実装依存なのでアルゴリズムは想定してはいけません。 1バイトずつまじめにコピーしているかもしれないし、2~8バイト単位にコピーしているかもしれません。

kokin_go_go_go
質問者

お礼

ご回答どうもありがとうございます。 memcopyは実装依存なのですね。 あまり気にしないことにて、参考にしてみます。 ありがとうございました。

関連するQ&A

  • 配列のポインタについて

    C言語で処理が下記のような処理を作成したいと思っております。 関数の引数によって、データを代入する配列を切り替えたいと考えております。 下記のような処理を考えた場合、if文の中・for文のbuffをどのように処理すれば よいでしょうか? アドバイスよろしくお願い致します。 int a[100][150]; int b[100][150]; void sample(int flg) { int i,j; unsigned short *buff; if(flg == 0){ buff = &a; }else{ buff = &b; } for( j=0 ; j<100 ; j++ ){ for( i=0 ; i<150 ; i++ ){ buff[y][x] = data; x++; } x = 0; y++; } }

  • long型のデータをバイト型の配列に代入する方法

    long型のデータを配列を使って1byte毎に分けたい処理を作りたいのですが、 やりかたとしてはlong型のアドレスをポインタ変数に渡して、 ポインタ変数をバイト配列に代入する方法になりますでしょうか? 具体的なプログラムはこんな感じと考えてますが unsigned long LONG: unsigned char AAA[8], *pon, i: pon = &LONG for(i=0 i<8 i++) { AAA[i] = *pon + i; } C言語に詳しい方教えてください、よろしくお願いします。

  • 2次元配列のコピーについて

    2次元配列のコピーについて質問があります。 $Aが元の2次元配列、$Bがコピー先だとして、 ${$A}[0..N][0..N]に値が入っているとします。 ここで、$Bの代入を、$B=$Aとやってしまうと、$Aと$Bが連動してしまいます。 ($Bが書き換わったのに$Aも書き換わる) これはなぜなのでしょうか。 また、$Bの代入を、配列を走査して foreach (0.. $#{$A}) {  my ($i) = $_;  foreach (0.. $#{${$A}[$i]})  {   my ($j) = $_;   ${$B}[$i][$j] = ${$A}[$i][$j];  } } とすれば問題ないのですが、あまりスマートだと思えません。 もっとスマートにコピーする方法はありますか?

    • ベストアンサー
    • Perl
  • 多次元配列とポインタ渡しについて

    多次元配列のポインタ渡しについて,自分で検索したのですがあまりにも様々で具体的な記述が無く質問させていただきました. 検索力不足もあるのでソースの提示だけでも結構ですので,ご回答お願いいたします. OS:Windows XP ソフト:VisualStudio.net2003(C++) C++プログラミング暦2ヶ月弱です. データを変換して多次元配列にデータを入れる自作の関数をつくりたいと考えています. 具体的には,a1からa2,b1からb2を10区間に分けてたデータを配列にしたいといったものです. 自分で記述した関数は以下の通りです. void Convert(float a1,float a2,float b1,float b2,unsigned short *Data){ int k; float a; float b; for(k=0;k<11;k++){ a = a1 + (a2 - a1) / 10; b = b1 + (b2 - b1) / 10; Data[k][1] = ( powf(2.0,16) * (a + 10.0) / 20; Data[k][1] = ( powf(2.0,16) * (b + 10.0) / 20; } } void main(){ float a = 10; float b = 20; unsigned short Data[11][2]; Convert(a1,a2,b1,b2,Data); ... } としています. ここでコンパイルすると, "5番目の引数をunsigned shortからunsigned short *に変換できません" となってしまいます. 配列の名前のみの部分はその配列の先頭アドレスを示すポインタであることから,自分では間違いがないと思っているのですが….

  • 配列のコピーについて

    C言語での配列のコピーについて調べているのですが、memcpyの使い方がよくわかりません 例えば memcpy(a,b,16); と for(i=0;i<16;i++){ a[i]=b[i]; } では何が違うのでしょうか? 教えていただけたら幸いです。

  • pythonの多次元配列へのデータ入力

    pythonの多次元配列で以下のように、ループのカウンタのn,mで配列の位置を指定して代入することができないようです。このような場合どう処理するのでしょうか。 for n in range(1:10) for m in range(1:10) a[n][m]=f(n/m) なお、aについては使用の宣言はしておらず、メモリも確保されていません。fは別途用意されています。 また、a[2][3]=1.3 のように配列の場所を指定して代入するのもダメのようです。numpy.arrayとかで宣言するのかなと思うのですが。使用例が見つかりません。2次元配列だけでなく3次元配列だとどうなるかなと思うのですが。 科学技術計算はこんなのばっかりです。pythonはそのようなものに向くでしょうか。いろんなものがpython対応になってきているので速さの問題があっても器用な処理ができるのなら選択されることも多いと思いますが。 よろしくお願いします。

  • 配列入れ替えの効率的方法は

    VBでグローバル変数配列を3000とっています。 格納されているデータを、1つづつずらして代入し直しをやりたいのですが 配列添え字1のデータを配列添え字0にというふうに3000回のループで 処理する以外に良い方法はないでしょうか 例 for i=0 to 2999 a[i]=a[i+1]

  • 構造体のコピーについて

    次のプログラムを実行してoriginalは偶数、copyは奇数を表示するようにしたいのですが、実行すると両方とも奇数になってしまいます。 正しく表示されるようにするにはどこを直せばいいのか教えてください。 #include<stdio.h> #include<stdlib.h> #include<string.h> typedef struct structSample_ { unsigned int nmemb; /*配列の要素数 */ int *data; /* データを格納する配列 */ }Sample; /* 関数のプロトタイプ宣言 */ Sample *alloc_str ( unsigned int nmenb ); /* 新しい構造体を確保 */ /* main関数 */ int main ( void ) { Sample *original_str, *copy_str; unsigned int number = 10; int i; /* 構造体用のメモリ割り当て */ original_str = alloc_str ( number ); copy_str = original_str; /* original にデータを代入 */ for( i = 0; i < original_str->nmemb; i++ ) original_str -> data[i] = (i+1) * 2; /* 偶数を代入 */ /* original を copy に複製 */ copy_str = original_str; /* copy のデータを編集 */ for( i = 0; i < copy_str->nmemb; i++ ) copy_str->data[i]--; /* 奇数にする */ /* 結果の確認 * original には偶数が入っているはず */ printf( "original: " ); for( i = 0; i < original_str->nmemb; i++ ) printf( "%d ", original_str->data[i] ); printf( "\n" ); /* copy には奇数がはいっているはず */ printf( " copy : " ); for( i = 0; i < copy_str->nmemb; i++ ) printf( "%d ", copy_str->data[i] ); printf( "\n" ); return 0; }

  • C言語の配列の扱い

    次のような配列bufと変数dataを宣言して bufの中身をdataにコピーしたいのですが、 buf[0]のみで、buf[1]の値が入りません。 具体的には、buf[0]には16進数で0x3f、 buf[1]には0x3aが入っていて、 dataの値を0x3a3fにしたいのです。 教えてください。 ***************************** unsigned char buf[2]; unsigned short data; data = (unsigned short)*buf; *****************************

  • C言語のfwrite関数について

    現在,バイナリのデータを処理するプログラムを作成しています。 おおまかに言えば,ファイルA(バイナリモードでオープン)からバイナリでデータを読み込んできて,そのデータを処理してファイルB(バイナリモードでオープン)に書出す,のようなプログラムです。 その処理したデータを入れるデータ型にunsigned long long int型(64bit)を使用しています。 その処理データをファイルBに書出す時に,fwrite関数を用いています(例参照)。 (例) for(i=0; i<N; i++){ fwrite(&c[i], sizeof(c[i]), 1, fp); } //配列cが「unsigned long long int型」です。 //配列cは最初に"0"で初期化しています。 //fpはファイルポインタです。 しかし,本システムでunsigned long long int型が実際に使用しているのは下位32bitです。 上の例で書出した場合,上位32bitの"0"も書出されていることになるのでしょうか。 書出されたファイルのサイズを見れば,64bit全て書出されているようですが,計算間違いで32bitを超えたところまで何かデータが入っている可能性もあります。 どなたはfwrite関数に詳しい方,ご回答をよろしくお願いします。

専門家に質問してみよう