1

I am trying to subtract the value from two textboxes in Visual Studio 2012.

Example input and results:

textbox1 -  textbox2   = label1 
  25.9   -    25.4     =  0.50   (it's ok) 
 173.07  -   173       =  0.06   (should be 0.07) 
 144.98  -   142.12    =  2.85   (should be 2.86) 

My code (I tried all three lines separately):

label1.text = (Convert.ToDouble(textbox1.text) - Convert.ToDouble(textbox2.text)).ToString

label1.text = (CDbl(textbox1.text) - CDbl(textbox2.text)).ToString

label1.text = (Val(textbox1.text) - Val(textbox2.text)).ToString 

This error (may be not an error) occurs some times, not every time. What am I missing here? And what should I use instead of "CDbl" ?

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
Umesh
  • 71
  • 3
  • 14
  • 1
    Let us know if it works when you use `CDec` instead of `CDbl`. – Andrew Morton Jan 30 '19 at 14:26
  • 1
    Ok... admittedly picky, but for the sake of fully explaining the issue... To say that `Decimal` is more accurate, in this sense, is technically incorrect. The problem is that some fractions are impossible to accurately represent in decimal form because they have repeating decimals. For instance, if you write 1/3 as a base-10 decimal, you'll have to round it at some point because it repeats forever. The real issue is that which fractions have repeating decimals changes [depending on the base](https://en.wikipedia.org/wiki/Repeating_decimal#Extension_to_other_bases). – Steven Doggart Jan 30 '19 at 14:53
  • 3
    `Decimal` stores numbers using base-10 digits and `Double` store them using base-2 digits. Therefore, `Decimal` isn't fundamentally more accurate than `Double`. It still has the same problem, just with different numbers. The real advantage with `Decimal` is that the rounding is more expected, especially when the inputs and outputs are both base-10 decimals, such as with money. No one is surprised when $1.00 / 3 gets rounded to $0.33. – Steven Doggart Jan 30 '19 at 14:53

1 Answers1

2

what should I use instead of "CDbl" ?

When you start with the a string, the best option is Double.Parse() or Double.TryParse(), depending on the possibility for bad data.

But even that's not enough in this case. Computers use something called IEEE754 for floating point arithmetic. This scheme for encoding floating point numbers is designed as an efficient way to represent numbers in binary, and further has direct support in CPUs for arithmetic operations, meaning it is much faster than any available alternative (it's not even close). Pretty much every programming platform uses it.

The downside is there is some loss of precision. When treated as IEEE754 doubles, 173.07-173 produces .69999999.

You can solve this in two ways:

  1. Round the results. This isn't an option when using division, but with just addition and subtraction you can track significant digits and round to get exact results. This is a pain, though.
  2. Use the Decimal type. Decimal isn't perfect, but is does have a much greater degree of precision (at the cost of some performance), and for your sample data produces exact results.

In short, try this code:

label1.text = (Decimal.Parse(textbox1.text) - Decimal.Parse(textbox2.text)).ToString() 
Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794