はじめに
X = 4.3 - 4.2 このとき、Xの値は?(後編)では、PowerShellとHaskellの連携による、小数どうしの計算方法を紹介した。
その後、iakioさんからのアドバイスで、Decimal型どうしの演算で誤差がなくせることが分かったので、関数化してみた。
せっかくなので、比較演算子の記号を分かりやすくしたり、%(パーセント)での計算も可能にしてみた。
定義
function Calculate-Expression([string]$Expression){
[string]$Expression_Parsed = `
(((((((( $Expression `
-replace '([\+\-\*\/\(\)])',' $1 ') `
-replace '%' ,' / 100 ') `
-replace '<=',' -le ') `
-replace '>=',' -ge ') `
-replace '!=',' -ne ') `
-replace '=' ,' -eq ') `
-replace '<' ,' -lt ') `
-replace '>' ,' -gt ').Split(" ") | `
ForEach{
$r = 0
if([Decimal]::TryParse($_,[ref]$r)){
[string]$r + 'd'
}else{
[string]$_
}
}
Invoke-Expression $Expression_Parsed
}
Set-Alias calc Calculate-Expression
使用例
calc "4.3 - 4.2" #誤差なく計算できる
#0.1
calc "4.3 - 4.2 = 0.1" #比較演算子を分かりやすく
#True
calc "50 * 80%" #パーセントでの計算もできる
#40
解説
1.PowerShell形式に変換+各項に分解
(((((((( $Expression `
-replace '([\+\-\*\/\(\)])',' $1 ') `
-replace '%' ,' / 100 ') `
-replace '<=',' -le ') `
-replace '>=',' -ge ') `
-replace '!=',' -ne ') `
-replace '=' ,' -eq ') `
-replace '<' ,' -lt ') `
-replace '>' ,' -gt ').Split(" ")
・文字列で渡ってきた計算式を、PowerShellで演算できる形式に変換(=⇒-eq、!=⇒-neなど)
・%は1/100を表す(例:90%=0.9)
・演算子の前後に半角スペースを付加
・計算式を各項に分解(Split関数)
例えば、式「1+2=3」は、以下のように分解される
1
+
2
-eq
3
2.数値をDecimal変換
ForEach{
$r = 0
if([Decimal]::TryParse($_,[ref]$r)){
[string]$r + 'd'
}else{
[string]$_
}
}
・項ごとにTryParse関数を使い、Decimal型への変換を行う
・Decimal型へ変換できる場合は、後ろにdを付ける(後でDecimal型として計算するため)
・上記以外はそのまま文字列を返す
例えば、式「1+2=3」は、以下のように変換される
1d
+
2d
-eq
3d
上記配列をstring型変数「$Expression_Parsed」に格納する
$Expression_Parsed
#1d + 2d -eq 3d
$Expression_Parsedを実行(計算)する
Invoke-Expression $Expression_Parsed
エイリアス(別名)を定義
Set-Alias calc Calculate-Expression
Calculate-Expression関数のエイリアスとしてcalcを指定。
※エイリアスの詳細についてはこちらを参照
おわりに
今回紹介した関数を応用すれば、例えば、ユーザがテキストボックスで入力した式を誤差なく計算したい場合に活用できるかもしれない。
そもそも、小数どうしの四則演算くらい、特に工夫しなくても正確に計算して欲しいところだが。