1

I am facing an odd problem in C#, where I need to evaluate some mathematical string expressions, which may divide by 0. Here is an example:

string expression = GetUserInput(); // Example: "(x + y) / z", where z may equal to 0

I am currently using NCalc library for evaluating this expression, which throws a DivideByZeroException if the z argument in current expression is 0.

I tried catching the exception by doing:

try {
    string formula = GetUserInput();
    Expression exp = new Expression(formula);

    // ...

    exp.Evaluate(); // Throws a DivideByZeroException

} catch (DivideByZeroException e) {
    //ignored
}

However, I need to evaluate this expression more than 6000 times (with different variables) in a time-efficient manner, so catching an exception every time significantly slows down my application.

I have multiple such expressions, each of which is entered by a user. I can not know if a given expression attempts to divide by zero or not.

Is there a way to evaluate a mathematical expression in C# in a "safe" way, where attempting to divide by 0 will return a static number (0, or infinity), without throwing an exception?

Victor2748
  • 4,149
  • 13
  • 52
  • 89
  • Should you parse your expression and checking if z is different from zero first ? – Thomas Sep 08 '16 at 03:34
  • Why do you think that exceptions signifacantly slow down your application? [It should not affect it too much.](http://stackoverflow.com/questions/1308432/do-try-catch-blocks-hurt-performance-when-exceptions-are-not-thrown) – Yeldar Kurmangaliyev Sep 08 '16 at 03:35
  • @Thomas Each time, the expression is different (as it is typed up by a user) and I can not know whether it can divide by zero. – Victor2748 Sep 08 '16 at 03:35
  • @YeldarKurmangaliyev Because I did some profiling on my application. When thousands of exceptions are thrown and caught, it can influence the performance in a noticeable way. In your reference, the question is different. My problem is poor performance when exceptions *are* thrown. – Victor2748 Sep 08 '16 at 03:37
  • `I need to evaluate a mathematical string expression, which may divide by 0`. Why don't you ignore such a scenario, by validating or showing an error rather than evaluating the expression after knowing z can be zero. – ViVi Sep 08 '16 at 03:39
  • if the expression contains "/ 0" or something like that dont evaluate ? – Thomas Sep 08 '16 at 03:40
  • @Rennie I can not know whether Z is zero or not, as each of my expressions are different (in my question is just an example) – Victor2748 Sep 08 '16 at 03:41
  • @Thomas Expressions contain variables rather than constant numbers. It is hard to analyse the expression to check if it might divide by 0 – Victor2748 Sep 08 '16 at 03:42
  • so you build the expression ? Can you please post more revelant code so we can try to help you ? Thanks – Thomas Sep 08 '16 at 03:47
  • If you don't wish exceptions to get caught, then the only way is to do a check and evaluate the cases where exceptions could be caused and prevent them. And exceptions doesn't have a major impact on performance unless you have 99% of cases where z is 0. – ViVi Sep 08 '16 at 03:48
  • Can you trace where the time is being lost? I can't imagine that the exception block alone would be causing that much performance loss, so it must be in the NCalc library. So you would have to make a change there for better performance. – Dijkgraaf Sep 08 '16 at 03:51
  • @Dijkgraaf I did the performance profiling, and it shows that when thousands of exceptions are thrown and caught, it causes performance issues. While throwing-catching a single exception may not influence the performance much, thousands of such operations add up and make a difference. – Victor2748 Sep 08 '16 at 03:53
  • @Victor2748 Yes, but it is not the Exception block that would cause it. It would be how the NCalc library is handling these cases and throwing it as an exception. So unless you want to write your own parser of math expressions, you need to address the issue in NCalc library. – Dijkgraaf Sep 08 '16 at 03:55
  • @Rennie I have over 3000 cases where z = 0, therefore over 3000 times an exception is thrown-caught. That is what I would like to avoid. Analysing a string expression to check if it divides by 0 is too hard. – Victor2748 Sep 08 '16 at 03:55
  • 3000 cases given the code you have looks like that you'd be compiling the expression many time unnecessarily? – Keith Nicholas Sep 08 '16 at 03:58
  • @KeithNicholas No, I compile my expression once and just give it different variables. I did not show that in my code snippet here, for the sake of simplicity. I thought it would be off the point of the question. – Victor2748 Sep 08 '16 at 04:00
  • how many inputs do you have? – Keith Nicholas Sep 08 '16 at 04:06
  • I have about 10 inputs of different equations. Each may or may not attempt to divide by 0 – Victor2748 Sep 08 '16 at 04:08
  • 1
    as in my answer, try floating point values, otherwise I think you either need to hack ncalcs source code or find another evaluator – Keith Nicholas Sep 08 '16 at 04:18
  • @KeithNicholas Thank you. This is what I was looking for. I guess it is the closest solution to my problem. – Victor2748 Sep 08 '16 at 04:20

2 Answers2

3

try making your values floating point.

Trying to divide an integer or Decimal number by zero throws a DivideByZeroException exception. To prevent the exception, ensure that the denominator in a division operation with integer or Decimal values is non-zero. Dividing a floating-point value by zero doesn't throw an exception; it results in positive infinity, negative infinity, or not a number (NaN), according to the rules of IEEE 754 arithmetic. Because the following example uses floating-point division rather than integer division, the operation does not throw a DivideByZeroException exception.

https://msdn.microsoft.com/en-us/library/system.dividebyzeroexception.aspx

Keith Nicholas
  • 43,549
  • 15
  • 93
  • 156
0

Evaluate z. If z is > 0 then do the operation, else move to next evaluation.

anil
  • 598
  • 1
  • 6
  • 20
  • 5
    he doesn't know what variable will be used to do the divide. It could be any combination that will generate the divide by zero .. . user might do x/y/(1-z) – Keith Nicholas Sep 08 '16 at 03:45
  • 3
    @anil: You could have gone through the discussion before posting such a simple answer. Even a newbie c# coder would know how to check for 0 like this `Evaluate z. If z is > 0 then do the operation, else move to next evaluation.` – ViVi Sep 08 '16 at 04:00