スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

F#入門初級編第3回(units of measure(1))

今回のお題は「units of measure(1)」です。
 
単位付きの数を対象にして、プログラミングしているとき、単位の変換を忘れて思わぬバグを招いたりすることがあります。
F#のunits of measureはfloat,float32,decimel,符号付きintを対象にして、単位を付加して値を取り扱うための仕組みです。
 
この仕組みを使うには、[<Measure>]属性を使用して、単位の型を次のように定義します。
 
[<Measure>]
type 単位名
 
たとえばセンチメートルをcmという記号であらわすことにすると次のようになります。
 
[<Measure>]
type cm
 
同様にメートルもmという記号で定義しておきます。
 
[<Measure>]
type m
 
さて使用する側では、数値<単位の型>という形で、追加情報である「単位の型」を付け加えます。
 
> let a = 3.0<m>;; //「数字の終わり」と「<」の間をあけないこと!
val a : float<m> = 3.0
 
> let b = 300.0<cm>;;
val b : float<cm> = 300.0
 
数値の型<単位の型>と表示されることに留意してください。
 
異なる単位同士の和、差はエラーになります。(これでバグが減らせます。)
 
> a+b;;
  a+b;;
  --^
 
C:\Users\T_GYOUTEN\AppData\Local\Temp\stdin(9,3): error FS0001: The unit of measure 'cm' does not match the unit of measure 'm'
 
> a-b;;
  a-b;;
  --^
C:\Users\T_GYOUTEN\AppData\Local\Temp\stdin(10,3): error FS0001: The unit of measure 'cm' does not match the unit of measure 'm'
 
「単位の型なしの数値」との積、商は次のようになります。
 
> a/3.00;;
val it : float<m> = 1.0
 
> 10.0*a;;
val it : float<m> = 30.0
 
それでは、同じ型同士の積、商の説明の前にいくつか値の型と値を定義しておきます。
 
[<Measure>]
type m //メートル
 
[<Measure>]
type cm //センチメートル
 
[<Measure>]
type s //秒
 
[<Measure>]
type kg //キログラム
 
let m3,m2,m1 = 3.0<m>,2.0<m>,1.0<m>;;
let cm3,cm2,cm1 = 300.0<cm>,200.0<cm>,100.0<cm>
let sec3,sec2,sec1 =3.0<s>,2.0<s>,1.0<s> 
 
まず単位の型がmのもの同士を掛け合わせてみます。
 
> m3*m2;;
val it : float<m ^ 2> = 6.0
 
単位がm^2というように、mを2個掛け合わせたものになっています。
このようにちゃんと単位も考え合わせてくれるのです。
(使用する方からみれば、これは平方メートルです。)

 
> m3/sec2;;
val it : float<m/s> = 1.5
 
> m3/m2;;
val it : float = 1.5 //比は単位なし
 
> m1*m2/m3;;
val it : float<m> = 0.6666666667 //単位が約分されている
 
 
上の二つの例をみても分かるように、単位の次元を考えてくれるということで、ここをチェックすることでもバグが減らせます。
 
> cm1*m1;;
val it : float<cm m> = 100.0
 
というようにもできますが、これなんかは、通常は使われていない単位になってしまいます。
(別に個人的に使ってもかまわないとは思いますが、混乱の元かも)
 
積の順番をかえても、きちんと上と同じ型だと判断してくれます。
> m1*cm1;;
val it : float<cm m> = 100.0
 
次に秒速vを10.0に設定したいとします。メートルを距離の尺度として採用するとすると、この場合
すでに定義済みのmとsを利用して次のように定義することができます。
 
> let v = 10.0<m/s>;;
val v : float<m/s> = 10.0
 
この速度で60秒間走ると走行距離は
 
> v * 60.0<s>;;
val it : float<m> = 600.0
 
と計算できます。
これは次のようにも定義できます。
 
> 10.0<m s^-1>;;
val it : float<m/s> = 10.0
 
加速度は速度(の増分)を時間で割ったものです。
 
> let a = v/1.0<s> ;;
val a : float<m/s ^ 2> = 10.0
 
<m/s ^ 2>ですが、これは次のものと同じです。
 
> 10.0<m / s / s>;;
val it : float<m/s ^ 2> = 10.0
 
> 10.0<m s^-2 >;; //掛け算記号の*は使わないことに留意してください。
val it : float<m/s ^ 2> = 10.0
 
すでに定義してある単位の型を用いて新しい型を定義できます。

 
[<Measure>]
type N = kg m s^-2
 
> let a = 1.0<N> ;;
val a : float<N> = 1.0
 
> let b = 2.0<kg m s^-2>;;
val b : float<kg m/s ^ 2> = 2.0
 
> let c = a+b;;
 
val c : float<N> = 3.0
 
> let e = b+a;;
 
val e : float<kg m/s ^ 2> = 3.0
 
同じ単位ですが、和の場合左辺の単位の方で、F#Interactiveには表示されるようです。
 
続く
スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

非公開コメント

No title

質問なんですが・
100cmが1mであるとか、そういう相互変換(定義)はできないのですか?
例えば、
let cm2m (x:int<cm>) = 1<m>*(int (x / 100))
のような関数を作らないとだめなんでしょうか?

No title

そうですね、後考えられる方法は、
例えば、センチメートルとメートルを相互変換したい場合なら

> let R_MtoCM = 100.0<cm/m>;;
val R_MtoCM : float<cm/m> = 100.0

とでも定義しておいて、

> let a = R_MtoCM * 1.0<m>;;
val a : float<cm> = 100.0

というようにするぐらいでしょうか。

後、よく使う単位系については、ライブラリとかもあるらしいですが、そのライブラリではどのように処理されているかはまだ調べていません。

またunits of measureについては私の知る限り次のブログが詳しいようです。
Andrew Kennedy's Blog
http://blogs.msdn.com/andrewkennedy/default.aspx

No title

> let R_MtoCM = 100.0<cm/m>;;
なるほど、コッチの方が気が利いてますね。
プロフィール

T GYOUTEN

Author:T GYOUTEN
F#と英単語とフリーソフトと読書に興味があります。
ホームページでフリーソフトも公開しています。どぞ御贔屓に。

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
フリーエリア
フリーエリア
blogram投票ボタン
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。