# Why are there so many numeric types (bit, int, float, double, long)?

I've learned PHP, Java, and C. Now I'm curious as to why there are so many types of numerical data types like bit, int, float, double, and long. Why not make only one type for numericals?

Is there any benefit to this? Maybe if we use integers to hold such small numbers we can save memory?

• In addition to HorusKol's answer: 'float' and 'integer' types are inherently different. Floats can hold very large numbers, but as the size of the number goes up, the precision goes down. This imprecision is because of the way floats are stored. By contrast, the range of values you can store in an integer is quite limited, but the value is always exact, so you can compare values much easier. Also, there are two different types of behaviour with division -- integers 'truncate' to the nearest whole number automatically, floats do not. Each of these behaviours are useful for different situations. – kampu May 25 '13 at 5:45
• Javascript only has one number type on the surface. – Esailija May 25 '13 at 11:18
• @kampu: Actually, in many languages, integers can store any number as long as the (virtual) memory is big enough to represent it. – Jörg W Mittag May 26 '13 at 0:08
• @JörgWMittag: However, that's questioner clearly is talking about static languages, not dynamic languages like Python, for example. CPython itself implements the 'unlimited range' integer as an array of 32bit ints, with the final bit in each int used to indicate if there are more bits to go. Also, integers can store any whole number only. That means that a float with infinite storage can store values to the precision (infinity aleph one), while integers can store values only to precision (infinity aleph zero). – kampu May 26 '13 at 1:12
• @kampu: Since all numbers are represented by series of bits, even with infinite storage, there will always be a one to one mapping between floating point numbers and integers. So I don't think aleph one comes to question. – COME FROM May 27 '13 at 6:39

## 7 Answers

There are two reasons why you should be concerned with the different numerical data types.

# 1. Saving memory

``````for(long k=0;k<=10;k++)
{
//stuff
}
``````

Why use a long when it could just as easily be an integer, or even a byte? You would indeed save several bytes of memory by doing so.

# 2. Floating point numbers and integer numbers are stored differently in the computer

Suppose we have the number 22 stored in an integer. The computer stores this number in memory in binary as:

``````0000 0000 0000 0000 0000 0000 0001 0110
``````

If you're not familiar with the binary number system this can be represented in scientific notation as: 2^0*0+2^1*1+2^2*1+2^3*0+2^4*1+2^5*0+...+2^30*0. The last bit may or may not be used to indicate if the number is negative (depending if the data type is signed or unsigned).

Essentially, it's just a summation of 2^(bit place)*value.

This changes when you are referring to values involving a decimal point. Suppose you have the number 3.75 in decimal. This is referred to as 11.11 in binary. We can represent this as a scientific notation as 2^1*1+2^0*1+2^-1*1+2^-2*1 or, normalized, as 1.111*2^2

The computer can't store that however: it has no explicit method of expressing that binary point (the binary number system version of the decimal point). The computer can only stores 1's and 0's. This is where the floating point data type comes in.

Assuming the sizeof(float) is 4 bytes, then you have a total of 32 bits. The first bit is assigned the "sign bit". There are no unsigned floats or doubles. The next 8 bits are used for the "exponent" and the final 23 bits are used as the "significand" (or sometimes referred to as the mantissa). Using our 3.75 example, our exponent would be 2^1 and our significand would be 1.111.

If the first bit is 1, the number is negative. If not, positive. The exponent is modified by something called "the bias", so we can't simply store "0000 0010" as the exponent. The bias for a single precision floating point number is 127, and the bias for a double precision (this is where the double datatype gets its name) is 1023. The final 23 bits are reserved for the significand. The significand is simply the values to the RIGHT of our binary point.

Our exponent would be the bias (127) + exponent (1) or represented in binary

``````1000 0000
``````

Our significand would be:

``````111 0000 0000 0000 0000 0000
``````

Therefore, 3.75 is represented as:

``````0100 0000 0111 0000 0000 0000 0000 0000
``````

Now, let's look at the number 8 represented as a floating point number and as an integer number:

``````0100 0001 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 1000
``````

How in the world is the computer going to add 8.0 and 8? Or even multiply them!? The computer (more specifically, x86 computers) have different portions of the CPU that add floating point numbers and integer numbers.

• 3) albeit rarely an issue: Operations on numbers bigger than the computer's wordsize are slower. – Loren Pechtel May 25 '13 at 22:33

Back before we had gigabyte systems (or on modern embedded systems like Arduino), memory was at a premium and so shorthand methods were implemented to specify how much memory a particular number would take up - BIT is straightforward - it would originally occupy only 1 bit of memory.

The other data sizes and names vary between systems. On a 32-bit system, INT (or MEDIUMINT) would generally be 2 bytes, LONGINT would be 4 bytes, and SMALLINT would be a single byte. 64-bit systems can have LONGINT set at 8-bytes.

Even now - especially in databases applications, or programs that have multiple instances running on servers (like server side scripts on websites) - you should be careful about what you choose. Picking a 2, 4, or 8-byte wide integer to store values between 0 and 100 (which can fit in one byte) is incredibly wasteful if you have a database table with millions of records.

More information: https://en.wikipedia.org/wiki/Integer_(computer_science)

• nice answer +1. – Vinay May 25 '13 at 5:43
• Not only 'back before', but also 'now when a system is small'. On an device the size of Arduino one has to be economical. – 9000 May 25 '13 at 5:49
• What system used only 1 bit to store a bit? bits usually aren't directly addressable – jk. May 25 '13 at 6:14
• that's true in a lot of architectures - but bits were directly addressable in really old systems, and even some more recent embedded systems (some controllers I programmed only 10 years ago worked with bits - those only had about 64 addressable locations of specific widths). Nowadays, I guess compilers work it out and put them into byte-arrays. – HorusKol May 25 '13 at 6:35
• I think the overriding factor is CPU ability and performance rather than memory concerns – James May 25 '13 at 19:18

In addition to cpmjr123's excellent points about memory scarcity and precision and range trade offs, thers is also potentially a CPU trade off.

Most modern machines have special hardware for performing floating point operations called an FPU. There are also systems that do not have FPU's (nowadays these are typically small embeded devices), consequently, depending on your target hardware, you would either have to not use floating point types at all or use a software floating point library. Even if your machine has an FPU there were historically differences in what functions it could provide. Any functions not done in hardware would have to be done in software (or avoided)

Doing floating point calculations in software is done by performing many simpler operations the hardware does support. You therefore get a potential speed trade off as well.

Perhaps the most important thing is that there are really three different basic number types.

integer, fixed decimal and floating point.

They all behave differently.

A simple operation like 7/2 could give answers of 3, 3.50 and 3.499 depending on the data type used.

"fixed decimal" is the Cinderella type, it is only supported natively in a few languages like COBOL and VisualBasic. It is of little interest to computer scientists but is vital to anyone submitting a set of accounts or calculating sales tax on an invoice.

• I'd separate them differently: discrete numbers, approximate numbers, and wrapping algebraic rings. Typical examples in C would be `int`, `float`, and `unsigned int`, respectively. Fixed-point types are a subcategory of discrete types, but algebraic rings are fundamentally different from numbers [must of the confusion regarding unsigned types in C stems from the fact that they mostly behave like rings rather than numbers, but aren't quite consistent]. – supercat May 27 '14 at 22:16

Is there any benefit they make it?

Of course. There are benefits. In the world of computers memory is one of the most important thing to consider. What is the use of having a memory of 2kb when the data can fit in less than 1kb?. Optimizations should be there. If you use more memory it obviously kills your computers speed at a point. Do you really like to have it? No right...?

``````int - 2 bytes (16 bits)

long - 4 bytes (32 bits)

long long - 8 bytes (64 bits)

float - 4 bytes
``````

Not only the memory but there are organization of type of numbers as well. for an instance floating point. The precision matters a lot and obviously we should have one type which can give us more precision.

If we consider olden days, we had a very less memory as you might know. To save it and use it wisely we had these differences. And much more if you just go ahead and give some try on searching with google.. Hope this helps.

integers and real (float,double) numbers are conceptually different types with different sets of operations and intrinsic properties.

Integers are enumerable but floats are not, etc.

In fact Float/double number is a structure that combines two integer fields: mantissa and exponent. Complex numbers (that you excluded from consideration) are even more, well, complex.

Any practical language should have at least integers and floats as distinct types - too different operations on them.

• I'm not familiar with the "complex numbers" you've mentioned. Can you explain further? – cpmjr123 May 25 '13 at 12:34
• check this: en.wikipedia.org/wiki/Complex_number – c-smile May 25 '13 at 16:06
• I am aware of complex numbers in the form of a+bi. I was asking for more information on how the computer stores complex numbers. To my knowledge, there are no primitive data types that support this. – cpmjr123 May 26 '13 at 6:23
• Complex numbers are typically stored as two floating point values, namely their `a` (real part) and `b` (imaginary part). CPU typically do not implement native support for operations on complex numbers, although CPU may implement accelerated multiply-add instructions for operations on pairs of values, such as (ab+cd) and (ab-cd). – rwong May 27 '13 at 19:26
• Additionally, many languages have some types whose behavior is largely defined as that of an wrapping algebraic ring (e.g. if a variable of type `uint16_t` holds 65535, incrementing it will make it hold 0). Ideally, languages would have cleanly-separate types for representing wrapping algebraic rings and numbers (allowing numbers that overflow to be trapped, while allowing code to easily perform operations on things that are expected to wrap). – supercat Sep 15 '14 at 18:42

Additionally to the fact that floating-point types behave completely different from integer types, I want to give a more extreme example why size per number really matters.

Imagine you want to sort a (long) array. For example in C:

``````int numbers;
``````

So here we have 100 Million numbers.

If each number is only one byte long (so using `unsigned char` instead of `int`), then this needs 100 Million bytes of space.

If you use `double`, then this usually are 8 bytes per number, so 800 Million bytes of space.

So each time you operate with a lot of objects (numbers in this example), size per object (size per number in this example) really does matter.