あらきけいすけのメモ帳

あらきけいすけの雑記帳2

ラグランジュ補間(2点を通る直線の公式)、単位の換算、そのプログラミングについての覚え

授業のための覚書

2点(x_0,y_0), (x_1,y_1)を通る直線の公式:\displaystyle y=\frac{x-x_1}{x_0-x_1}y_0+\frac{x-x_0}{x_1-x_0}y_1
これは Lagrange 補間(Lagrangian interpolation*1)と呼ばれる計算技法である。この式は次のようにも書ける:
2点(x_0,y_0), (x_1,y_1)を通る直線の公式:\displaystyle y=\frac{x-x_0}{x_1-x_0}(y_1-y_0)+y_0
「直線の式」だからって、この計算式の応用範囲が「直線を描画する」といったグラフィックスだけに限られるわけではない。例えば、摂氏温度*2から華氏温度*3への換算にも使える。水の氷点が(0度C,32度F), 沸点が(100度C,212度F)なので摂氏温度がc度のときの華氏温度の値は\displaystyle f=\frac{c-100}{0-100}32+\frac{c-0}{100-0}212になる。
ここで受験数学の答案のような「筆算にしばられた発想」だと、係数を整理してf=1.8c+32とまとめるところだが、プログラミングの世界では整理すべきでない。この換算をC言語コードで書くときは、次のように書くのがベター;

// マクロ, 関数形式マクロ
#define Cfleeze   (0.0)
#define Cboil   (100.0)
#define Ffleeze  (32.0)
#define Fboil   (212.0)
#define tempC2tempF(tempC) (tempC - Cfleeze)/(Cboil - Cfleeze)*(Fboil - Ffleeze) + Ffleeze
// 定数, 関数
float tempC2tempF (float tempC) {
  const float Cfleeze =  0.0, Cboil = 100.0;
  const float Ffleeze = 32.0, Fboil = 212.0;
  tempF = (tempC - Cfleeze)/(Cboil - Cfleeze)*(Fboil - Ffleeze)
          + Ffleeze;
  return tempF;
}

このコードならば「tempC=CfleezeのときにFfleeze」「tempC=CboilのときにFboil」の値を返す tempC の1次関数を計算していると分かる。ややこしい計算はコンピュータにやらせればよい。むしろ「何の計算をコンピュータにやらせているのかはっきり分かる」コードの方がベターである*4

演算数から考えると const を使って計算の定数を予め作っておいて*5、define で「インラインで計算」するのが早いかも:

// マクロ, 関数形式マクロ
// tempC2tempF(tempC) = (tempC - Cfleeze)/(Cboil - Cfleeze)
//                      *(Fboil - Ffleeze) + Ffleeze
#define Cfleeze   (0.0)
#define Cboil   (100.0)
#define Ffleeze  (32.0)
#define Fboil   (212.0)
const float
  tempC2tempFCoeff  = (Fboil - Ffleeze)/(Cboil - Cfleeze),
  tempC2tempFOffset = -(Cfleeze)*(Fboil - Ffleeze)/(Cboil - Cfleeze)
                      + Ffleeze;
#define tempC2tempF(tempC) ((tempC)*tempC2tempFCoeff + tempC2tempFOffset)

*1:ラグランジュ補間 - Wikipedia

*2:セルシウス度 - Wikipedia

*3:華氏 - Wikipedia

*4:プログラミングの世界では、いきなり数値をソースコードに書くことは「マジックナンバー」と呼ばれ、プログラムの可読性が悪くなるので避けるべきとされている。;マジックナンバー (プログラム) - Wikipedia可読性 - Wikipedia

*5:変数名は長くなってもよいから、計算で使うデータの内容を表示した方がよい。変数名の長さは、実際のCPU上で動くマシン語には影響しない。