3

In programming languages, for represent numbers you have (mainly) two types: Int(s) and floats.

The us of Int is very easy. However floats cause a lot of unexpected surprises:

http://anh.cs.luc.edu/python/hands-on/3.1/handsonHtml/float.html

I wonder why is not used a decimal-based type make more sense as the default for literals and normal math?

Where normal math is more precise?

mamcx
  • 412
  • 3
  • 8
  • One reason is that you can easily fake a decimal type at the application level using `int`. Faking `float` is much more difficult. – Gort the Robot Aug 24 '13 at 20:46
  • 1
    I know at least 2 languages that have a BCD type, they are COBOL and 370-Assembler. You could try them. – ott-- Aug 24 '13 at 20:47
  • @StevenBurnap Faking a *fixed-point* decimal number if easy with an `int`. But so is a fixed-point binary number, I'd wager. A decimal *floating-point* number (yes, that's a thing) is hard too. And in any case, this is only an argument for having a built-in implementation, not for making said implementation the *default*. –  Aug 24 '13 at 20:51
  • @delnan - that is just plain wrong. A decimal floating point number is not too hard. For example, look at .Net's [System.Decimal](http://msdn.microsoft.com/en-us/library/system.decimal.aspx) (just decimal in C#) – Dave Hillier Aug 24 '13 at 20:54
  • @DaveHillier I didn't say "too hard", I said "hard". I can't judge whether it's exactly as hard to implement as a binary float (the naive, slow, inaccurate algorithms are probably more familiar as we're used to base 10), but it's nowhere as simple as a fixed-point format. –  Aug 24 '13 at 20:58
  • @delnan sorry, I transposed the words as I read that! – Dave Hillier Aug 24 '13 at 23:11
  • actually ints have bigger/easier-to-find gotchas than floats (nearly any time you use division) – ratchet freak Aug 24 '13 at 23:41

3 Answers3

6

Languages which are using a single representation of numbers are relatively rare. As statically typed I can think only of some basic variants, and even in the dynamically typed realm I know more which are using at least integers and float than a unique format. Those who are came relatively late in the game and the choice of binary floating point is probably the result of the fact that binary floating point was already available in hardware and as type in the implementation language of their interpreter.

Now, why binary floating point has become the method of choice for type modelling real numbers?

If you want a type to modelize real numbers while using a constant size of a few words, you have the choice between fixed point and floating point numbers. Other kind of representation for rational numbers (fixed point and floating point are able to represent only rational number and a few other value like infinities -- which aren't real numbers BTW) exist but they are less widely useful.

Fixed point representations have some advantages, but they have one big issue: there is no good default for the number of digits after the point, so all languages and libraries which provide them ask the programmer to choose in the context of their application.

Floating point representations don't have that problem: once the size is fixed, you can come up with a repartition between the significand (often improperly called the mantissa) and the exponent good enough that allowing to customize it brings more problems than it would solve.

You may wonder why one has chosen a binary floating point format (BFP in the following of the discussion) instead of a decimal one. Decimal floating point (DFP) has one (and none more) advantage over binary: it can represent exactly real constant as we usually write them, in decimal. All other problems of BFP are also problems of DFP, but they may be hidden for simple enough computations by the advantage above (you get the exact result because the computation is so simple that all results -- final and intermediary -- are exactly representable).

DFP has some disadvantages of his own. Some properties of real numbers are also properties of BFP, but not of DFP (the most obvious is that (a+b)/2 may be outside the closed interval [a, b] with DFP) and because of that and for some other reasons, analysis of numerical properties of algorithms is more difficult for DFP than for BFP. Worse, error bound achievable with DFP are worse than one achievable with BFP for a given representation size. Implementing DFP is more difficult than implementing BFP (not so much that it has any importance nowadays, but it was a factor -- both of complexity and achievable performance -- when the trend was set). Finally for scientific computing -- historically the major consumer of FP -- the advantage of DFP is not pertinent, while all its disadvantages are.

So you got BFP in the hardware because it was what people needing FP wanted, and although some language definitions allow for DFP, implementations rarely use the possibility and prefer to use what the hardware provides.

AProgrammer
  • 10,404
  • 1
  • 30
  • 45
  • IMHO, I think the majority of the times a number is used for counting (for i=1 to 10), specify a value (age = 10) and basic arithmetic (+-*/). But look like is expected something more complex than that? – mamcx Aug 24 '13 at 21:02
  • For the few languages which are using a unique number type, the direct availability of binary FP in hardware and in C probably explain it. – AProgrammer Aug 24 '13 at 21:23
  • Decimal floating point formats are pretty nasty in a lot of ways, since they require frequent expensive normalization and denormalization steps. The simple act of subtracting two numbers will frequently require that one be divided by a power of ten prior to the subtraction, and may then require that the result be multiplied by a power of ten. Such division and multiplication is much more expensive than shifting. – supercat Oct 23 '14 at 01:39
  • 1
    @supercat, floating point, whatever the base, implies normalization and denormalization steps. – AProgrammer Oct 23 '14 at 06:53
  • @AProgrammer: Yes, but *division and multiplication is much more expensive than shifting*. – supercat Oct 23 '14 at 14:47
  • @supercat, DFP format are usually BCB based, so normalization is shifting (but for software implementation, I'd not be surprised if keeping the significant part in binary and doing the normalization by multiplication -- by reciprocal for division -- would not be better performancewise). – AProgrammer Oct 23 '14 at 15:02
  • @AProgrammer: I don't know of any significant use of BCD on any post-1970s processors. People writing games for the Atari 2600 use it a lot because it's generally necessary to convert a score to a string of character pointers in under 150 cycles, which would be way too little time for a binary-to-decimal conversion, but I don't know of any CMOS processors (or, for that matter, any processors other than the *NMOS* 6502) with a BCD carry chain that can handle more than one digit per cycle. Even the mostly-compatible CMOS version of the 6502 requires an extra cycle when performing BCD math. – supercat Oct 23 '14 at 15:25
  • @AProgrammer: Actually, the approach I would like to see for "arbitrary precision" decimal types would be to use each word to encode nine decimal digits. A number with 10 digits to the left of the decimal and 10 to the right would require four words to store (plus the exponent), with the first and last word holding one digit each, and a little work would be required when rounding off individual digits, but no division longer than 64x32->32r32 would be required except when dividing one big number by another. – supercat Oct 23 '14 at 15:38
  • @supercat, about BCD, see any IBM mainframe -- AFAIK COBOL mandate the availability of BCD -- and the IEEE 754-2008 standard decimal exchange format has provision for three decimal digits per 10 bits encoded in something which is more a packed BCD form than binary (there is also provision for a binary significant, IIRC IBM mainframe and POWER have them available in hardware). – AProgrammer Oct 23 '14 at 15:50
  • @supercat, about an unbounded type, my unbounded integer implementation is templated on the base as well as on the representation type and one reason is that I sometimes use a big decimal base. – AProgrammer Oct 23 '14 at 15:52
  • @AProgrammer: I've heard about some features in IEEE 754-2008, but I've not seen the standard nor am I aware of any features emerging into programming languages yet. My biggest peeve with IEEE 754 is with its failure to define a set of relational operators that would be suitable for "data processing" [i.e. represent a complete ranking]. I've heard that's supposedly been added, but I've not seen any language or framework which supports it except through rather clunky methods. – supercat Oct 23 '14 at 15:55
  • @AProgrammer: Actually, I suppose that's my second biggest peeve--the first is the failure of the standard to specify that while the 80-bit type is intended for "temporary computations", any programming language which uses the type for its temporary calculations but fails to expose it to the programmer should be considered broken. – supercat Oct 23 '14 at 15:57
2

Languages use binary floating point numbers because that's what the hardware usually provides. Very few CPUs have instructions for handling decimal floating point numbers, and the adoption of the IEEE 754 appears to have fixed the decision for the future.

Ross Patterson
  • 10,277
  • 34
  • 43
1

Floating point numbers are a tradeoff between precision and accuracy. They are notable for their ability to handle very wide numeric ranges, with reasonable accuracy. They are therefore considered a "one size fits all" type.

If you take a floating point number, and constrain its range to those numbers that can be represented by the mantissa only, you can treat it like an integer for accuracy purposes (in other words, you won't get the weirdness you would normally get from floats; you can compare them exactly in an if statement, for example).

This is why Lua chose a floating point as its default data type; in a sense, you can get the best of both worlds.

See Also
How Lua handles both integer and float numbers?

Robert Harvey
  • 198,589
  • 55
  • 464
  • 673
  • .NET's `decimal` is only one possible decimal type. I haven't implemented one myself but I really doubt this is inherent to base 10 - in other words, I think one could have a decimal floating point type with a range comparable to IEEE 754 (but the same issues at that magnitude, of course). –  Aug 24 '13 at 20:30
  • @delnan: Anything is possible, given enough bits. The `decimal` type in .NET uses actual base 10 arithmetic. – Robert Harvey Aug 24 '13 at 20:33
  • So how does your answer address the question, as none of the facts you present disqualify base 10 floating point numbers as default data type? –  Aug 24 '13 at 20:34
  • See the fourth and fifth paragraphs. – Robert Harvey Aug 24 '13 at 20:35
  • Those paragraphs explain why some languages get away without a separate integer type, not why both those languages and those with a separate int type default to binary floating point. –  Aug 24 '13 at 20:36
  • I added some text to the first paragraph. Better? – Robert Harvey Aug 24 '13 at 20:37
  • No, not really. Perhaps I'm being dense, but all I see is reasons that floats are okay in some respects. But you don't seem to address OP's reasons to prefer decimal floats, and the downsides are not inherent but only due to the number of bits a particular implementation uses (consider arbitrary-precision decimals as in Python - they are potentially superior in range, accuracy *and* precision). You *could* argue that binary floats offer a greater range for the same number of bits, but the answer as of now doesn't and honestly that seems like a bad reason for many high-level languages. –  Aug 24 '13 at 20:47
  • @delnan: Adding two binary floating-point numbers with exponents that differ by `n` requires shifting the mantissa of the lower number to the right by `n` bits, keeping track of the last bit shifted out as well as a flag indicating whether any "1" bits were shifted out beyond it. Pretty cheap. Adding two decimal floating-point numbers with exponents that differ by `n` requires dividing the mantissa of the lower number by 10^n. *MUCH* more expensive. – supercat Sep 13 '13 at 20:27
  • @supercat And adding two arbitrary precision integers is much more expensive than adding two word-sized integers. Yet they're still widely used, even as default integer type in a number of programming languages. In any case, this stream of comments is not an appropriate forum for discussing the pros and cons of decimals (I was already stretching it with my previous comments). –  Sep 13 '13 at 20:53