我有一个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)]相同的结果。
答案 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。