構造体の配列: Sample 1: 構造体のメンバーのコピー(C)

高速化プログラミング   
トップ  >  メモリジャンプと高速化  >  構造体の配列  >  Sample 1: 構造体のメンバーのコピー(C)

構造体の配列: Sample 1: 構造体のメンバーのコピー(C)

言語の変更:   FORTRAN版

■ 概要

ここでは構造体のあるメンバーの配列を別の配列にコピーするサンプルを示します。

Code 1は配列の構造体のサンプルです。配列a, b, c, d, e, f, g, hをメンバーとするVectorという構造体を定義します。Vector型のvecを宣言してからそれぞれのメンバーの配列を長さnでメモリの確保をします。メイン計算ではメンバーの配列aを別の配列rにコピーをします。

Code 2は構造体の配列のサンプルです。a, b, c, d, e, f, g, hをメンバーとするVectorという構造体を定義します。Vector型の配列vecを長さnでメモリの確保をします。Code 1と同様にメイン計算ではメンバーの配列aを別の配列rにコピーをします。

配列の長さnとして2,000,000から40,000,000まで20個の値を用いて、Code 1Code 2のメイン計算にかかる時間を測定して出力します。

■ ソースコード


  ◆ Code 1   ◆ Code 2
 
// Program to copy a member of a structure to another array
#include <stdio.h>
#include <time.h>

struct Vector {
  double *a, *b, *c, *d, *e, *f, *g, *h;
};

int main()
{
  int i, k, n;
  Vector vec;
  double *r;
  printf("Array size    Elapsed time [sec] \n");

  for (int k=1; k<=20; k++) {
    // Array size
    int n = k * 2000000;

    // Allocation
    r = new double[n];
    vec.a = new double[n]; vec.b = new double[n];
    vec.c = new double[n]; vec.d = new double[n];
    vec.e = new double[n]; vec.f = new double[n];
    vec.g = new double[n]; vec.h = new double[n];

    // Initialization
    for (i=0; i<n; i++) {
      vec.a[i] = 1.0;
      vec.b[i] = 1.0;
      vec.c[i] = 1.0;
      vec.d[i] = 1.0;
      vec.e[i] = 1.0;
      vec.f[i] = 1.0;
      vec.g[i] = 1.0;
      vec.h[i] = 1.0;
    }

    // Start time
    clock_t time0 = clock();

    // Main calculation: copy the member a to r
    for (i=0; i<n; i++)
      r[i] = vec.a[i];

    // Finish time
    clock_t time1 = clock();

    // Output time
    double time = (double)(time1-time0)/CLOCKS_PER_SEC;
    printf("%11d %15.7f\n",n, time);

    // Deallocation
    delete[] r;
    delete[] vec.a; delete[] vec.b;
    delete[] vec.c; delete[] vec.d;
    delete[] vec.e; delete[] vec.f;
    delete[] vec.g; delete[] vec.h;
  }
  return 0;
}

    
 
// Program to copy a member of a structure to another array
#include <stdio.h>
#include <time.h>

struct Vector {
  double a, b, c, d, e, f, g, h;
};

int main()
{
  int i, k, n;
  Vector *vec;
  double *r;
  printf("Array size    Elapsed time [sec] \n");

  for (int k=1; k<=20; k++) {
    // Array size
    int n = k * 2000000;

    // Allocation
    r = new double[n];
    vec = new Vector[n];




    // Initialization
    for (i=0; i<n; i++) {
      vec[i].a = 1.0;
      vec[i].b = 1.0;
      vec[i].c = 1.0;
      vec[i].d = 1.0;
      vec[i].e = 1.0;
      vec[i].f = 1.0;
      vec[i].g = 1.0;
      vec[i].h = 1.0;
    }

    // Start time
    clock_t time0 = clock();

    // Main calculation: copy the member a to r
    for (i=0; i<n; i++)
      r[i] = vec[i].a;

    // Finish time
    clock_t time1 = clock();

    // Output time
    double time = (double)(time1-time0)/CLOCKS_PER_SEC;
    printf("%11d %15.7f\n",n, time);

    // Deallocation
    delete[] r;
    delete[] vec;



  }
  return 0;
}

    

■ 計算時間の測定結果

Code 1Code 2を実行したときの計算時間をそれぞれ青線と赤線で図1に示します。そして両者の比を緑線で示します。

測定時間
図1 測定時間

■ 考察

Code 1の配列の構造体では配列のメンバーが連続的に配置されているので、構造体のメンバー、配列aにアクセスするときはメモリのジャンプは起こりません(図2を参照)。一方、Code 2の構造体の配列では構造体の同じメンバーは不連続に配列されているので、このサンプルでは図3のようにメモリのジャンプが起こります。

Code 1のときのメモリアクセス
図2 Code 1のときのメモリアクセス
Code 2のときのメモリアクセス
図3 Code 2のときのメモリアクセス

図1の実測ではCode 1Code 2より計算時間が2~3倍速いです。2次元配列のときよりは倍率が低いですが、構造体のメンバーの個数(サイズ)によっては倍率がもっと上がる可能性があります。



はじめに

演算数を減らす

メモリジャンプを減らす

高性能のアルゴリズム

その他



4 8 5 5 5 3