我正在调整 RationalNumber
实现中的一些代码。特别是,在相等逻辑内部,我正在考虑以下内容:
public bool Equals(RationalNumber other)
{
if (RationalNumber.IsInfinity(this) ||
RationalNumber.IsInfinity(other) ||
RationalNumber.IsNaN(this) ||
RationalNumber.IsNaN(other))
{
return false;
}
try
{
checked
{
return this.numerator * other.Denominator == this.Denominator * other.numerator;
}
}
catch (OverflowException)
{
var thisReduced = RationalNumber.GetReducedForm(this);
var otherReduced = RationalNumber.GetReducedForm(other);
return (thisReduced.numerator == otherReduced.numerator) && (thisReduced.Denominator == otherReduced.Denominator);
}
}
如您所见,我使用异常作为流程控制机制。这背后的原因是,我不想在每次相等性检查时计算两个分数的最大公约数时受到惩罚。因此,我只决定在可能性最小的情况下这样做:一个或两个叉积溢出。
这是一种可接受的做法吗?我一直读到异常不应该用作代码的流机制,但我真的没有看到另一种方法来实现我想要的。
欢迎任何替代方法。
最佳答案
The reasoning behind this is that I do not want to incur in the penalty of evaluating the greatest common divisor of both fractions on every equality check.
这是合理的推理。这段代码的总成本是
{probability of fast-path} * {fast-path cost}
+ ((1.0 - {probability of fast-path}) * {slow-path cost})
根据所涉及的三个常量,这是一个好的或坏的选择。您需要充分了解将在实践中处理的数据。
请注意,异常非常慢。我曾经将它们作为每个 CPU 内核每秒 10000 次的基准测试,但由于涉及内部 CLR 锁,我不确定它们是否会扩展到多个内核。
也许您可以添加运行时分析。跟踪异常发生率。如果太高,请关闭优化。
您可能应该记录下您这样做的原因。
这也不是架构问题,因为如果您稍后改变主意,您可以轻松切换到不同的算法。
作为替代方案,您可以先不加检查地进行计算和比较。如果结果“不等于”,则可以保证确切的结果也“不等于”。即使发生溢出。因此,如果许多数字结果不相等,这可能是一条无异常的快速路径。
关于c# - 用作控制流机制的异常在某些特定场景下是否有效?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31073824/