logo
Welcome Guest! To enable all features please Login or Register.

Notification

Icon
Error

Options
Go to last post Go to first unread
StorkBite  
#1 Posted : Monday, July 31, 2006 11:49:31 PM(UTC)
StorkBite

Rank: Advanced Member

Groups: Registered, Registered Users
Joined: 3/19/2005(UTC)
Posts: 2,995

Was thanked: 14 time(s) in 10 post(s)

How to handle a ‘divide by zero’ error

A divide-by-zero error will occur whenever there is a denominator in the formula that could end up having a value of zero (even if there is no chance it will ever happen), such as this sample

formula: Close/(High-Low)

In this formula, if High-Low equates to zero (because the High and Low are equal), then a divide-by-zero error occurs.

To avoid divide-by-zero errors, the division that is giving the problem has to be identified and then rewritten to trap the zero, for instance, using the same sample formula above, we could do this:

Z:=If(H-L=0,.00001,H-L);

Close/(z);

Thus, when the zero would normally occur we substitute a value very near zero, .00001, to avoid the error. This does introduce a minimal, probably non-significant, error into the calculation, but it is often worth it.

What does the number stand for directly following the divide by zero error? It is the number of times that the calculation ran into the zero value.

wabbit  
#2 Posted : Saturday, February 25, 2012 8:27:55 PM(UTC)
wabbit

Rank: Advanced Member

Groups: Registered, Registered Users, Subscribers, Unverified Users
Joined: 10/28/2004(UTC)
Posts: 3,111
Location: Perth, Western Australia

Was thanked: 16 time(s) in 16 post(s)
It seems there are a bunch of people who have forgotten (how) to handle DBZ (divide by zero) errors; hence the bump of this thread, with a few more examples.

1. When do we need to check for DBZ?
Some coders will try to figure out when the denominator in a division operation may be zero and only then try to trap the error, but good coding practices mandate that EVERY TIME we perform a division operation, we MUST check for a zero condition. It isn't hard and it uses very little computing power; the time saved writing a simple check will save hours of frustration at erroneous results later.

2. How to check for DBZ in MSFL?
The MS formula language is a fully evaluated scripting language (there are lots of discussions on the Forum about this, but if you don't understand right now, press on reading anyway and it might become more apparent). MS also some issues when it comes to how it performs math operations on very large and very small numbers, so we need to be very careful how we get MS to perform what should be a simple check.

Let's start with trying to gain an understanding of what doesn't work.

An example of what DOESN'T work:
Code:
{Example 1}
{Bad example of DBZ check}
If( H-L=0, 0, CLOSE/(H-L) );

By reading the code, many would expect that when (H-L)=0 the function will return the TRUE value of the If() expression i.e. zero, and, only in the event that (H-L)<>0 will the division operation be evaluated in the FALSE value of the If() expression; but, MS is a fully evaluated language, so MS looks at BOTH values in the If() expression, so will return an error if either part contains an error.

Another example of what DOESN'T work:
Code:
{Example 2}
{Bad example of DBZ check}
numerator:={some expression};
denominator:={some expression};

{plot}
numerator / (denominator + 0.00001);

An often touted solution to resolving DBZ is to simply add a very small value to the denominator on every computation. This is bad for two reasons: first, it introduces an error to the expected value of the division operation, but secondly and more importantly, what if the desired denominator is -0.00001? We'd be creating a DBZ when one shouldn't exist!

3. So, what does work?
Henry's method as show in the previous post works to trap the DBZ, but we can extend its functionality to avoid messing with the scaling when the denominator is very small; we 'eliminate' the result, or in the example below, we set the output to zero if the desired denominator is zero (we have to check this twice):

Code:
{Example 3}
{Better method to capture DBZ}
numerator:=CLOSE;
desiredDenominator:=HIGH - LOW;

verySmallNumber:=0.00001;

denominator:=If( desiredDenominator=0, verySmallNumber, desiredDenominator );

divisionOperation:=numerator / denominator;

{plot}
If( desiredDenominator=0, 0, divisionOperation );

Of course, you could return a different value than zero.

4. A practical example
On another forum, a member asked for assistance to resolve errors with this code:

Code:
{Sourav's Normalized Indicator}
Ind:=Cum(((Pwr((C-L),2)-Pwr((H-C),2))/(H-L))*V);
Npds:=Input("periods to normalize", 1,500,48);
Norm:=(Ind-LLV(Ind,Npds))/(HHV(Ind,Npds)-LLV(Ind,Npds)+.0000001)*100;
Norm;


Q. Can you spot where the errors will be generated?
A. Of course you can!

The DBZ error is being caused in the Ind line where a division operation is being carried out without a DBZ check. We can see the author is trapping the DBZ error in the Norm line (and introducing accuracy errors!)

Possible solution:

Code:
{Sourav's Normalized Indicator}
Npds:=Input("periods to normalize", 1,500,48);

verySmallNumber:=0.00001;

{first part of the operation}
numerator:=V*(Pwr(C-L,2)-Pwr(H-C,2));
desiredDenominator:=H-L;
denominator:=If( desiredDenominator=0, verySmallNumber, desiredDenominator);

Ind:= Cum(numerator / denominator);

{second part of the operation}
numerator:=100*(Ind-LLV(Ind,Npds));
desiredDenominator:=HHV(Ind,Npds)-LLV(Ind,Npds);
denominator:=If( desiredDenominator=0, verySmallNumber, desiredDenominator);

Norm:=numerator / denominator;

{plot}
Norm;

Note: I have written this in a very verbose form to emphasise the lessons; of course, this can be easily abbreviated.

5. More advanced methods
If we KNOW the sign of the denominator i.e. positive or negative, then we can use some slightly more technical tricks, but you have to very sure!

Code:
{Example 4}
{We know the sign of the denominator will ALWAYS be positive}
numerator:=CLOSE;
denominator:=HIGH - LOW; {will always be greater than or equal to zero}

verySmallPosNumber:=0.00001;

{plot}
numerator / Max(denominator, verySmallPosNumber);


Code:
{Example 5}
{We know the sign of the denominator will ALWAYS be negative}
indy:=WillR(10);

numerator:=indy;
denominator:=Ref(indy,-1); {will ALWAYS be less than or equal to zero}

verySmallNegNumber:=-0.00001;

return:=numerator / Min(verySmallNegNumber, denominator);

{plot}
If( denominator=0, 0, return ); {see Example 3}

And of course, the more advanced coders will now be writing their own codes to test whether the denominator is positive or negative, and using a verySmallPosNumber or verySmallNegNumber as required.

Armed with this knowledge, we can revisit Sourav's indicator:

Code:
{Sourav's Normalized Indicator}

Npds:=Input("periods to normalize", 1,500,48);

verySmallNumber:=0.00001;

{first part of the operation}
numerator:=V*(Pwr(C-L,2)-Pwr(H-C,2));
denominator:=H-L; {always >=0}

Ind:= Cum( numerator / Max(denominator, verySmallNumber) );

{second part of the operation}
numerator:=100*(Ind-LLV(Ind,Npds));
denominator:=HHV(Ind,Npds)-LLV(Ind,Npds); {always >=0}

Norm:=numerator / Max(denominator, verySmallNumber);

{plot}
Norm;


Anyway, I hope this clears up the DBZ issues.



wabbit [:D]
Users browsing this topic
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.