I've never understood why a float datatype is considered an approximation while a decimal datatype is considered exact. I'm looking for a good explanation, thanks.

- 3,291
- 4
- 35
- 48

- 5,074
- 4
- 42
- 89
-
http://en.wikipedia.org/wiki/Floating_point – Mat Sep 10 '11 at 15:24
-
possible duplicate of [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) – xanatos Sep 10 '11 at 15:41
4 Answers
Well, it depends on your point of view. Both float
and decimal
(assuming you mean types like the ones in C#) represent exact values. However, in both cases conversions (and arithmetic) can end up with approximations where the value stored is only "the closest one available to the theoretical exact value".
In particular - and importantly the normal cause of the "float
is approximate" idea - is conversions of literal values in code:
float f = 0.1f;
decimal d = 0.1m;
These literals are expressed in terms of decimal numbers - and 0.1 can't be exactly represented as a binary floating point number. However, it can be represented exactly as a decimal floating point number.
If we used binary for literals, e.g.
// Imaginary syntax - doesn't work in C#!
float f = 0b0.11f;
then there wouldn't be any approximation here - that value would be exactly the same as the decimal value 0.75.
Basically it's all about the bias of humans to think about numbers in base 10. From the point of view of an alien with 3 fingers on a single hand who represented values in base 3 naturally, both float
and decimal
would be "approximations".
(There are other significant differences between float
and decimal
in C# around the significant digits vs the range of values, but that's a different matter.)

- 1,421,763
- 867
- 9,128
- 9,194
-
Can you explain me how you wrote 0B0.11? I think I'm quite lost :-) Or should it be 0.11B? – xanatos Sep 10 '11 at 15:33
-
@xanatos: It's not *real* syntax (at least in C#) - it's just "imagine if we could write floating point literals in this syntax". I used "0B" as a prefix to represent the base in the same way that we use "0x" for hex, as opposed to using a *suffix* to indicate the type of value being represented. – Jon Skeet Sep 10 '11 at 15:35
-
Yes yes... But my first problem was that I hadn't ever thought of writing a non-integer binary number, and then why you put the B in the middle. – xanatos Sep 10 '11 at 15:36
-
@xanatos: The B is just for "binary", that's all. Would it be better as "0b" do you think? And I could make the sample value "0b11.01" which would be equivalent to decimal 3.25 if it would be helpful... – Jon Skeet Sep 10 '11 at 15:40
-
Clear! It's like 0x for hex! No no it's clear... But I was mixing the B with the f of float. You should have written `0B0.11f` then! There isn't an implicit conversion betwen Double and Float :-) For the casing... Whell... The X can be upper or lower, so I think the B should follow the same rule. – xanatos Sep 10 '11 at 15:43
-
@xanatos: Okay, will change to 0b0.11f. I think "b" is slightly clearer than "B". – Jon Skeet Sep 10 '11 at 15:48
-
@Skeet - The reason I asked and the problem I'm having is this. The database language I'm using only allows 4 decimal places in the exact types (Decimal/Numeric). That is fine if I'm storing financial data such as mortgage payments. However, to calculate the mortgage payment I need decimal precision that goes beyond 4 decimal places. I prefer to use 7 decimal places. So if I use a float type and store for example 22/7 rounded to two places will I always get 3.1428571? – Michael Riley - AKA Gunny Sep 10 '11 at 16:48
-
1@Cape Cod Gunny: Could you use an integer type instead? For example, store hundredths of a cent instead of dollars. – Jon Skeet Sep 10 '11 at 17:30
well, you're right - it's misleading to make such a blanket statement. to understand completely you need to grasp two things.
first, decimal is intended for storing (exactly) decimal values with a fixed number of decimal places. typically, money (where the decimals are cents, for example). that's a very specific use case. it's not an exact store for any value; it's only for decimal values with a fixed number of decimal points, and the implementation is tailored to do that correctly.
second, floats are intended to be a more general datatype - they are used to store "any" value - and the implementation reflects that (so, for example, the implementation aims to cover a wide range of scales and support operations as efficiently as possible). in particular, it uses a binary representation that cannot represent all decimal values exactly. so, for example, it can store 0.5 exactly, but it can't store 0.1 exactly. that's just a fact of life of the binary - base 2 - representation used, but it means that for money, floats are not a good idea: if you can't store 0.10 exactly as a float then any calculations involving 10 cents may accumulate unexpected errors.
in other words, both have their limitations. the only way that decimal is "more exact" than float is that it's easier to understand: the values for which it does work exactly are clearly defined, useful, and match the "natural" base 10 representation we use. in contrast, it's much harder to understand which values will be stored exactly by floats, and which not, because they depend on the underlying base 2 representation.

- 45,717
- 10
- 93
- 143
-
What do you mean "floats are intended to be more general"? Binary floats are to base-2 as decimal floats are to base-10. One is not more "general" than the other -- one simply suits representing numbers in base-2 and the other suits representing numbers in base-10. (Of course, since CPUs operate on binary, binary floats are obviuosly much faster.) – Kirk Woll Sep 10 '11 at 15:35
-
most software uses floats. it is treated as a more general datatype. people don't select float in their programs because they want to store binary data exactly; they select it because they're writing a general number-crunching algorithm. – andrew cooke Sep 10 '11 at 15:39
-
Sure, it's more popular. That's different from being more general. And people select float because it's already there (and faster!). But not because it solves a more general class of problems. – Kirk Woll Sep 10 '11 at 15:40
-
you're taking one meaning of the word "general" and forcing my text into using it. you're free to do that, but you're arguing against your own twisted reading, not what i intended. – andrew cooke Sep 10 '11 at 15:41
-
@Andrew - If I want 22/7 rounded to 7 decimal places and I say Round(22/7,7) will I always get 3.1428571? Unrounded it repeats for ever but because I specify rounding to 7 decimal it becomes exact. Is that a good way to understand how a float can be both an approximation and exact – Michael Riley - AKA Gunny Sep 10 '11 at 15:44
-
@cape cod gunny - not really. the problem is that float uses a base 2 representation. so even if you round something in decimal, it may not be rounded nicely in binary. maybe kirk woll has a point - do their comments help you at all? i tried extending the final para - is that clearer? – andrew cooke Sep 10 '11 at 15:48
-
@Andrew - Thanks for explaning this using english. I'm still no 100% clear on all this stuff, but I've got a much better grasp of what I have to do to make things work so I get accurate results. – Michael Riley - AKA Gunny Sep 11 '11 at 14:45
You can get all the gory details here, but basically IEEE floating point stores numbers as an integer mantissa times two raised to an integer power. Just like some fractions like one-third cannot be expressed exactly as a non-repeating base 10 decimal number, many fractions cannot be expressed exactly as binary fractions. This is often surprising because, while we're used to 1/3 as a repeating decimal we intuitively expect 1/5 to be easily represented as 0.2, but in binary it's a repeating decimal (binarial?) that cannot be exactly represented in a finite number of bits.

- 2,576
- 3
- 24
- 29
A decimal
value is exactly equal to the value of its string representation (edit: in decimal, as Skeet notes), and decimal
is also capable of exactly representing decimal numbers with a limited amount of digits. On the other hand, a float
value often will differ from its string representation, and there are many decimal numbers (such as 0.1) that cannot be exactly represented as a float
.

- 37,289
- 4
- 68
- 81