Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can exceptions used as a control flow mechanism be valid in some specific scenarios?

I'm tweaking some code in a RationalNumber implementation. In particular, inside the equality logic, I'm considering the following:

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);
   }
}

As you can see I'm using exceptions as a flow control mechanism. The reasoning behind this is that I do not want to incurr in the penalty of evaluating the greatest common divisor of both fractions on every equality check. Thus I only decide to do it in the least probable case: one or both cross products overflow.

Is this an acceptable practice? I've always read that exceptions should never be used as a flow mechanism of your code, but I don't really see another way to achieve what I want.

Any alternative approaches are welcome.

like image 816
InBetween Avatar asked Jun 26 '15 12:06

InBetween


1 Answers

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.

This is sound reasoning. The total cost of this code is

{probability of fast-path} * {fast-path cost}
+ ((1.0 - {probability of fast-path}) * {slow-path cost})

Depending on the three constants involved this will be a good or bad choice. You need to have a good understanding of that data will be processed in practice.

Note, that exceptions are very slow. I once benchmarked them to be 10000 per second per CPU core and I'm not sure they would scale to multiple cores due to internal CLR locks involved.

Maybe you can add runtime profiling. Track the rate of exceptions. If too hight, switch off the optimization.

You probably should document why you did this.

It's also not an architectural problem because in case you change your mind later you can easily switch to a different algorithm.

As an alternative, you could first compute and compare unchecked. If the result is "not equal" it is guaranteed that the exact result would be "not equal", too. Even if overflow occurred. So that could be an exception free fast path if many numbers turn out to be not equal.

like image 119
usr Avatar answered Oct 16 '22 14:10

usr