3

I want to perform a basic calculation with fractional numbers using vb.net.

Dim a As Single= 7200.5
Dim b As Single= 7150.3
Dim c As Single= a - b

'Expected result = 50.2
MsgBox(a.ToString + " - " + b.ToString + " = " + c.ToString.Trim)
'Produced result is: 50.2002

Dim single1 As Single
Dim single2 As Single
Dim single3 As Single

single1 = 425000
single2 = 352922.2
single3 = single1 - single2

'Expected result is: 72077.8
MsgBox(single3.ToString)
'Produced result is: 72077.81

How can the results be so inaccurate for such a simple calculation? The problem is solved when I change the data type to Decimal, but Decimal objects consume more memory (16 bytes). Is there any alternative data type that i can use to perform simple fractional calculations with accurate results?

Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
Albert Tobing
  • 169
  • 2
  • 14
  • 2
    "decimal consume bigger space (16 bytes)" Do you have a memory problem when using `decimal`? – Magnus Nov 15 '12 at 14:14
  • Not only it require bigger space, but it is also the slowest among other data types (single, double, int). But most importantly, I am curious why the result is so inaccurate for such a simple calculation. – Albert Tobing Nov 15 '12 at 14:17
  • Also if u change variable a,b,c to double, it still produce inaccurate result. But if u change the variable single1, single2, single3 to double, it produce the right result. Why? – Albert Tobing Nov 15 '12 at 14:18
  • 1
    Suggested reading: [What is the difference between Decimal, Float and Double in C#?](http://stackoverflow.com/questions/618535/what-is-the-difference-between-decimal-float-and-double-in-c) – Magnus Nov 15 '12 at 14:19
  • When .Net calculates the result of an addition, subtraction, multiplication etc. it can only give the result to the precision of the least precise data type. This is why multiplying a decimal with a value of 1.25 by an integer of value 2, you will only get 2 as a result. – Sean Airey Nov 15 '12 at 14:24

3 Answers3

5

This is to do with the way floating point numbers are stored in memory, and a Single in .Net is a single precision floating point number, which is much less accurate than a Decimal or a Double for storing decimal numbers.

When the computer calculates your number, it only has binary fractions to use and in a single precision floating point number, they're not very accurate.

See http://en.wikipedia.org/wiki/Single-precision_floating-point_format for more information.

EDIT: There's some more information specific to VB.Net here: http://msdn.microsoft.com/en-us/library/ae382yt8(v=vs.110).aspx

Sean Airey
  • 6,352
  • 1
  • 20
  • 38
0

The Single and Double data types are not precise. They use the floating point method to store their values. Floating points use less memory and allow for faster calculations, but they are imprecise. That is the trade-off that you have to accept if you are going to use them. If precision is important, then they are not an option for you. Decimal is precise (to a certain number of fractional digits, that is), so usually, that is the best choice for precise fractional numbers in most cases. If you really need to save memory, and you are guaranteed that your numbers will be within a certain range, then you could use an Int16, Int32, or Int64 instead. For instance, if you only care about two fractional digits, you could simply multiply everything by 100 and then just divide by 100 (using Decimal types for the division) before displaying it. In that way, you can store many numbers and perform many operations using less memory, and only need to use the Decimal data type when you need to display a result.

Dim a As Integer = 720050 '7200.5
Dim b As Integer = 715030 '7150.3
Dim c As Integer = a - b
Dim cDisplay As Decimal = CDec(c) / CDec(100)
MessageBox.Display(String.Format("{0} - {1} = {2}", a, b, c))
Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
0

You can use the Decimal data type instead. It will work great! This is because Decimal is a fixed point value, whereas Single and Double are floating point values (with loss of precision).

Steven Doggart
  • 43,358
  • 8
  • 68
  • 105
Serge Bollaerts
  • 324
  • 2
  • 6