「.NETのfloat.Epsilon定数は計算機イプシロンではない」の版間の差分

提供: MonoBook
ナビゲーションに移動 検索に移動
imported>Administrator
imported>Administrator
 
16行目: 16行目:
 
https://oku.edu.mie-u.ac.jp/~okumura/algo/
 
https://oku.edu.mie-u.ac.jp/~okumura/algo/
  
速攻で[[C言語]]からC#に[[移植]]した(ほぼ[[コピペ]]しただけ)。<source lang="csharp">
+
速攻で[[C言語]]からC#に[[移植]]した(ほぼ[[コピペ]]しただけ)。
 +
 
 +
<syntaxhighlight lang="csharp">
 
     using System;
 
     using System;
  
46行目: 48行目:
 
         }
 
         }
 
     }
 
     }
</source>
+
</syntaxhighlight>
  
計算機イプシロンの定番の[[アルゴリズム]]といえば、変数をひたすら2で割り続け、ゼロになった瞬間のひとつ前を捉えるというもの。「1以上」という条件はコンピューターの指数と仮数の組み合わせで表現される浮動小数点数では、1未満だと指数部だけを使ってどこまでも小さくなってしまうためであり、なんとしても仮数部を使おうということらしい。<source>
+
計算機イプシロンの定番の[[アルゴリズム]]といえば、変数をひたすら2で割り続け、ゼロになった瞬間のひとつ前を捉えるというもの。「1以上」という条件はコンピューターの指数と仮数の組み合わせで表現される浮動小数点数では、1未満だと指数部だけを使ってどこまでも小さくなってしまうためであり、なんとしても仮数部を使おうということらしい。
 +
<syntaxhighlight lang="csharp">
 
         static double MachineEpsilon()
 
         static double MachineEpsilon()
 
         {
 
         {
61行目: 64行目:
 
             return eps;
 
             return eps;
 
         }
 
         }
</source>
+
</syntaxhighlight>
  
 
== 備考 ==
 
== 備考 ==
 
実行環境(主に[[CPU]]の違い)により計算結果が変化する点に注意すること。
 
実行環境(主に[[CPU]]の違い)により計算結果が変化する点に注意すること。
[[アーキテクチャ]]がいっぱい[[ARM]]が主体の[[Xamarin]]系は要注意。
+
[[アーキテクチャ]]がいっぱいある[[Xamarin]]系は要注意。
  
 
[[category: .NET]]
 
[[category: .NET]]
 
[[category: Mono]]
 
[[category: Mono]]
 
[[category: Xamarin]]
 
[[category: Xamarin]]

2018年8月14日 (火) 02:46時点における最新版

C#においてfloat型(Single型)の絶対値をfloat.Epsilon定数と比較している箇所の挙動がどうもおかしい。

原因[編集 | ソースを編集]

ググってMSDNを見るとサラッと絶望的なひとことメモが。

The value of the F:System.Single.Epsilon property is not equivalent to machine epsilon, 
which represents the upper bound of the relative error due to rounding in floating-point arithmetic.
https://msdn.microsoft.com/ja-jp/library/system.single.epsilon(v=vs.110).aspx

要約すると「浮動小数点演算の丸の相対誤差の上限(丸め誤差発生時にズレるであろう最大値)」であり「計算機イプシロン」ではない。

まじかよ。名前紛らわしすぎだろ。

解決[編集 | ソースを編集]

「奥村晴彦『C言語による最新アルゴリズム事典』技術評論社,1991年,ISBN4-87408-414-1,2400円」という書籍に計算機イプシロンを動的に求めるアルゴリズムが詳細に解説されており、またソースコードは公式サイトにおいても配布されている。この本は非常に面白いので迷わず買え。個人的にはこの手の技術書を買う際に目次と技術評論社という名前だけで信頼して買うようになった一冊である。

https://oku.edu.mie-u.ac.jp/~okumura/algo/

速攻でC言語からC#に移植した(ほぼコピペしただけ)。

    using System;

    class MainClass
    {
        static float Foo(float x) { return x; }

        static float MachineEpsilon()
        {
            int b, p;
            float x, y, eps;

            x = y = 2;
            while (Foo(x + 1) - x == 1) x *= 2;
            while (Foo(x + y) == x) y *= 2;
            b = (int)(Foo(x + y) - x);
            p = 1; x = b;
            while (Foo(x + 1) - x == 1) { p++; x *= b; }
            eps = 1;
            while (Foo(1 + eps / 2) > 1) eps /= 2;
            eps = Foo(1 + eps) - 1;

            return eps;
        }

        public static void Main(string[] args)
        {
            Console.WriteLine("epsilon = {0}", MachineEpsilon());
        }
    }

計算機イプシロンの定番のアルゴリズムといえば、変数をひたすら2で割り続け、ゼロになった瞬間のひとつ前を捉えるというもの。「1以上」という条件はコンピューターの指数と仮数の組み合わせで表現される浮動小数点数では、1未満だと指数部だけを使ってどこまでも小さくなってしまうためであり、なんとしても仮数部を使おうということらしい。

        static double MachineEpsilon()
        {
            double eps = 1.0d;

            do
            {
                eps /= 2.0d;
            }
            while ((double)(1.0 + eps) != 1.0);

            return eps;
        }

備考[編集 | ソースを編集]

実行環境(主にCPUの違い)により計算結果が変化する点に注意すること。 アーキテクチャがいっぱいあるXamarin系は要注意。