My question is, why not use fractions?
Quick answer:
- Too much code needed
- Dynamic storage needed
- Long representation even for simple numbers
- Complex and slow execution
And most prominent:
- Because floating point is already based on fractions:
Binary ones, the kind a binary computer handles best.
Long Form:
The mantissa of a floating point number is a sequence of fractions to the base of two:
1/2 + 1/4 + 1/8 + 1/16 + 1/32 + 1/64 + 1/128 ...
Each holding a zero or one denoting if that fraction is present. So displaying 3/8th gives the sequence 0110000...
A fraction is just two numbers which, when divided by each other, yields the number you are interested in. So picture a struct which holds one integer of whatever size, and one byte for each of divisor and dividend.
That 'whatever size' is eventually the most important argument against. An easy to implement system does need a representation as short as possible to save on memory usage - that's a premium, especially early machines - and it should use fixed size units, so memory management can be as simple as possible.
One byte each may not really be good to represent the needed fractions, resulting in a rather complicated puzzle of normalisation, which to be handled needs a rather large amount of divisions. A really costly operation (Hard or Softwarewise). In addition to the storage problem for the numbers, this would require even more address space to hold the non trivial handling routines.
Binary (*1) floating point is based on your idea of fractions, but takes it to the logical end. With binary FP there is no need for many complex operations.
- Turning decimal FP into binary is just a series of shift operations.
- Returning it to decimal (*2) is again just shifting plus additions
- Adding - or subtracting - two numbers does only need a binary integer addition after shifting the lesser one to the right.
- Multiplying - or dividing - means multiplication - or division - of a these two fixed point integers and addition of the exponent.
All complex issues get reduced to fixed length integer operations. Not only the most simple form, but also exactly what binary CPUs can do best. And while that length can be tailored to the job (*3), already rather thrifty ones (size wise) with just 4 bytes storage need will cover most of everyday needs. And extending that to 5,6 or 8 gives a precision rarely needed (*4).
And probably we all remember how to add or subtract fractions from school.
No, we don't really. To me that was something only mentioned for short time during third grade. Keep in mind most of the world already went (decimal) floating point more than a century ago.
*1 - Or similar systems, like IBM's base-16 floating point used in the /360 series. Here the basic storage unit isn't a bit but a nibble, acknowledging that the memory is byte-orientated and parts of the machine nibble-orientated.
*2 - The least often done operation.
*3 - Already 16 bit floating point can be useful for everyday issues. I even remember an application with a 8 bit float format used to scale priorities.
*4 - Yes, there are be use cases where either more precision or a different system is needed for accurate/needed results, but their number is small and special - or already covered by integers:)