Vb.Net attempt to divide by zero problem

Posted on 2013-05-16
Medium Priority
Last Modified: 2013-05-23
Hi EE,
    I have a piece of code, it's working most of the time, however it some time throw 'attempt to divide by zero' error, although I did have a check for zero on the denominator before the divide, wonder what the problem is, if anyone has any idea please let me know.

                            Dim myDenominator As Decimal = (CDec(Math.Round(row("TotQty"), 2)) + CDec(Math.Round(row("DelQty"), 2)))
                            If (myDenominator <> 0) Then

                                Dim newStdCost As Decimal = (((CDec(Math.Round(row("TotQty"), 2)) * CDec(Math.Round(row("StdCost"), 2))) + (CDec(Math.Round(row("DelQty"), 2)) * CDec(Math.Round(row("DelCost"), 2))))) / myDenominator

End If

Open in new window

Question by:miketonny
  • 3
  • 3
  • 2
LVL 40
ID: 39173867
Do you absolutely need the precision of a Decimal?

When you assign the value to your denominator, you end up with only 2 decimal. And the multiplication ends up with 6 at most. There is no need for all the extras that the Decimal type provides.

Because the number of decimal places in the Decimal type is variable, Decimal values are handled in a special way compared to the more straightforward Single and Double type.

I would try removing all the CDec and work with a Double all the way. Convert only the result to Decimal if you really need that data type for other operations.

Author Comment

ID: 39176339
thanks James,
could you let me know how double and decimal are handled differently? i see this is a good chance of learning something I didn't know before.
LVL 40

Accepted Solution

Jacques Bourgeois (James Burger) earned 1200 total points
ID: 39176574
The Single is a 32-bit number. 16 for the integer part, 16 for the decimal. The number of decimals is thus fixed at 7.

The Double is a 64-bit number. 32 for the integer part, 32 for the decimal. The number of decimals is thus fixed at 15.

The Decimal is a 128-bit number. However, contrary to the other 2 types of floats, the number of bits assigned to the integer part and the decimal part is variable. If you have a value of 0, no bit is used for the integer part, and all of the 128 bits are used for the decimal part, giving you 28 decimal places. As the integer part grows, the number of bits available for the decimal part is reduced, an you thus lose decimal places. A very big number (either negative or positive) will thus have less decimal precision than a small one.

I do not know about the implementation details, but it is clear that this mechanism of having a variable lenght for the integer vs decimal parts of a value involves some internal manipulations that are not necessary in a Double that has a fixed memory footprint for the 2 values. What is clear also is that the Decimal type incurs a hit on performance. So, unless you really need the extra precision (over 15 decimals), you are better to stay clear of that type.

Now, a question of my own. I would be glad to have somebody jump in and explain that to me.

The documentation for Decimal states that the Decimal type "is particularly suitable for calculations, such as financial, that require a large number of digits but cannot tolerate rounding errors". This is confirmed somewhat by the fact that when you convert a VB6 application to .NET, the old Currency type (that is not available anymore) is converted to Decimal. I greatly suspect that your use of the Decimal type could come from such a conversion.

But although I never had to code financial applications, in my experience most financial operations round off at 4 decimals (this is what the old Currency type did). When I bought my house, I checked the interests charged by the bank and came out with a higher amount than the bank did. It made a difference of $25 a month on my paiement. I was working with Single values, 7 decimals. When I adjusted to 4, I came out with only 1 cent of difference... and figure out who was getting the extra cent?

I know that some finalcial operations, such as currency exchange, round off at 5 decimals. So, why this statement about Decimal suitable for financial calculations. A Single is quite capable of working at that level, and a Double twice more so.

As far as I am concerned, Decimal could be useful for some scientific calculations, say at the level of the atom or the universe. But even there, it is often too much. I had to do something dealing with chemistry for a pharmacology company many years ago, and the Double, with its 15 decimals of precision, was enough for them.

So, could somebody tells me what types of financial operations would require the Decimal type?

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

LVL 20

Assisted Solution

ElrondCT earned 800 total points
ID: 39183005
Responding to the original question: Are you sure the problem is happening at the Dim newStdCost line? Is it giving you that line number in the stack trace, or is it stopping there in the debugger? If you view myDenominator, does it show 0? What's the point of having newStdCost defined inside an If/Then block that is only one line long? It's going to be out of scope as soon as the End If is hit. Or did you simply delete following lines in the If/Then block?

James, as a developer of financial applications, I can tell you that I use Decimal types for all of my currency values. The reason is that it's too easy for rounding errors to creep in otherwise. It may not seem like a big deal what's happening to that extra cent, but it makes accountants go crazy; they want numbers to tie out exactly. I go to a lot of effort to make sure that, for instance, if a one dollar asset is depreciated over three months, I get back to a dollar, not 99 cents. The other issue is that getting a spurious 1 millionth or whatever can cause comparisons to go haywire: if .33 + .37, because of the imprecision of floating point arithmetic, turns into .70000000000001, that doesn't equal .7, and you can run into really nasty debugging projects and extra verifications required all over the place. (Even more commonly at issue, .00000000001 <> 0.)

Decimal is a bit more processor-intensive, to be sure, but in my opinion it's well worth it. If the alternative is doing a Math.Round() call every time you add and subtract, you're probably ahead of the game.
LVL 40
ID: 39183128
Thanks for the input Elrond.

I never had to deal with those precisions in my applications, where woodworkers often find that 1/64 is too much precision in my current project, and where money operations in my older projects were almost of the multiplying a quantity by a unit price and adding the taxes sort. And my own accoutant is OK as long as we follow the rounding rules of the canadian government that do not got further than a few decimals. My bank does not care either, interests on my 25 years mortgage were rounded out at the 4th decimal.

Having the input from a programmer who has another experience is always a good learning lesson.

Author Comment

ID: 39192344
thanks guys for all the input, really helped me understand the definition and difference between these two. appreciate all your help.

Author Comment

ID: 39192358
yes I'm sure it was the line throwing the error.
there are further calculations after that however none of them have a divide so i took them out in the post above.

the funny thing is it is not always throwing the error, happens 1 - 2 times everyday. i tried to record the product it had the issue and went back checked, everything looked normal.

maybe there's something else going wrong?
LVL 20

Expert Comment

ID: 39193177
If you haven't gotten a stack trace or other message that specifically points to that line, then I'd be suspicious that there's something else happening. A Mod calculation, for instance, can also return a divide by zero error. There might be other things that don't come immediately to mind.

If you're getting it 1-2 times a day, I presume this is an application that's in production. Since it's intermittent, just running in debug won't likely help you much. But I think you need to get some debugging information out of the application. My first step would probably be to put the Dim newStdCost statement in a Try/Catch block. If the exception fires, display ALL the values that are in the calculation on that line. If you get the error and the Catch isn't triggered, it tells you that the problem is somewhere else; perhaps you can set up another Try/Catch block for the rest of the code and display enough information in the error message to tell you how far it got before crashing.

Featured Post

Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

If you're writing a .NET application to connect to an Access .mdb database and use pre-existing queries that require parameters, you've come to the right place! Let's say the pre-existing query(qryCust) in Access takes a Date as a parameter and l…
The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
Screencast - Getting to Know the Pipeline
Suggested Courses

864 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question