2012-03-06 11 views
1

"最適化コード"オプションがオフの場合は正常に動作するC#コードがありますが、それ以外の場合は失敗します。関数やクラスの最適化を妨げる関数やクラスの属性はありますか?C#コンパイラ "コードを最適化する":コードフラグメントのみを無効にする

(私は成功せず、安全ではないかMethodImpl試してみました)

おかげ

編集:

double arg = (Math.PI/2d - Math.Atan2(a, d)); 
:私はいくつかのより多くのテストを行っている
を... コードは次のようです

a = 1かつd = 0の場合、argは0にする必要があります。 ThidコードはExcelDNA経由でExcelから呼び出される関数です。 OK

最適化せずにExcelから、このコードを呼び出す:OK

最適化を使用してExcelから、このコードを呼び出す:OKではない、のarg == 0が偽である(最適化されたアプリのコンソールから同じコードを呼び出す

代わりにargは0に近い非常に小さな値ですが0ではありません)

呼び出された関数の前に[MethodImpl(MethodImplOptions.NoOptimization)]と同じ結果が返されます。

+1

「失敗」とはどういう意味ですか?あなたは例外を取得しますか、それはゆっくり実行するのでしょうか?コードの機能は最適化されても変更されるべきではありません。 – Botz3000

+6

最適化を有効にしたときにエラーが発生した場合は、間違っている可能性があります...コードを投稿してください! –

+0

'MethodImpl.NoOptimization'を試してもまだ失敗している場合は、あなたの問題が最適化であると疑います。いくつかのコードを投稿してください。 –

答えて

2

これは浮動小数点データ型を扱うときに得られるものです。厳密に0は得られませんが、非常に近い値です。これは、倍精度の精度が限られているため、すべての値を表現することができない場合もあります。あなたはそれを期待する必要があります(値が、十分にから0に近いことを確認してください)。

+0

'decimal'や' int'を 'Math.Atan2'と一緒に使うのは意味がありません。 'decimal'を使うと、魔法のように無限の精度を与えることはできません。ちょうど小数部分を正確に表現できます。 – svick

+0

Decimalは無限の精度をいつ提供するのですか?また、それは彼がそれでやりたいことに依存します。結果は非常に小さい値であり、不正確さについては何もできません。 0のように定数を2倍にすることは、しばしばこのようなバグにつながります。 – Botz3000

+0

はい、 'double'を使うとそのようなバグにつながります。しかし、どのように 'decimal'を使うのが助けになりますか? – svick

2

これは、Excelが設定している可能性が高いfloating point modeと非常によく似ています。これは、アセンブリ(DLL)をホストしているプログラム(Excel)によってプログラムが浮動小数点数をわずかに差し引いていることを意味します。これは、結果がどのように計算されるか、またはどのような値が自動的に0に強制的に強制されるかに影響を与える可能性があります。

異なる浮動小数点モードおよび/またはエラーの問題に遭遇することは絶対に避けてください。値が非常に近いかどうかをチェックすることで、等価性を確認する必要があります。 This is not really a hack.

public class AlmostDoubleComparer : IComparer<double> 
{ 
    public static readonly AlmostDoubleComparer Default = new AlmostDoubleComparer(); 
    public const double Epsilon = double.Epsilon * 64d; // 0.{322 zeroes}316 

    public static bool IsZero(double x) 
    { 
     return Compare(x, 0) == 0; 
    } 

    public static int Compare(double x, double y) 
    { 
     // Very important that cmp(x, y) == cmp(y, x) 
     if (Double.IsNaN(x) || Double.IsNaN(y)) 
      return 1; 
     if (Double.IsInfinity(x) || Double.IsInfinity(y)) 
      return 1; 

     var absX = Math.Abs(x); 
     var absY = Math.Abs(y); 
     var diff = absX > absY ? absX - absY : absY - absX; 
     if (diff < Epsilon) 
      return 0; 
     if (x < y) 
      return -1; 
     else 
      return 1; 
    } 

    int IComparer<double>.Compare(double x, double y) 
    { 
     return Compare(x, y); 
    } 
} 

// E.g. 
double arg = (Math.PI/2d - Math.Atan2(a, d)); 
if (AlmostDoubleComparer.IsZero(arg)) 
    // Regard it as zero. 

(それはより一貫大きな値を扱う)私はまた、再解釈した整数の比較を移植した場合には、あなたはそれがより適切な見つけます。

public class AlmostDoubleComparer : IComparer<double> 
{ 
    public static readonly AlmostDoubleComparer Default = new AlmostDoubleComparer(); 
    public const double MaxUnitsInTheLastPlace = 3; 

    public static bool IsZero(double x) 
    { 
     return Compare(x, 0) == 0; 
    } 

    public static int Compare(double x, double y) 
    { 
     // Very important that cmp(x, y) == cmp(y, x) 
     if (Double.IsNaN(x) || Double.IsNaN(y)) 
      return 1; 
     if (Double.IsInfinity(x) || Double.IsInfinity(y)) 
      return 1; 

     var ix = DoubleInt64.Reinterpret(x); 
     var iy = DoubleInt64.Reinterpret(y); 
     var diff = Math.Abs(ix - iy); 
     if (diff < MaxUnitsInTheLastPlace) 
      return 0; 

     if (ix < iy) 
      return -1; 
     else 
      return 1; 
    } 

    int IComparer<double>.Compare(double x, double y) 
    { 
     return Compare(x, y); 
    } 
} 

[StructLayout(LayoutKind.Explicit)] 
public struct DoubleInt64 
{ 
    [FieldOffset(0)] 
    private double _double; 
    [FieldOffset(0)] 
    private long _int64; 

    private DoubleInt64(long value) 
    { 
     _double = 0d; 
     _int64 = value; 
    } 

    private DoubleInt64(double value) 
    { 
     _int64 = 0; 
     _double = value; 
    } 

    public static double Reinterpret(long value) 
    { 
     return new DoubleInt64(value)._double; 
    } 

    public static long Reinterpret(double value) 
    { 
     return new DoubleInt64(value)._int64; 
    } 
} 

また、あなたがしようとNGenアセンブリを、あなたはExcelが持っているモード、またはどのようにそれがCLRをホストしているのいずれかを回避することができるかどうかを確認できます。

+0

"これはExcelが設定している可能性の高い浮動小数点モードと非常に関係があります" =>リンクのおかげで、私はそれをチェックします。 – Poca

+1

@Pocaもしあなたが期待しているものに戻ってしまうと(デフォルトとはどういうことか分かりません)、Excelを混乱させる可能性があることを覚えておいてください。 –

関連する問題