3.6 – floating point types in C language

by subbu on September 1, 2013

Numbers with fractional part are called real constants. These are often called as floating point values. The name floating point refers to the fact that it can have variable number of decimal places. Say for example 12.34 has two decimal places and 14.7896 have four decimal places. Classification and construction of real constants was discoursed in previous section constants in C language part-2.

We use floating point types to store larger and the numbers with fractional part. C language provides three floating point types to handle real constants of different ranges those are float, double and long double.

Precision:

It is the accurate value of a number that, how many decimal places that it can store? For example the result of 1.0/3.0 is a recurring result 0.3333333…. and so on. The precision of a floating point number is how many digits that it can represent without information loss. Floating point types can only store certain number of decimal places, and the rest would be lost.

Floating point types in C language:

  • C language supports float, double and long double types to store real constants of different ranges and precision.
  • Floating point types have no unsigned types.
  • Here float takes 4 bytes, double takes 8bytes and long double takes 10 bytes of memory.
  • The range of float is -3.4×1038 to 3.4×1038, double is -1.7×10308 to 1.7×10308 and long double is -3.4×104932 to 1.1×104932.
  • Format specifier to float is %f or %e, double is %lf or %le and long double is %Lf or %Le.
  • float can handle 6 decimal places, double can handle 12 decimal places and long double can handle up to 14 decimal places.
#include<stdio.h>
int main()
{
float x=34.78654565656567;
double y=34.78654565656567;
long double z=34.78654565656567;
printf("%f equals to %e",x,x);
printf("\n%lf equals to %le",y,y);
printf("\n%Lf equals to %Le",z,z);
return 0;
}

Output in Turbo C 3.0:
34.786545 equals to 3.478654e+01
34.786546 equals to 3.478655e+01
34.786546 equals to 3.478655e+01

Take care of types and precision:

In C language floating point types can’t promise the accuracy. Care must be taken regarding the precision a type can handle and the types when we compare any two floating point type variables or constants.

#include<stdio.h>
int main()
{
float x=34.78654565656567;
printf("%.8f ",x);/*printing upto 8 decimal places*/
printf("\n.6f",x);/*printing upto 6 decimal places*/
return 0;
}

Output:
34.78654480
34.786545
Here the value printed by the printf() deviates from the original value that has assigned, because float type of variable can store only 6 decimal places and omits beyond that. That is why it could print up to 6 decimal places properly.

#include<stdio.h>
int main()
{
long double x=34.7865456587332128;
printf("%.6Lf ",x);/*printing upto 6 decimal places*/
printf("\n%.12Lf",x);/*printing upto 12 decimal places*/
printf("\n%.14Lf",x);/*printing upto 14 decimal places*/
return 0;
}

Output in Turbo C 3.0:
34.786546
34.786545658733
34. 78654565873321

Here long double can store accurately upto 14 decimal places.

Overflow and underflow of floating point types:

In case of integer types overflow results wrapping towards negative side, underflow results wrapping towards positive side.
In floating point types overflow results +INF and underflow results -INF
0/0 returns a floating point constant +NAN (Not a Number)

#include<stdio.h>
int main()
{
float x=-3.4e50;
float y=3.4e50;
printf("%f",x);
printf("\n%f",y);
return 0;
}

Output:
-INF
+INF

#include<stdio.h>
int main()
{
float x,y,z;
x=0.0/5.0;
y=7.0/0.0;
z=0.0/0.0;
printf("%f",x);
printf("\n%f",y);
printf("\n%f",z);
return 0;
}

Output:
0.000000
+INF
+NAN

Default literal types in C language:

Default integer literal type in C language is signed int:

Integer constants written in a program are by default signed int type.
Suffix “u” or “U” is used to make it unsigned int, “l” or “L” is used to make it  long int  and “lu” or “LU” is used to make it long unsigned.

a=1234;   /*signed int*/
b=45698u;  /* unsigned int */
c=-534201L;  /* long int */
d=64578uL; /* unsigned long int */

Default real literal type in C language is double:

Real constants written in a program are by default double type.
Suffix “f” or “F” can be used to make it as a float type literal and “l” or “L” can be used to make it as a long double literal.

x=23.567;  /* considers as double type */
y=23.567F; /* considers as float type */
z=23.567L; /* considers as long double type */

Example:

#include<stdio.h>
int main()
{
printf("%d\n%d\n%d",sizeof(5),sizeof(5.0),sizeof('s'));
return 0;
}

Output:
2
8
2
sizeof char type in C languageOutput of the above example demonstrates the fact that, by default any integer constant takes 2 bytes (int type), any floating point constant takes 8 bytes (double type). Here the case with sizeof(‘s’) is different, it returns the size of the type of ASCII value of ‘s’ that is the size of the type of 115, which is the size of int that is 2.

Note:
Care must be taken while comparing variables or constants of floating point types because comparing different floating point types result unexpected result.

Example:

#include<stdio.h>
int main()
{
float x=12.3456;
float y=14.1233;
if(x+y==26.4689)
printf("Hello");
else
printf("World");
return 0;
}

Output:
World

Comparing float and double types

It is bit surprising by printing World instead of Hello. The reason is that,  here x+y returns float type takes 4 bytes and 26.4689 is of double type takes 8 bytes. The 4 bytes of float type and 8 bytes of double types are compared, which may not be equal. It can be rectified by adding suffix “f” to double constant 26.4689 and making it as float before comparing with float type expression x+y

#include<stdio.h>
int main()
{
float x=12.3456;
float y=14.1233;
if(x+y==26.4689f)
printf("Hello");
else
printf("World");
return 0;
}

Output:
Hello

Conclusion:

Floating point types offer limited precision. 6 decimal places to float type, 12 decimal places to double and 14 decimal places to long double. Trying to use more than significant decimals will result in a loss of precision.

Floating point numbers often have small rounding errors. Regardless, comparisons on floating point numbers may not give the expected results when two numbers are close. We can avoid most of these errors by using proper suffix letters to match the types.

Previous post:

Next post: