与Math.Min或Math.Max短路进行比较
本文关键字:Math 比较 短路 Max Min | 更新日期: 2023-09-27 18:20:37
当与两个数字/函数的最小值或最大值进行比较时,如果第一个为真,那么C#是否短路,而第二个为真?这些情况的具体例子是
if(x < Math.Max(y, z()))
和
if(x > Math.Min(y, z()))
由于Math.Max(y, z())
将返回至少与y一样大的值;y,则不需要评估z(),这可能需要一段时间。与Math.Min
类似。
我意识到这两者都可以按照的思路重写
if(x < y || x < z())
为了短路,但我认为在不重写的情况下,比较更清楚。这会短路吗?
正如其他人所指出的,编译器对Min或Max的语义一无所知,这将允许它打破在调用方法之前对参数求值的规则。
如果你想写自己的,你可以很容易地做到:
static bool LazyLessThan(int x, int y, Func<int> z)
{
return x < y || x < z();
}
然后称之为
if (LazyLessThan(x, y, z))
或
if (LazyLessThan(x, y, ()=>z()))
或者就此而言:
static bool LazyRelation<T>(T x, T y, Func<T> z, Func<T, T, bool> relation)
{
return relation(x, y) || relation(x, z());
}
...
if (LazyRelation(x, y, ()=>z, (a,b)=> a < b)))
不,它不会短路,z()将始终被求值。如果你想要短路行为,你应该按照你所做的重写。
Math.Min()
和Math.Max()
是与其他方法一样的方法。必须对它们进行求值,才能返回将用作比较中第二个参数的值。如果您想要短路,则必须使用||
运算符编写条件,如您所演示的。
(没有什么特别新的添加,但我想我会分享我在上面运行的测试结果。)
Math.Max()可以很容易地被CLR的即时编译器内联,从那时起,我很好奇它是否可以以短路的方式进一步优化代码。
因此,我创建了一个微基准,分别对这两个表达式求值1000000次。对于z(),我使用了一个函数,该函数使用递归方法计算Fib(15)。以下是运行这两个程序的结果:
x < Math.Max(y, z()) : 8097 ms
x < y || x < z() : 29 ms
我猜CLR不会以任何阻止方法调用执行的方式转换代码,因为它不知道(也不检查)例程是否有任何副作用。
不,它不会短路,至少在C#编译器级别是这样。Math.Min
或Math.Max
是两个普通的静态方法调用,编译器不会在这个意义上进行优化。
代码的求值顺序为:z(),Math.Max,x>。。。
如果您真的想确定,请查看IL代码。