434,573 Members | 938 Online + Ask a Question
Need help? Post your question and get tips & solutions from a community of 434,573 IT Pros & Developers. It's quick & easy.

How to determine which of the generic decimal datatypes to use.

 P: n/a John Bentley: INTRO The phrase "decimal number" within a programming context is ambiguous. It could refer to the decimal datatype or the related but separate concept of a generic decimal number. "Decimal Number" sometimes serves to distinguish Base 10 numbers, eg "15", from Base 2 numbers, Eg "1111". At other times "Decimal Number" serves to differentiate a number from an integer. For the rest of this post I shall only use either "Generic Decimal Number " or "decimal datatype" for clarity. DEFINTIONS Generic Decimal Number: a base 10 number with a fractional part represented with digits. A Generic Decimal Number may be implemented with any of several datatypes including the decimal datatype, a double, a single, a string. Decimal Datatype: the .Net (or other programming language) decimal datatype. ISSUES When programming with generic decimal numbers there are a few of key issues to consider: 1 How to round a number. 2 How to determine which of the generic decimal datatypes to use: Single; Double; or Decimal 3 Determine if two generic decimal numbers are equal. 4 Work with fractions that cannot be represented accurately as a generic decimal numbers. These are interrelated issues but for the moment I'm interested in 2. Would you like to tell me the rules you use when deciding to use the floating point datatypes (Single and Double) V the Fixed Point/Scaled Integer Datatype (Decimal)? By all means address other related issues if it helps in the answering of this question. Although I would be interested in answers that relate to .NET specifially I'm interested more in the general mathematical/computational ideas that govern the choice. Jul 19 '05 #1
17 Replies

 P: n/a John Bentley wrote: These are interrelated issues but for the moment I'm interested in 2. Would you like to tell me the rules you use when deciding to use the floating point datatypes (Single and Double) V the Fixed Point/Scaled Integer Datatype (Decimal)? By all means address other related issues if it helps in the answering of this question. Although I would be interested in answers that relate to .NET specifially I'm interested more in the general mathematical/computational ideas that govern the choice. http://www.pobox.com/~skeet/csharp/floatingpoint.html gives some of the details of floating point numbers, and some suggestions as to when to use what. It's not exactly what you were after, but hopefully you'll find it useful. -- Jon Skeet - http://www.pobox.com/~skeet/ If replying to the group, please do not mail me too Jul 19 '05 #2

 P: n/a > http://www.pobox.com/~skeet/csharp/floatingpoint.html gives some of the details of floating point numbers, and some suggestions as to when to use what. It's not exactly what you were after, but hopefully you'll find it useful. Jon, that is exactly the type of thing I was after. Yours is a well written article. Standby 1 or 2 days: I am digesting the issues you raise there. I will have some questions. Thanks for publishing it. Jul 19 '05 #3

 P: n/a John Bentley wrote: http://www.pobox.com/~skeet/csharp/floatingpoint.html gives some of the details of floating point numbers, and some suggestions as to when to use what. It's not exactly what you were after, but hopefully you'll find it useful. Jon, that is exactly the type of thing I was after. Yours is a well written article. Thanks - that's very kind of you. Standby 1 or 2 days: I am digesting the issues you raise there. I will have some questions. Thanks for publishing it. Questions are more than welcome - they'll suggest ways I could expand the article, for one thing :) -- Jon Skeet - http://www.pobox.com/~skeet/ If replying to the group, please do not mail me too Jul 19 '05 #4

 P: n/a John Skeet, Your last post and new article on the decimal datatype taught me more. I still have a lot to digest from these. Standby about 3 days for a fuller response. I am writing my own articles that parallel yours in many ways. In short (and as a preview) the insight that you've given me is precisely the distinction Binary Versus Decimal Datatype: All datatypes are ultimately represented as binary bits, However for nonintegral numbers the base of the scaling is different. For Doubles and Singles ("Binary Datatypes") it is a base 2 scale, for decimals ("Decimal Datatypes") it is base 10. This is why 0.1 can be represented exactly in a decimal datatype but not in a binary datatype. To help me with this could I trouble you/ challenge you to write a function to return the Binary representation of a Double? Eg (To Copy straight from your example) In: 46.42829231507700882275457843206822872161865234375 Out: 01000000010001110011011011010010010010000101011100 11000100100011 I was about to attempt it myself after succesfully doing this for a Decimal (due with thanks to your hint about Decimal.GetBits. Alas the job appears a bit tricky. I dare say you will be able to whip something up though (?) Jul 19 '05 #8

 P: n/a > Ah, that's easy :) using System; using System.Text; public class Test { static void Main() { Console.WriteLine (ToDoubleBitsString (46.4282923150770088227545784320682287216186523437 5d)); } static string ToDoubleBitsString(double d) { long bits = BitConverter.DoubleToInt64Bits(d); return Convert.ToString (bits, 2).PadLeft (64, '0'); } } Brilliant! :) Bravo Jon. Now I have all the tools (I think) to digest your articles and the issue. Expect fuller post in 3 days. Jul 19 '05 #9

 P: n/a > ------------------------------------------------- John Bentley wrote (at this indent level): ------------------------------------------------- Ah, that's easy :) using System; using System.Text; public class Test { static void Main() { Console.WriteLine (ToDoubleBitsString (46.4282923150770088227545784320682287216186523437 5d)); } static string ToDoubleBitsString(double d) { long bits = BitConverter.DoubleToInt64Bits(d); return Convert.ToString (bits, 2).PadLeft (64, '0'); } } Brilliant! :) Bravo Jon. Now I have all the tools (I think) to digest your articles and the issue. Expect fuller post in 3 days. Jon. Probably another 3 days :) Jul 21 '05 #10

 P: n/a John Bentley wrote: My current inclination is to use, then "Binary scaled nonintegral Datatype" versus "Decimal scaled nonintegral datatype". Or, for short, a "Binary scaled Datatype" versus "Decimal scaled datatype". I am preferring these terms over your current ones as: Fair enough. I still prefer my terms as I think they're more commonly used, but it's really just a matter of taste - the main thing is that we can understand each other :) One alternative way of putting it for me would be "floating binary point" or "floating decimal point" - how does that grab you? It is enough to know that for BOTH binary scaled datatypes and decimal scaled datatypes 1/3 (and other fractions) are never stored exactly, they only ever are sometimes APPARENTLY stored exactly. Or as you say "Whatever base you come up with, you'll have the same problem with some numbers - and in particular, "irrational" numbers (numbers which can't be represented as fractions)" It's worth noting that 1/3 *isn't* an irrational number though - and indeed if we had a base 3 floating point number type, it would be exactly representable (but 1/2 wouldn't be). Still, however, The question of "Which nonintegral datatype should you choose?" is still open. In order to answer this can we now aggree that the following statement from microsoft is wrong? "The Decimal value type is appropriate for financial calculations requiring large numbers of significant integral and fractional digits and no round-off errors." VS Documentation/MSDN > .NET Framework Class Library > Decimal Structure The part that is wrong, I claim, is that the decimal value type is not immune from round off errors in financial applications. Where 1/3 is involved, for example, you might well get a round off error. It is just less prone to round off errors than a binary scaled datatype because it will have more exact representations (true or false?). If you have a scolarship fund of \$100, for example, that is to be divided equally between 3 students then it's not clear who will get the 1 cent. Am I right to claim that the MS statement is wrong or is there a way of contextualising the statement to make it both true and expose a deeper understanding? I think the difference is that most of the time financial calculations *don't* require divisions like that. They usually include a lot of addition and subtraction, and multiplication - but rarely actual division. On the other hand, I haven't done much financial work, so that's really speculation. Certainly as soon as division comes in, you're likely to get inaccuracies. Ah, but look at it the other way: double stores a much larger range, despite holding it in a smaller amount of memory. That *must* mean that it's representing values more sparsely (if you see what I mean). I do (I believe) see what you mean, but perhaps not clearly the truth of it. Could we then write that 0.1 is such a sparse value under the double datatype?: it has trouble represententing this and many other values exactly where the decimal datatype does not. I'm not sure what you mean by a "sparse value" here. Put it this way: Suppose we had two data types, one of which represented a thousand numbers between 0 and 10000, and another of which represented a hundred numbers between 0 and 10000000 - there will be more of a "gap" between represented numbers in the second type than in the first type, on average. No - because they have a different range. On the other hand, every number which can be exactly represented as a double *and* is within the decimal range *and* which has 28 or fewer significant digits in its exact decimal string representation can be exactly represented as a decimal. Thanks, that helps. I concur. Now could a financial application have a number which: 1. can be represented exactly as a double; and 2. is inside the decimal range ( -7.923E+028 < x < +7.923E+028 ); and 3. has *more than* 28 significant bits to the right of the decimal point. ? It could - but I suspect it's unlikely. More simply, are there numbers that could arise in a financial application that can be exactly represented by a double but can't be represented at all by a decimal? I think it's unlikely, and you'd be *extremely* unlikely to actually know for sure that such a number would be exactly represented - it would be pure fluke. If that is true then we ought then ask: are there numbers that *would arise as a matter of course* in a financial application that can be exactly represented by a double but can't be represented at all by a decimal? That's basically not true. The above questions still stand though. Looking at a scientific appliation now. If it is true that a decimal is less prone to round off error then wouldn't you *definitely* use this for a scientific application. When building the sky scrapper for example, it is important when adding the floors to find the total height that there is no massive error. Futhermore, it would be unlikely that any girder on any floor will be built to a tolerance requiring more than 28 decimal places (or even 20). There will be no *massive* error using double. The error is likely to be smaller than the engineers would be able to cope with anyway. The real world doesn't tend to be as precise as a double, in other words. -- Jon Skeet - http://www.pobox.com/~skeet If replying to the group, please do not mail me too Jul 21 '05 #12 