• 締切済み

C言語のファイル入力とif文

あるcsvファイルから波形を読み込み、それを配列に格納しています。 (これは先日質問したもので、以下URLにおけるNo.4様の回答を参考にしています。 http://okwave.jp/qa/q7521134.html) csvファイルの中身は左が時刻[ms]、右が電圧値[V]で、 0.001 0.14 0.002 0.32 0.003 0.46 ・ ・ 2.000 0.22 という風になっています。 このプログラムはシミュレーションを行っており、「計算上の時刻」と「csvファイルにおける時刻」が 一致したときの時刻の「csvファイルの電圧値」を計算でも使用したいと考えています。 例えば計算上で時刻0.003[ms]になったら0.32[V]、2[ms]になったら0.22[V]といった風に 値を取り出したいです。 どなたか詳しい方、回答・アドバイス等よろしくお願いいたします。

みんなの回答

  • jjk65536
  • ベストアンサー率59% (66/111)
回答No.2

popenで手抜きする方法もあります。 処理速度上は不利ですので、多少遅くても問題ない場合に限りますが さっさと動かしたい場合などに有用です。 たとえば時刻から電圧値を取得する関数を float getv(float time); というように作るとします。 内部実装をpopenでごまかす場合、例えば以下のように書けます。 #include <stdio.h> float getv(float time) {  float v;  char cmd[BUFSIZ];  sprintf(cmd, "grep '^%.3f' data.csv", time);  FILE *fd;  fd = popen(cmd, "r");  fscanf(fd, "%f %f", &time, &v);  close(fd);  return v; } int main(int argc, const char *argv[]) {  float v = getv(0.002);  printf("%f\n", v);  return 0; } 上記例はLinuxではそのまま動きますが、他のOSの場合はgrepなどを用意する必要があります。

回答No.1

時刻[ms]の値の性質がわからないので、方針が定まりませんが、自分だったら時刻の性質に応じてこのどれかを使いますね。 1. 時刻が必ず0.001[ms]刻みであることがわかっている場合 O(1) 0.001[ms]と配列の添え字が一対一対応する配列を作成し、そこにデータを入れる。 例えば、2.000[ms]が最大だったら、2001個の要素を持つ配列を作り、voltage[2001]; 0.012はvoltage[12]を参照する。 ここで、0.000[ms]がないのにvoltage[0]を作るのは時刻と配列が一対一対応したほうがわかりやすいと思ったからです。 2. 計算で使うときの時刻はきっかりその値を要求して、ブレがない場合 O(1) (動作しない可能性が高いので非推奨。しかしながら、うまくハマると3.よりは高速なはず) BerkeleyDBでDB_HASHなメモリーDBを作ってそこにデータを入れ、それを参照。 Keyとして時刻の値を、Valueとして電圧値の値をそれぞれバイト列だと思って入れます。 例えば、計算の時に0.002という値を確実に要求して、0.0021などは要求しない場合にのみ使えますが、浮動小数点値を入れるのでかなり不安ですね。 3. CSVファイルの時刻は0.001[ms]きざみであり、計算で使う時刻にブレがないか、計算で使う時の時刻が0.001[ms]以下のブレがある場合 O(log N) CSVファイルのデータを読み、時刻と電圧値をもった構造体の配列に入れます。それから、時刻順にソートして、電圧値を取るたびに二分探索します。 CではC90準拠の標準ライブラリーにqsortとbsearchはあるので、それを使えば簡単に作れるはずです。 qsortに与えるcomparは単純に大小で-1、1を返すようにして、 bsearchにcomparで与える関数は二値を引いた結果で-1、0、1を返すようにして、引いいた時の差が一定 (0.0005ms?) 以下なら0を返すようにしたほうが良いでしょう。 4. CSVファイルの時刻が0.001[ms]きざみでなく、値がなかったら前の値や後の値を使って欲しい場合 つまり、CSVファイルにある時刻では0.002と0.005の値しかない場合に0.003が来たら0.002の値を使いたいような場合。 O(log N) 上記3のcomparの条件では引いた時の差がその値に合致しないと発見できなかったことになるので、3の手順のところのbsearchの自作が必要です。 bsearchのソースコードはどこかのライブラリーのを使い、見つからなかった場合にNULLを返すところで比較に使っていた値を返すという工夫をすればよいでしょう。 例えば、FreeBSDのlibcにあるbsearchだと、pとその前後の値を見てNULLの代わりにほしいものを返すように書き換えるとよいでしょう。 http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdlib/bsearch.c?rev=1.4.10.1.8.1;content-type=text%2Fplain 5. それ以外の場合 (何らかの理由でソートできない場合も含む) O(N) CSVファイルのデータを読み、時刻と電圧値をもった構造体の配列に入れます。 配列の頭から順に条件に合う時刻がないか探します。 配列の要素をソートする必要もなく、一番簡単な実装です。 この場合でも、最近使われた時刻と電圧値のペアを覚えておくことで多少は性能が良くなるかもしれません。 1から5はおすすめの順に並べていますが、時刻の性質によって取れないアルゴリズムも多数ありますので。