29

I am maintaining a C# desktop application, on windows 7, using Visual Studio 2013. And somewhere in the code there is the following line, that tries to create a 0.01 decimal value, using a Decimal(Int32[]) constructor:

decimal d = new decimal(new int[] { 1, 0, 0, 131072 }); 

First question is, is it different from the following?

decimal d = 0.01M; 

If it is not different, why the developer has gone through the trouble of coding like that?

I need to change this line in order to create dynamic values. Something like:

decimal d = (decimal) (1 / Math.Pow(10, digitNumber)); 

Am I going to cause some unwanted behavior this way?

7
  • I think you want : decimal[] d = new decimal[] {1,0,0,131072}; The constructor 'new decimal()' doesn't accept an array as a parameter. Commented Apr 15, 2016 at 14:04
  • 8
    @jdweng this overload does. Commented Apr 15, 2016 at 14:05
  • 1
    Submit it to thedailywtf.com Commented Apr 15, 2016 at 14:07
  • 1
    @jdweng No - the constructor takes an array that has to be exactly 4 items long and uses it to construct a single decimal object. Commented Apr 15, 2016 at 14:11
  • 1
    @jdweng That's a different constructor. The one that takes an array of 4 ints combines isNegative and scale into the 4th int. Commented Apr 15, 2016 at 14:41

6 Answers 6

12

It seems useful to me when the source of the decimal consists of bits.

The decimal used in .NET has an implementation that is based on a sequence of bit parameters (not just one stream of bits like with an int), so it can be useful to construct a decimal with bits when you communicate with other systems which return a decimal through a blob of bytes (a socket, from a piece of memory, etc).

It is easy now to convert the set of bits to a decimal now. No need for fancy conversion code. Also, you can construct a decimal from the inputs defined in the standard, which makes it convenient for testing the .NET framework too.

Sign up to request clarification or add additional context in comments.

2 Comments

Seems likely, especially since there is no BitConverter.ToDecimal() etc. I assume that Decimal.GetBits() is the other piece of the puzzle.
I don't think there's any relation between the .NET Decimal type and the type described on the Wiki page. That type has a much larger precision and range than the .NET type, which looks like a replacement for fixed decimal types designed by someone who didn't understand the importance of fixed decimal types having fixed precision [among other things, when using fixed-precision types, if (x+y)+z and x+(y+z) can be evaluated without an overflow trap, both will yield the same result; that isn't true with any floating-point types, including Decimal].
9

The decimal(int[] bits) constructor allows you to give a bitwise definition of the decimal you're creating bits must be a 4 int array where:

bits 0, 1, and 2 make up the 96-bit integer number.

bits 3 contains the scale factor and sign

It just allows you to get really precise with the definition of the decimal judging from your example I don't think you need that level of precision.

See here for more detail on using that constructor or here for other constructors that may be more appropriate for you

To more specifically answer your question if digitNumberis a 16bit exponent then decimal d = new decimal(new int[] { 1, 0, 0, digitNumber << 16 }); does what you want since the exponent goes in bits 16 - 23 of last int in the array

1 Comment

"bits 0, 1, and 2 make up the 96-bit integer number" I think that's a very confusing formulation, since it sounds like you combine 3 bits and get 96 bits. (Authors of .Net didn't help you by naming the parameter bits.)
3

The definition in the xml is

 // // Summary: // Initializes a new instance of System.Decimal to a decimal value represented // in binary and contained in a specified array. // // Parameters: // bits: // An array of 32-bit signed integers containing a representation of a decimal // value. // // Exceptions: // System.ArgumentNullException: // bits is null. // // System.ArgumentException: // The length of the bits is not 4.-or- The representation of the decimal value // in bits is not valid. 

So for some unknown reason the original developer wanted to initialize his decimal this way. Maybe he was just wanted to confuse someone in the future.

It cant possibly affect your code if you change this to

decimal d = 0.01m; 

because

(new decimal(new int[] { 1, 0, 0, 131072})) == 0.01m 

4 Comments

There is a IEEE standard describing decimal, nothing confusing here.
Why can't Microsoft cal a Rose a Rose and make up their own names. The link Patrick provide has done everything to avoid calling the IEEE floating point number a floating point number.
Reasoning by using == is not a great idea: (new decimal(new int[] { 10, 0, 0, 0x30000})) == 0.01m also returns true. And while the two values represent the same number, they are not the same decimal value (it's 0.010, not 0.01).
Is there any situation where 0.010 != 0.01?
2

You should exactly know how decimal stored in memory.

you can use this method to generate the desired value

public static decimal Base10FractionGenerator(int digits) { if (digits < 0 || digits > 28) throw new ArgumentException($"'{nameof(digits)}' must be between 0 and 28"); return new decimal(new[] { 1, 0, 0, digits << 16 }); } 

Use it like

Console.WriteLine(Base10FractionGenerator(0)); Console.WriteLine(Base10FractionGenerator(2)); Console.WriteLine(Base10FractionGenerator(5)); 

Here is the result

1
0.01
0.00001

Comments

2

The particular constructor you're talking about generates a decimal from four 32-bit values. Unfortunately, newer versions of the Common Language Infrastructure (CLI) leave its exact format unspecified (presumably to allow implementations to support different decimal formats) and now merely guarantee at least a specific precision and range of decimal numbers. However, earlier versions of the CLI do define that format exactly as Microsoft's implementation does, so it's probably kept that way in Microsoft's implementation for backward compatibility. However, it's not ruled out that other implementations of the CLI will interpret the four 32-bit values of the Decimal constructor differently.

Comments

1

Decimals are exact numerics, you can use == or != to test for equality.

Perhaps, this line of code comes from some other place where it made sense at some particular point of time.

I'd clean it up.

5 Comments

Well. such code is in the Windows Forms generated code. Not easy to clean up and totally useless since it will be generated back to what it was.
Doesn't mean it's good code =) I bet if I open forms auto-generated code with ReSharper on, the whole scrollbar will be orange =)
In what sense are decimal numbers 'exact numerics'?
I'm not really sure how this answers the question.
The set of values that Decimal can represent precisely lines up with human-readable notation more nicely than the set of values that Double can represent precisely, but neither is more or less "exact" in the general case.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.