C#编译器“优化代码”:仅禁用代码片段

时间:2012-03-06 17:23:33

标签: c# compiler-optimization

我有一个C#代码,当“优化代码”选项关闭时效果很好,但是否则失败。是否有任何函数或类属性可以阻止函数或类的优化,但让编译器优化其他属性?

(我尝试过不安全或MethodImpl,但没有成功)

由于

修改: 我做了一些测试...... 代码是这样的:

double arg = (Math.PI / 2d - Math.Atan2(a, d)); 

a = 1且d = 0时,arg应为0。 该代码是Excel通过ExcelDNA调用的函数。

从优化的控制台应用程序调用相同的代码:确定

在没有优化的情况下从Excel调用此代码:确定

使用优化从Excel调用此代码:不行,arg == 0为false(而arg是一个非常小的值,接近0,但不是0)

与被调用函数之前的[MethodImpl(MethodImplOptions.NoOptimization)]相同的结果。

2 个答案:

答案 0 :(得分:2)

这是使用浮点数据类型时的结果。你得到的确不是0,而是一个非常接近的值,因为double的精度有限,并不是每个值都可以表示,有时那些微小的精度误差会加起来。您需要预期(检查值足够为0)。

答案 1 :(得分:2)

这很可能与Excel可能设置的floating point mode有关 - 这意味着您的程序计算的浮点略有不同,因为程序(Excel)托管程序集(DLL)。这可能会影响结果的计算方式,或者如何/将值自动强制为零。

为了确保您不会遇到不同浮点模式和/或错误的问题,您应该检查是否相等,而不是通过检查值是否非常接近。 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。

相关问题