Re: Divide by 0 avoidance / handling
Hi exterminator, thanks for replying. I thought I lost you.
Quote:
Originally Posted by exterminator
I did not feel like replying because whatever I would be saying would be a repetition of what I already said.
Fair enough. However, I thought I brought forth some valid points that differed from your thoughts.
Quote:
Originally Posted by exterminator
You are thinking too hard about it.
I just want the most robust code possible, with simple error checking, and without sacrificing speed. I believe my proposed solution obtains all of these things.
Quote:
Originally Posted by exterminator
No one does anything exceptional about divisions anyway. Like I said, the causes of the problem are the 2 things I already mentioned.
That's my fear... that people don't do anything and just assume their logic / algorithms are flawless. I don't trust either. The most likely causes are the 2 things you mentioned, and I have already taken care of these, as I have said. Now, for the unlikely causes of bad divisions, I want to ensure my production code doesn't flop. Again, I want the most robust code possible.
Quote:
Originally Posted by exterminator
Consider the case, where I am to apply Newton-Raphson technique to determine the yield to maturity of a bond given its price or for that matter am implementing any other numerical method.. what do I do? There would be a lot of arithmetic (division too!) involved. I am not going to call bounds_checked_quotient_finder() always.. doesn't make sense.
Yes, you cannot call such a function before each division, you are correct. I am not implying that you should, in fact, I said from the start that this would slow and bloat the code. My proposed solution states you should perform only one much more simple check at the very end. It's faster, the code isn't complex, it needs only be called once, it's much more clean, and its robust.
The alternative is to not check at all, as you propose, and assume your logic / algorithms are perfect. But, the point of robust code is that it works in cases that were unexpected. In your example, I am sure you cannot possibly predict every resultant operation that Newton's method may cause. So, instead of assuming success, why not check the final result and have robust code?
Quote:
Originally Posted by exterminator
What do I do, I do simple maths.. choosing the right data types and right techniques...
Of course. As do I. But, even the right math can be faulty in some cases, due to strange boundary cases, precision errors, etc. You cannot prevent these cases with 100% certainty. Robust code assumes these cases may occur, and can handle them when they do. This is my goal.
Quote:
Originally Posted by exterminator
Check for divide by zero that I mentioned using epsilon is the maximum I will do. And mind you - you cannot compare floating points for 0 by just using == with 0.0 - It could be a result of an operation or anything and the fact that floating point numbers cannot be represented precisely in binary.. I cannot do that. I "have to" use epsilon or a MACRO that defines the value.
Ok, you are confusing two different things...
I understand that FP are not represented exactly in binary. I know you must use an epsilon to compare two FP numbers, as a result of inaccurate storage and accumulative error. But, your use of epsilon is incorrect. The epsilon has to be relative to the numbers being compared. Those epsilon constants are used to create the epsilon that you need, not to be used as-is. The are only useful in respect to the number 1.0, simply because this is how they are defined. You must account for the magnitude of your numbers, and the amount of accumulative error. (And use fabs() to be more efficient.)
The above epsilon talk is besides the point. To prevent infinity from occurring due to a division by 0, you only need check to see if the divisor is exactly 0. Dividing by something close to 0, but not 0, hardly ever returns infinity due to the limited precision of the FPU. If you are dealing with numbers far greater than the smallest magnitude FP (~1e-309), then your divisors will either be exactly 0.0, or they will be so large (but still close to 0, say 1e-20) that they will not cause infinity to occur. Epsilon is not required for a 'divide by 0' check.
To be more clear: You are speaking about checking to see if some arbitrary variable is 0, and yes, you need to use an epsilon for this, just as if you were comparing two FP values. I am speaking about preventing a division by 0, so I only need to check to see if divisor is exactly 0.
(Since there is great confusing here, I want to clarify that I am aware of algorithms in which you expect a 0 result, and due to FP inaccuracies, you will get something only close to 0 instead. In these cases, yes, you should see if the number is close to being 0, and change it to be 0. This is not what 'division by 0' is about.)
(Also, for those joining mid-thread, I do realize there is still the chance that a divisor is so small that when divided into the dividend that it causes overflow. The minimal divisor value to avoid such a case is dependent on the dividend's value. Such an 'epsilon' must be computed at runtime from the dividend, and cannot be determined by the aforementioned constants. This is not the issue I speaking about above, although it is the main concern raised in this thread.)
Quote:
Originally Posted by exterminator
Regarding your "something really unexpected" - I think you are asking about something more than the problems of overflow or divide by zero. You are talking about exceptions.. and that too not just application related exceptions but system exceptions as well.. But for that you have exception handling... Try searching for exception handling threads in non-Visual C++ forum... you will get many.
No, I am not speaking about exceptions. I am talking about FP overflow.
I am sorry, but I just really don't know where the break in our communication is occurring.
The "something really unexpected" is just a concrete example where you cannot assume that FP values are as expected. I chose it because it is one example that no one can argue against, because, when the hardware cannot be trusted to work, you have no idea what will happen. If you do not believe in such a crazy claim, please read this post by Raymond Chen on overclocking. Note that computers are being sold overclocked unbeknownst to customers:
The Old New Thing: There's an awful lot of overclocking out there
Yes, I admit, this is an extreme case. The much, much more likely case is that merely your logic / algorithm is faulty. And that is the reason we make robust code. If our logic never fails, and the algorithm never fails, and the compiler, the OS, and hardware never fails, then why make robust code at all? Why even bother?
Re: Divide by 0 avoidance / handling
Quote:
Originally Posted by gstercken
No, you can't assume that... By default, floating point exceptions are turned on. It depends on the implementation of the floating point library you use - and the VC++ standard library happens to turn them off.
/fp (Specify Floating-Point Behavior) can set FP exceptions to be on by default, rather than off, with /fp:except. Introduced in VC++ 2005. Not available for VC++ 2003.