読者です 読者をやめる 読者になる 読者になる

チリペヂィア

リンクフリー。サンプルコードなどは関連記事内でライセンスについて明示されない限り商用利用なども自由に行って構いませんが、自己責任でお願いします。またこれら日記内容の著作権自体は放棄していません。引用部分については引用元の権利に従ってください。

誤差を抑えてパーセント小数値を入力するテキストフィールド

そういやdecimalとかあったね!(ブクマを参照のこと)

テキストフィールドでfloatをパーセント入出力させる方法。浮動小数点って適当に100倍して100で割ると、わりと誤差が出ちゃうんですね。
例) 99.9 % と入力したら 99.899999999 % と表示される、など

doubleで逃げられないかと思いきや案外難しく、どうしたものか*1と見送っていたんですが、はてなでブクマした記事を読んでdecimalの存在を思い出しました。c#にはdecimalあるジャン!

private static System.Text.RegularExpressions.Regex regexPercentTextPerser =
    new System.Text.RegularExpressions.Regex("[\\+\\-]?(([0-9]*\\s*\\.\\s*[0-9]+)|([0-9]+))",
    System.Text.RegularExpressions.RegexOptions.Compiled | System.Text.RegularExpressions.RegexOptions.Singleline);

public static float PercentField(Rect position, GUIContent label, float value)
{
    System.String formattedText = System.Math.Round(((decimal)value * 100), 6).ToString();
    if (0 <= formattedText.IndexOf('.')) formattedText = (formattedText.TrimEnd(new char[] { '0' })).TrimEnd(new char[] { '.' });
    System.String getText = EditorGUI.TextField(position, label, formattedText + " %");
    decimal decimalValue = 0;
    if (decimal.TryParse(regexPercentTextPerser.Match(getText).Value.Trim(), out decimalValue)) decimalValue /= 100;
    return (float)decimalValue;
}

ここではRound(decimal)使って6桁でファジーにまるめています(近いほうに丸める、あまり二進数的でない人間的な丸め*2)。不必要な小数点とゼロ表示も切除します。正規表現はわりと適当。ややこしいから空白判定のところ無くても良いかな?

DBやらないせいかdecimalは忘れてしまいます。Access/ExcelVBAが流入してるんだから、.Netはdecimal完備してるっちゃそうなんですね。そうかそうかdecimalって幾何演算でもUIのコーディングに使えるのか。
そういやc++ってdecimalあったっけ???で思い出したんですが、cppreference.comのFloor()関数のページって、この↓
説明図を置いてくれるところが大好きです。ものすごく分かりやすい。

*1:固定小数点と文字列の相互変換の手作りとか面倒くさいよなー、と

*2:ちなみに6桁は適当な数値です。これ以上長く表示されてもウザいかなと。