double型配列に格納されたデータを入出力するには


エル  2004-11-10 00:56:20  No: 55080

C++.NETで今、ファイルの入出力処理を実装しています。
double型の各データを1行ごとに保存したり読み出したりしたいのですが
ファイルの書き込みは、おそらく
buf(変数)に保存したい値を代入して
text=text+buf;
fputs(text, fout(fopenでオープンした領域));
とすればいいのは、大体わかるのですが、

ファイルの読み込みで困っています。
安直にReadStringで代入しても良いものか、
そもそも、CString、char型の値が
double型に変換できるのでしょうか?
ご教授おねがいします。


KING・王  2004-11-10 02:55:30  No: 55081

strtod()で変換できると思いますが。。。


tetrapod  2004-11-10 17:42:42  No: 55082

ファイルにどのような形式で保存するのか決めないと手がつけられません。
バイナリなのかテキストなのか?
シリアライズ形式なのか、単純形式なのか?

テキストで行くなら既に指摘されているとおり。
読み込みには fread や fgets を使った後で strtod や sscanf で変換。
書き込みには sprintf で変換した後 fwrite や fputs


エル  2004-11-11 00:50:33  No: 55083

どうも、うまくいかないです・・・
手始めに書き込みを実装したんですが、データの書き込み時に
プログラムが応答しなくなってPC再起を繰り返す羽目になります。
とりあえず、少々長いですがデータ書き込みの部分のソースを
張っておきます。どこら辺が原因なのでしょうか?
ちなみに、ファイルはテキスト形式で保存して使用するデータ型は
double型です。
m_edit2は、ファイル名を記述するエディットボックスです。
その他、不明な変数などありましたら貼り付けます。

void CLayoutDlg::OnBnClickedButton8()
{
  // TODO : ここにコントロール通知ハンドラ コードを追加します。
  FILE *fout;
  double num;
  CString text, filename;
  char buf[1000];
  int a=0,b=0,c=0,d=0,e=0,f=0,g=0,h=0,i=0,j=0,k=0;

  m_edit2.GetWindowText(filename);
  if (filename == "")return;

  if ((fout = fopen(filename,"wb")) == NULL) {
    AfxMessageBox("書き込みファイルをオープンできません");
    return;
  }
  text="";
  while (a<3){
    if(a==0){
      if(k==0)num=agentTable1[b][c][d][e][f][g][h][i][j].getUp();
      if(k==1)num=agentTable1[b][c][d][e][f][g][h][i][j].getDown();
      if(k==2)num=agentTable1[b][c][d][e][f][g][h][i][j].getRight();
      if(k==3)num=agentTable1[b][c][d][e][f][g][h][i][j].getLeft();
      if(k==4)num=agentTable1[b][c][d][e][f][g][h][i][j].getDeep();
      if(k==5)num=agentTable1[b][c][d][e][f][g][h][i][j].getNarrow();
      if(k==6)num=agentTable1[b][c][d][e][f][g][h][i][j].getNomove();
    }else if(a==1){
      if(k==0)num=agentTable2[b][c][d][e][f][g][h][i][j].getUp();
      if(k==1)num=agentTable2[b][c][d][e][f][g][h][i][j].getDown();
      if(k==2)num=agentTable2[b][c][d][e][f][g][h][i][j].getRight();
      if(k==3)num=agentTable2[b][c][d][e][f][g][h][i][j].getLeft();
      if(k==4)num=agentTable2[b][c][d][e][f][g][h][i][j].getDeep();
      if(k==5)num=agentTable2[b][c][d][e][f][g][h][i][j].getNarrow();
      if(k==6)num=agentTable2[b][c][d][e][f][g][h][i][j].getNomove();
    }else if(a==2){
      if(k==0)num=agentTable3[b][c][d][e][f][g][h][i][j].getUp();
      if(k==1)num=agentTable3[b][c][d][e][f][g][h][i][j].getDown();
      if(k==2)num=agentTable3[b][c][d][e][f][g][h][i][j].getRight();
      if(k==3)num=agentTable3[b][c][d][e][f][g][h][i][j].getLeft();
      if(k==4)num=agentTable3[b][c][d][e][f][g][h][i][j].getDeep();
      if(k==5)num=agentTable3[b][c][d][e][f][g][h][i][j].getNarrow();
      if(k==6)num=agentTable3[b][c][d][e][f][g][h][i][j].getNomove();
    }
    k++;
    if(k>=7){j++;k=0;}
    if(j>=5){i++;j=0;}
    if(i>=5){h++;i=0;}
    if(h>=5){g++;h=0;}
    if(g>=5){f++;g=0;}
    if(f>=5){e++;f=0;}
    if(e>=5){d++;e=0;}
    if(d>=5){c++;d=0;}
    if(c>=5){b++;c=0;}
    if(b>=5){a++;b=0;}

    sprintf(buf,"%lf\n",num);
    text=text + buf;
  }
  fputs(text, fout);
  fclose(fout);

}


REE  2004-11-11 01:22:06  No: 55084

出来上がるファイルのサイズを計算してみましたか?
一行につき10byteで済んだとしても、410Mbyteになりますよ
プログラムが応答しなくなったわけじゃなくて、単に書き込みが終わってないだけではないですか?
これだけ大きいのであれば、全部連結したりしないで、
少しずつファイルに出力した方がよいでしょう。


エル  2004-11-11 23:47:38  No: 55085

ためしに、1行書き込むたびに現在行を表示してみたんですが・・・
すごい時間かかります・・・
1時間ほどで1%ぐらいしか進みません。
どうやら、相当書き込みに時間がかかるようで・・・
単純計算で100時間!!?無理ですね・・・

>REEさん
返答ありがとうございます。
ちょっと、質問を
少しずつファイルに出力するというのは、
複数のファイルに分割して保存するということなのでしょうか?
それとも、
一つのファイルに少しずつ追記していく形になるのでしょうか?


REE  2004-11-12 01:22:21  No: 55086

>ためしに、1行書き込むたびに現在行を表示してみたんですが・・・
>すごい時間かかります・・・
どのように表示しているのか分かりませんが、これだけの量があれば、
表示にも相当時間がかかります。
経過を確認したいのであれば、もっと間隔をあけて制御変数だけを表示した方がいいでしょう。
例:dが変化するタイミングでa〜dを表示

>少しずつファイルに出力するというのは、
>複数のファイルに分割して保存するということなのでしょうか?
>それとも、
>一つのファイルに少しずつ追記していく形になるのでしょうか?

後者です。
例えば、text=text + buf; の代わりに fputs(buf, fout);
として、fputs(text, fout);を消します。

ちなみに、for文の多重ループを使っていないのは何か理由があるのですか?
後半の連続したif文も処理に時間がかかる原因の一つになっているように感じます。


エル  2004-11-12 09:45:29  No: 55087

>REEさん
多重forループにしてないのには理由ないです・・・
ただ、自分が多重ループにするの忘れてただけで・・・
多重ループの方がソースもすっきりしますよね。

後半のif文連続は擬似○進数みたいな感じで作ったんですが、
最初の位(k)が7進数  、最後の位(a)が3進数。
残りが5進数といった感じでやってみたんですが、
if文連続より良いアルゴリズムが思いつかなくてこのような形にしました。


REE  2004-11-12 19:23:51  No: 55088

>if文連続より良いアルゴリズムが思いつかなくてこのような形にしました。

その良いアルゴリズムが、for文の多重ループです。
特にfor文に変更したくない理由が無ければ、変更した方がよいでしょう。


なーめ  2004-12-09 23:51:27  No: 55089

すでに1ヶ月くらい経過していますが。(^^;;
解決ボタンもないことですし。

for にしてもネストが深くてはあまりきれいには見えませんね。

ということで美しく書くことに徹してみます。
ループの中身を変えてオーバヘッド測定をしてみました。
プログラムは下にあります。

結果:
  ( Pentium4 1.9GHz Win2K, VC++6.0 )

  // 主として while( vc ) のオーバヘッド
  ループ内が a = b; のみのとき 3154ms  

  // sprintf() のオーバヘッド
  sprintf( s, "%lf", a = b ); のとき 222281 ms.

  // 添え字アクセスのオーバヘッド( memory cache swap 込み)
  a = vv[vc[10]]...[vc[0]]; のとき 38611 ms.

  // I/O 込みのオーバヘッド
  fprintf( fp, "%lf\r\n", a = b ); のとき 243148 ms.

  // 現実に近い形 ... 94878 ms.
  fprintf( fp, "%lf\r\n", a = vv[vc[10]]...[vc[0]] );

  ここでなぜか値が小さいが、vv[]..[] の内容はほとんど0であるため
  書式生成のオーバヘッドがほとんどないためであることが判明。

  // 検証 ... 88181 ms.
  sprintf( vs, "%lf\r\n", a = vv[vc[10]]...[vc[0]] );

  // なおバイナリで保存すると... 47514 ms.
  fwrite( &vv[vc[10]]...[vc[0]], 1, sizeof(double), fp );
  
  // やはり一括で保存するのが早いだろう ... 10790 ms.
  ループせずに fwrite( vv, 1, sizeof(vv), fp );

結論:

  sprintf()で有効な値を持つdoubleを書式変換すると重くなる。
  loopvec クラスの使用も for ループに比べれば明らかに遅いが、
  思ったほど遅くもなさそうだった。スピードの要求されないところには
  きれいな表記のために使用しても良さそうだと思われる。

  int vec[] = { 7,3,5,5,5,5,5,5,5,5,5 };
  loopvec vc( vec,11 );
  while( vc ) // ループは一重(ひとえ)ね。
  {
     vc[0],vc[1] ...
  }

  でも、やはりバイナリで一括保存するのは早い。
  サフィックスの vc[n] が汚いかもしれない。
  さて、みなさんの評価はいかがなりや?

-----------------------------------------------------------

#include "loopvec.h"

double vv[5][5][5][5][5][5][5][5][5][3][7];

void CDblmemDlg::OnSaveFile() 
{
  CTime et,st = time(NULL);
  CTimeSpan dt;
  double a = 0.0, b = 2.33;
  int vec[] = { 7,3,5,5,5,5,5,5,5,5,5 };
  loopvec vc( vec,11 );
  __int64 s,e;
  FILE * fp;
  if( fp = fopen( "E:\\tempfile.txt","wb" ))
  {
    s = qpc();
    while( vc )
    {
      fwrite( &vv[vc[10]][vc[9]][vc[8]][vc[7]][vc[6]][vc[5]][vc[4]][vc[3]][vc[2]][vc[1]][vc[0]], 1, sizeof(double), fp );
    }
    e = qpc();
    fclose( fp );
  }
  TRACE("%s\n", ed( s,e ));
}
---------------------------------- 測定ツール ----

__int64 qpc( void ) // query performance counter
{
  __int64 q;
  QueryPerformanceCounter( (LARGE_INTEGER*)&q );
  return( q );
}

char * ed( __int64 s, __int64 e )  //  eval diff
{
  static char es[272];
  __int64 d, v;
  QueryPerformanceFrequency( (LARGE_INTEGER *)&v );
  d = (( e - s ) * 1000 ) / v;
  sprintf( es, "%d ms.", (int)d );
  return( es );
}
---------------------------------- loopvec.h ----
class loopvec
{
public:
  int * m_vec;
  int * m_cnt_vec;
  int m_nSize;
  bool m_done;
  loopvec( int * pvec, int size_by_int )
  {
    m_vec = new int[size_by_int];
    m_cnt_vec = new int[size_by_int];
    memcpy( m_vec, pvec, sizeof(int)*size_by_int );
    memcpy( m_cnt_vec, pvec, sizeof(int)*size_by_int );
    m_nSize = size_by_int;
    m_done = false;
  }
  ~loopvec()
  {
    delete m_vec;
  }
  operator bool()
  {
    int c;
    for( c = 0; c < m_nSize; c ++ )
    {
      if( ++m_cnt_vec[c] >= m_vec[c] )
      {
        m_cnt_vec[c] = 0;
      }
      else
      {
        return( true );
      }
    }
    if( m_done ) return( false );
    m_done = true;
    return( true );
  }
  operator []( int c )
  {
    if( c < m_nSize )
    {
      return( m_cnt_vec[c] );
    }
    else
    {
      return( 0 );
    }
  }
};
-------------------------------


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加