CでCSVにデータセットをエクスポートする

Cの基礎を学んだばかりで、講師から提供されたデータセットを読み取り、それをCSVにエクスポートする作業プログラムを構築しました。

しかし、必要な列(x、y、z)にデータ値を表示するだけで、これが単純化されたものになる可能性があると彼は述べました。しかし、私の設定でそれがどのように機能するかはわかりません。

これは私の初めてのコーディングです(私は健康の学生です)と少し圧倒されています。私が言ったように、私は自分のコードを見直すこと、そしてそれをもっと単純にして値を 'プリントアウト'するだけの方法が欲しいのです。

create_CSVint main は自分で作成しますが、 gen_sally は講師が作成します。

#include
#include
#include
#include

void gen_sally( int xs, int ys, int zs, int time, float *sally )
/*
 *  Gen_Sally creates a vector field of dimension [xs,ys,zs,3] from
 *  a proceedural function. By passing in different time arguements,
 *  a slightly different and rotating field is created.
 *
 *  The magnitude of the vector field is highest at some funnel shape
 *  and values range from 0.0 to around 0.4 (I think).
 *
 *  I just wrote these comments, 8 years after I wrote the function.
 *  
 *  Developed by Sally of Sally University
 *
 */
{
  float x, y, z;
  int ix, iy, iz;
  float r, xc, yc, scale, temp, z0;
  float r2 = 8;
  float SMALL = 0.00000000001;
  float xdelta = 1.0/(xs-1.0);
  float ydelta = 1.0/(ys-1.0);
  float zdelta = 1.0/(zs-1.0);

  for( iz = 0; iz < zs; iz++ )
  {
     z = iz * zdelta;                       //map z to 0->1
     xc = 0.5 + 0.1*sin(0.04*time+10.0*z);  //For each z-slice, determine the spiral circle.
     yc = 0.5 + 0.1*cos(0.03*time+3.0*z);   //   (xc,yc) determine the center of the circle.
     r = 0.1 + 0.4 * z*z + 0.1 * z * sin(8.0*z);// The radius also changes at each z-slice.
     r2 = 0.2 + 0.1*z;                          //   r is the center radius, r2 is for damping
     for( iy = 0; iy < ys; iy++ )
     {
        y = iy * ydelta;
        for( ix = 0; ix < xs; ix++ )
        {
            x = ix * xdelta;
            temp = sqrt( (y-yc)*(y-yc) + (x-xc)*(x-xc) );
            scale = fabs( r - temp );
/*
 *  I do not like this next line. It produces a discontinuity 
 *  in the magnitude. Fix it later.
 *
 */
           if ( scale > r2 )
              scale = 0.8 - scale;
           else
              scale = 1.0;
            z0 = 0.1 * (0.1 - temp*z );
           if ( z0 < 0.0 )  z0 = 0.0;
           temp = sqrt( temp*temp + z0*z0 );
            scale = (r + r2 - temp) * scale/(temp + SMALL);
            scale = scale/(1+z);
           *sally++ = scale * (y-yc) + 0.1*(x-xc);
           *sally++ = scale * -(x-xc) + 0.1*(y-yc);
           *sally++ = scale * z0;
        }
     }
  }
}


void create_csv(char* filename,float *sally, int size){

    printf("1");

    printf("\n Creating %s.csv file",filename);

    FILE *fp;

    fp=fopen(filename,"w");

    fprintf(fp,"X,Y,Z\n");
    int i;
    int counter = 0;

    for(i = 0; i< size; i++){
        if(sally[i] == 0){
            fprintf(fp,"0");
        } else {
            fprintf(fp,"%f",sally[i]);
        }
            counter++;
            if(counter == 3){
                fprintf(fp, "\n");
                counter = 0;
        } else {
            fprintf(fp,",");
        }
    }

    fclose(fp);
    printf("\n %sfile created",filename);
}


int main(int argc, char *argv[]){

    printf("1\n");
    //read from args
    int xs;
    int ys;
    int zs;
    int time;
    sscanf(argv[1],"%d",&xs);
    sscanf(argv[2],"%d",&ys);
    sscanf(argv[3],"%d",&zs);
    sscanf(argv[4],"%d",&time);//Is a constant, will always be reads as 1


    int arraySize = xs*ys*zs*1;

    //allocate memeory for array. This is done so that stack memory doesn't run out.'
    float* sally;
    sally = (float*)malloc((arraySize) * sizeof(float));

    //runs the code. One of the args is a pointer so no return type is needed. 
    gen_sally(xs,ys,zs,time,sally);

    //create varibles for file generation
    char filename[20] = "results.csv";
    create_csv(filename, sally, arraySize);

    free(sally);
    return 0;
}
4
nl ru de
create_sally 関数がないので、おそらく create_csv を意味します。
追加された 著者 Scott Olson,
ありがとうございました。それでも私の質問では役に立ちません。
追加された 著者 Tom,

4 答え

main()には以下の行があります。

    int arraySize = xs*ys*zs*1;

1の倍数ならそれ自体なので、1を掛ける理由はありません。

create_csv()関数では、変数 counter は不要です。代わりに、モジュロ演算子を使用して変数 i を使用できます。

    if (i % 3) {
        fprintf(fp, ",");
    }
    else {
        fprintf(fp, "\n");
    }

これの代替の単純化は次のようになります。

    fprintf(fp, "%c",  (i % 3)? ',' : '\n');

また、 create_csv()では、2つではなく1つの printf()ステートメントを使用することもできます。

    printf("1\n Creating %s.csv file\n", filename);

main()では、 malloc()のより良いプログラミング方法は

sizeof *sally

のではなく

sizeof(float)

because the type of sally may change at some point; by using *sally only one line of code needs to change のではなく multiple lines of code. The cast of the result from malloc() is not necessary.

    float* sally;
    sally = malloc((sizeof *sally) * arraySize);

このコードは疑問です:

    if (sally[i] == 0) {
        fprintf(fp, "0");
    }
    else {
        fprintf(fp, "%f", sally[i]);
    }

整数のゼロとfloat変数を比較しているので、比較に0.0を使用する方が安全かもしれません。現在のコードはすべてのコンピュータで正しく機能しない可能性があります。

0 としてゼロ値を書き込むことが要件でしたか?そうでなければ、コードはさらに単純化することができます。

void create_csv(char* filename, float *sally, int size) {
    printf("1\n Creating %s.csv file\n", filename);

    FILE *fp;

    fp = fopen(filename, "w");

    fprintf(fp, "X,Y,Z\n");
    int i;

    for (i = 0; i < size; i++) {
        fprintf(fp, "%f%c", sally[i], (i % 3) ? ',' : '\n');
    }

    fclose(fp);
    printf("\n %sfile created", filename);
}
2
追加された
私はいくつかのマイナーな編集をしました、そして私は sizeof による乗算についても変更しました - 最初に sizeof を置くことは良い習慣です。積(積は左に関連し、中間は少なくとも size_t であることが望ましいため)。
追加された 著者 Toby Speight,
「現在のコードはすべてのコンピュータで正しく動作しない可能性があります」に同意しないコンパイラーは、 00.0f に変換してから比較を行います。
追加された 著者 Philip Robey,

入出力操作が成功したかどうかを常に確認する

このようなコードは問題があります。

FILE *fp = fopen(filename, "w");
fprintf(fp,"X,Y,Z\n");

ファイルを開けなかった場合は、 fp にNULLポインタが割り当てられます。私たちが本当に不運であるならば、プログラムはそれを fprintf()に渡しても生き残ります、そして我々はデータが保存されなかったという表示を 与えません。データが安全に保存されているとユーザーが判断した場合、それは深刻な問題になる可能性があります。

同様に、読み込んだ値を使用する前に、引数に対して sscanf()の戻り値を使用する必要があります。 (代わりの方法 - strtoul()または strtoul()を検討してください。有効な数字の後にがらくたがないことを確認できます)。

1
追加された

float v double

変数は float だが定数( 0.40.1 、...)と関数( sin()、cos())は二重です。全体を通して float または double を使用するほうが一貫性があります。

 float xc, time, z;
 xc = 0.5f + 0.1f*sinf(0.04f*time + 10.0f*z); 
//or 
 double xc, time, z;
 xc = 0.5 + 0.1*sin(0.04*time + 10.0*z); 

精度対スピード

hypot() is usual more accurate, although sometime slower than posted code.

temp = sqrt( (y-yc)*(y-yc) + (x-xc)*(x-xc) );
// Alternative: 
temp = hypot(y-yc, x-xc);
temp = hypotf(y-yc, x-xc); //using float only.

%f v%g

浮動小数点数には浮動点があることを思い出してください。 "%f" では、大きな数字は不要な文字を多く含み、小さな数字は 0.000000 を印刷します。固定小数点フォーマットよりも先頭の数字を印刷する方が有益です(特にデバッグ中)。 "%g" または "%e" を使用することをお勧めします。

// fprintf(fp,"%f",sally[i]);
fprintf(fp,"%g",sally[i]);
0
追加された

矛盾/間隔不足

しないでください、 0.1 + 0.4 * z * z + 0.1 * z * sin(8.0 * z); 、すべての数学演算子をどこでもスペースで囲んでください。ランダムな場所だけではありません。

Comments

関数定義とその本体との間にコメントの壁を追加しないでください。読むのは本当に難しいです。通常、関数は関数定義の前にコメント化されているので、...以下が推奨されます。

/*
*  Gen_Sally creates a vector field of dimension [xs,ys,zs,3] from
*  a proceedural function. By passing in different time arguements,
*  a slightly different and rotating field is created.
*  @param[in] 
*  ...
*  @param[out]
*/
void gen_sally(int xs, int ys, int zs, int time, float *sally)

以下のコメントも読むのが面倒です:

 z = iz * zdelta;                       //map z to 0->1
 xc = 0.5 + 0.1*sin(0.04*time+10.0*z);  //For each z-slice, determine the spiral circle.
 yc = 0.5 + 0.1*cos(0.03*time+3.0*z);   //   (xc,yc) determine the center of the circle.
 r = 0.1 + 0.4 * z*z + 0.1 * z * sin(8.0*z);// The radius also changes at each z-slice.
 r2 = 0.2 + 0.1*z;                          //   r is the center radius, r2 is for damping

改行など。変数の名前を変えないようにしましょう。そして実際のコードの前に起こることすべてを説明しますか?

健全性チェック

NULLポインタ、無効な値などをチェックしていないあなたの関数はどれも失敗してエラーを返すことはできません。

0
追加された
すみません、その部分を逃しました:)
追加された 著者 Bill,
入力をありがとう、しかし私が質問で言ったように、あなたがコメントしているコードの部分は私の講師です。私の下にあるように、それは私が改善したいコードです。
追加された 著者 Tom,