1

I have an old VBA application that has generates values like 1.123456789123456789123456789E-28. When I googled to find the equivalent data type in C#, I found this article in SO Difference between decimal, float and double in .NET?. As per what this post suggests, decimal data type has the largest size in C#. So I used decimal data type but I found that decimal seems to be limited in representing large values that VBA represents in exponential form. So I googled again and found this article https://msdn.microsoft.com/en-us/library/ae55hdtk.aspx. As stated in this article,

Nonintegral number values can be expressed as mmmEeee, in which mmm is the mantissa (the significant digits) and eee is the exponent (a power of 10). The highest positive values of the nonintegral types are 7.9228162514264337593543950335E+28 for Decimal, 3.4028235E+38 for Single, and 1.79769313486231570E+308 for Double.

This means Double data type has the largest range of values. So now I am confused between decimal and double.

Then I did a little experiment with code like below

    double dbl = 1.123456789123456789123456789E-28;
    decimal dcl = 1.123456789123456789123456789E-28M;
    MessageBox.Show(dbl.ToString());
    MessageBox.Show(dcl.ToString());

The dbl prints the value as it is 1.123456789123456789123456789E-28 while the dcl value changes to 0.0000000000000000000000000001; Can someone explain what is happening here ? What is the equivalent data type in C# to represent large exponential values like in VBA with same precision?

Community
  • 1
  • 1
devanalyst
  • 1,348
  • 4
  • 28
  • 55
  • 2
    I think if you read that first article further, you will understand the differences and when to use them. I think you may have misunderstood that first link you posted. – Hank Nov 14 '16 at 17:15

2 Answers2

4

According to the C# language specification: https://msdn.microsoft.com/en-us/library/aa691085%28v=vs.71%29.aspx

  • A real literal suffixed by F or f is of type float. For example, the literals 1f, 1.5f, 1e10f, and 123.456F are all of type float.
  • A real literal suffixed by D or d is of type double. For example, the literals 1d, 1.5d, 1e10d, and 123.456D are all of type double.
  • A real literal suffixed by M or m is of type decimal. For example, the literals 1m, 1.5m, 1e10m, and 123.456M are all of type decimal. This literal is converted to a decimal value by taking the exact value, and, if necessary, rounding to the nearest representable value using banker's rounding (Section 4.1.7). Any scale apparent in the literal is preserved unless the value is rounded or the value is zero (in which latter case the sign and scale will be 0). Hence, the literal 2.900m will be parsed to form the decimal with sign 0, coefficient 2900, and scale 3.

Looking at the third bullet point, you can see the phrase "...This literal is converted to a decimal value by taking the exact value...". The value you are getting (0.0000000000000000000000000001) is the converted result of the input literal (1.123456789123456789123456789E-28M) that you started with. Of course, with the value rounded as per the second part of the third bullet-point regarding the conversion "...if necessary, rounding to the nearest representable value using banker's rounding...".

This is true for decimal, but for float or double the exponential notation can be preserved by the data type itself, so no conversion/rounding is necessary.

Addition:

To expand further on the above, see: https://msdn.microsoft.com/en-us/library/364x0z75.aspx

This is the definition for the decimal data type. As noted there: the range of decimal is (-7.9 x 1028 to 7.9 x 1028) / (100 to 28) or 28 to 29 significant digits. Your literal, 1.123456789123456789123456789E-28M is beyond that limit, so when it is converted, everything to the right of the 1 is rounded as per the rules above.

Solution(?):

If you need a larger precision than decimal can provide, you may want to look into implementing your own class, which is definitely doable. Consider searching for C# implementations of BigDecimal for ideas.

One implementation I found on a quick google: https://gist.github.com/nberardi/2667136

I cannot speak to its correctness, but it could at least be a starting point for you.

gmiley
  • 6,531
  • 1
  • 13
  • 25
1

float and double are floating point numbers. That means that they are holding number and exponential coefficient separatly, where double is double size of float. double is not recommended to use in cases when precision is important, for example prices.
decimal is holding numbers in "decimal" form, with fixed point. It's more precise, especially with decimal calculations.
It seems that double is more likely to be what you're looking for.

xill47
  • 77
  • 5