Your code will only run on MIPS and ALPHA platforms if you compile it for them. You cannot compile a Windows EXE on an x86 platform, and expect it to run on a MIPS platform, IIRC.
Viggy
Printable View
Your code will only run on MIPS and ALPHA platforms if you compile it for them. You cannot compile a Windows EXE on an x86 platform, and expect it to run on a MIPS platform, IIRC.
Viggy
I never knew that. If I had been dealing with this problem, I would have created an overflow on testing, and then been scratching my head over why an exception wasn't getting thrown. I'm surprised that warnings about this sort of subversion (specifically with respect to arithmetic overflow) is not mentioned in the STL books. Josuttis doesn't even mention this, unless he put it in a little note that I missed. Thanks.Quote:
Compiled using Visual C++ 6.0, this does not throw an exception that your program can handle, because the CPU handled it and went on its merry way without you being aware anything wrong has happened. To have the exceptions handled by your app, you have to set the CPU's flags, either by control_fp() or setting the registers yourself using assembly language.
I follow your thoughts. The reason this thread started is because I want robust code. So, I am not going to rely on anything unreliable.Quote:
Originally Posted by spiritualfields
I was hoping that all FPUs handled such invalid operations in the same manner. I thought this may be so, since NaN and infinities are part of the IEEE standard. If they handle such cases, by far the easiest way to handle them is to let them happen, and check the result for NaN. This way, you need not be concerned that your assertion code is correct (again, denominator != 0.0 is insufficient). In fact, you could even let a bad operation carry through more operations, and only check the final result (i.e. just before you go to use it), instead of every division, so it would be faster. Also, there would be no overhead from exception handling.
I was unaware there were so many control options available to FPUs. If I can ensure that the FPU control word disallows interrupts / exceptions, and deals with them as the IEEE standard dictates, then I believe my code idea is the most reliable code of all. However, I am uncertain if I can ensure the FPU status... this is my problem.
Over in the microsoft.public.vc.language newsgroup, a real world story was told of the FPU status change causing unexpected crashes. The story appears to imply that the FPU status is not maintained per thread / process. Can this possibly be true? If the FPU status is global to the entire OS, then no software could ever rely on it. Thus, I find this hard to believe. Any thoughts / info on this?
Thanks for your time,
Well, if it were true, then anytime you run a Visual C++ app, you change the FPU globally. I highly doubt it, but you can easily test it by running two apps under the debugger and watch the registers. One program calls control_fp() with some wacky values, and see if the FPU control status word of the other program changes.Quote:
Originally Posted by JasonD
What does happen, and I've experienced it, is that any code that relies on third-party software, i.e. loading of drivers, then there is your risk of having the FPU control word change on you. The HP printer drivers from some time back were notorious for changing the state of the FPU control word whenever they were used.
Regards,
Paul McKenzie
std::numeric_limits<T>::epsilon() returns the difference between 1 and the smallest value greater than 1 that the data type can represent. There are similar constants defined in FLOAT.H:Quote:
Originally Posted by exterminator
Firstly, your logic could be improved by only performing one check, instead of two: if (fabs(x) < epsilon) ... However, I don't follow your logic. I don't think it is correct.Code:#define FLT_EPSILON 1.192092896e-07F /* smallest such that 1.0+FLT_EPSILON != 1.0 */
#define DBL_EPSILON 2.2204460492503131e-016 /* smallest such that 1.0+DBL_EPSILON != 1.0 */
I realize you can multiply a value with these epsilon values to know the smallest absolute change that you can make to this original value, and get a different floating point representation (i.e. the value actually changes). These tolerances are VERY meaningful in this manner. But, to avoid an overflow, you must also be aware of the size of the numerator; not just the denominator (as I have already stated). This is why such checking code will be slow, cumbersome, and thus prone to error.
Yes, understood. I already take all of these precautions. The callers don't invoke functions with improper input. The functions assert the input is proper for DEBUG mode, and attempts to deal with it properly in RELEASE mode. This thread is due to my concern of how to properly deal with this issue in RELEASE mode.Quote:
Originally Posted by exterminator
Yes, exactly. And I, on the other hand, want the exact opposite. I want the FPU to handle the exceptions, which is the default. I want it to return NaN upon invalid operations, and I want it continue on its merry way. My code will not need exception handling, and will handle these cases merely by testing the result to see if it is NaN. In short, I prefer 'error codes' style over 'exception handling' style of error checking.Quote:
Originally Posted by Paul McKenzie
Ok, right. It doesn't matter what the default setting of the processor is (if there is such a thing); your runtime will initialize the control word to something, overwriting whatever it was before. Since, your runtime initialization is always invoked, you need to know what it initialized it to (or make sure you initialize it yourself).Quote:
Originally Posted by Paul McKenzie
Right. I am not familiar with those platforms, but it makes sense that they are not x86 compatible. _controlfp and _controlfp_s are "platform independent" so they should work identically for all such platforms. So, I should be ok if I must ensure the proper FPU control word via these functions.Quote:
Originally Posted by MrViggy
I was surprised when I first realized this, too. But, then I recognized that this is a far better way of dealing with the problem. Sometimes infinities are ok, since they still can be used with < and >. The IEEE standard really is great. And I am glad that it is used by default. I just need to make sure that this is always the case, and that other applications or others thing I don't know about can't steal this assumption from me -- otherwise, I'll lose the robustness I am looking for.Quote:
Originally Posted by spiritualfields
I highly doubt this, as well. And, yes, you can test this just as you said. Good idea.Quote:
Originally Posted by Paul McKenzie
But, I think you've just solved the dilemma... The person posting the original story about how his application would crash due to the FP control word being changed stated that it was due to printer usage. I asked if his story's implication that the control word was global was true, and he replied and stated that he believes the printer usage may have been from his own application.
Thanks for all of your information, Paul. It is very valuable.
Perhaps a good question to ask, which I think I haven't, yet, is:
How do all of you avoid division by zero / overflows?
Sorry, I lost track of this thread.Yup! (the values are implementation dependent though)Quote:
Originally Posted by JasonD
Why don't you think it is correct? Can you prove it to me that it is incorrect? Can you show a sample code in your support?Quote:
Originally Posted by JasonD
The problem is "Divide by 0" and what I suggested resolves that precisely. Now a calculation going out of bounds is a different thing altogether. That is a sign of logical code error. 0 denominator can be too but it is something that comes in directly as an argument so you can keep to have it as an argument validation. Going out of bounds in calculations happens because of 2 main reasons:Quote:
Originally Posted by JasonD
1. Logical error in code
2. Wrong data type choice (there are libs to handle very large numbers, you might try that)
Having said that, it is not impossible to even check out of bound condition in your code. Here is a sample:(untested/uncompiled code sample)Code:template <typename T>
T bounds_checked_quotient_finder(T numerator, T denominator)
T temp = std::numeric_limits<T>::max()/numerator;
if (temp > denominator)
{
//it will surely go out of bound
throw out_of_bound_exception();
}
else
{
//check for divide by zero.. if it is then throw divide_by_zero_exception
//else perfectly safe to do the division
temp = numerator/denominator;
}
return temp;
}
But it is just too much for nothing. The two things that I mentioned above are the things that need to be taken care of.
Thanks for your post, again.
I don't follow what you mean by implementation dependent. If we deal with 32-bit and 64-bit IEEE floating point storage, these values should never change. Do you mean that these values will be different when running on hardware that doesn't use these two IEEE standards for float and double?Quote:
Originally Posted by exterminator
I have two concerns:Quote:
Originally Posted by exterminator
#1. prevent divide by 0, and
#2. prevent overflow via division.
Since #1. divide by 0 can be prevented merely via:
if (x==0.0) { dont_divide; }
then I assume your solution was to my problem #2 (which is the whole point of this thread). Thus, I assume you are trying to arrive at a way to prevent division when it would cause overflow. And, you stated:
Assuming double type for the moment, your logic is as follows (rounding epsilon to 2.22e-16 for ease of writing):Quote:
Originally Posted by exterminator
So, you are just checking to see if the magnitude of x is less than the epsilon. Thus, the logic is the same as what follows:Code:if (x<0.0)
{
if (x + 2.22e-16 > 0.0) dont_divide;
}
else
{
if (x - 2.22e-16 < 0.0) dont_divide;
}
But, and as I have already explained in my original post, and in my reply to your post, an overflow due to division is dependent on the numerator, as well! The minimum value you can divide by changes if the numerator changes. Thus, checking the denominator against an absolute value, without regard to the numerator, is insufficient. The value must be relative.Code:if (fabs(x) < 2.22e-16) dont_divide;
(I think this is clear, but, as you requested, here is one example that shows the above logic will not work. Given 1e-15, which the above code will not catch, the following results: 1e+309 / 1e-15 = 1e+324 = overflow.)
Ok, wait... Now, it appears that your above code was an attempt to avoid division by 0 only, and not overflow. But, this is simply done like so:Quote:
Originally Posted by exterminator
if (x == 0.0) dont_divide;
I still don't see the use of the epsilon. Please explain, since I am not following your logic.
Ok, again, exterminator, you have offered this extra knowledge in code safety / security. Which, I appreciate. But, as I have already said in my first reply to you, I am aware of this, and this is not the issue I am trying to solve. To make this absolutely clear: I have no intention of ever dividing by 0, or dividing by a number so small that it will overflow even a 32-bit float. My functions check all input, except in the most lowest level functions (that are called millions of times) in which their callers extensively check all parameters. All callers to all functions also check input before invoking a function. Furthermore, I use assert() statements in every imaginable place to catch problems, even small tolerance problems, the moment something goes slightly out of expected range. Now, this leaves me with one final issue to solve: What should I do when this code is in production on a user's home machine, and something completely unexpected will cause a division overflow / divide by 0? I am unwilling to refuse the checking of divide by 0 or division that causes overflow because I believe my code logic is correct. I don't trust my logic this much, and no one else should trust their own to this degree. Bugs happen. I have assertions everywhere just because I know my logic is not perfect. These are standard programming practices. These unexpected logic flaws can miss the unit testing and beta testing, and happen in the field. No matter how much you attempt to prevent this, you cannot be 100% sure that you can prevent them from occurring. I just don't trust the combination of my logic + compiler's logic + OS logic + hardware. All of these will never equate into 0 problems. I am well aware that the biggest issue is my own faulty logic. Some algorithms are very complex, and sometimes, you just don't know what may happen -- if even just in 1 in a billion chance. THUS, I assume there will be problems no matter what I do. And I want to deal with it when it happens. This is the method for the most robust code possible. I must assume that such divides will happen. This is the point of this thread: What do you do when the unexpected happens? How do you deal with this in a very quick way, since these tests will be performed in the production build on end users' machines, perhaps millions of times? (i.e. performance is critical)Quote:
Originally Posted by exterminator
Well, yes and no...Quote:
Originally Posted by exterminator
Yes, the above is too much for what it solves, I agree. This is why I figure you can just let all operations go through, letting the FPU use NaNs in each operation, even AFTER the faulty one, and at the very end, I can merely do this:
if (_isnan(x)) { deal_with_error; }
No, what you imply is incorrect. The above two things DO have to be taken care of -- yes -- but they are not the ONLY things that needs to be taken care of. In my case, these two are already handled. I am now on step #3. Step #3 is what I explained in depth above. Step #3 is the reason for this thread. It is the next step to creating absolutely robust code.
I hope I have explained anything I left vague before...
Thanks for your time,
Does anyone else wish to share how they deal with / avoid division by zero and overflow due to division?
I'd love to hear about it.
Hey, Jason! :)
Got your PM. I have the subscriptions. I did not feel like replying because whatever I would be saying would be a repeatition of what I already said. [not to mention that I visit here only when there's nothing much in non-visual C++ forum/C#/Databases/ and of course chit chat :D].. Seriously? It's diwali time here in India.. :)
You are thinking too hard about it.
No one does anything exceptional about divisions anyway. Like I said, the causes of the problem are the 2 things I already mentioned.
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. What do I do, I do simple maths.. choosing the right datatypes and right techniques... 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.
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.
//Happy Diwali to all who celebrate :wave: