## Sunday, 26 February 2012

### Integer and Floating Point Literals in C and C++

I played around in C++ with some code to see how it calculates numbers that are integers or floating point literals. The code, comments and results follow.

The term floating-point number is generic in that it doesn’t specify a byte size. A single-precision floating-point number is specific. In C/C++ it’s a 4 byte number with 6 decimal precision (e.g., 6.123456). A double-precision floating-point number uses 8 bytes and has 10 decimal precision (e.g., 10.0123456789).

Sample Code Part 1 – Declaring Variables with Literals.

The sample code was created in MS Visual C++ 2010 as a Windows Form Application. It contains a form (Form1) that displays when the program runs. The sample code, contained in the Form Load Event, executes and adds text to a RichTextBox named rtOut.

// Title.
rtOut->Text = "Experiments Declaring Integer & Floating-point Data Types.\n\n";

// declare variables
int iVal = 8;
rtOut->Text += "Declare: int data type (iVal) with literal 8: int iVal = 8;\n";
float fVal = 8.0;
rtOut->Text += "Declare: float data type (fVal) with literal 8.0: float fVal = 8.0;\n\n";

// Integer in a string.
rtOut->Text += "The int data type (iVal) is " + iVal + " in this string.\n";
rtOut->Text += "There is no decimal point or decimal numbers.\n\n";

// Float in a string.
rtOut->Text += "The float data type (fVal) is " + fVal + " in this string.\n";
rtOut->Text += "There is no decimal point or decimal numbers.\n";
rtOut->Text += "In debug mode, the local window shows: iVal: 8 fVal: 8.000000\n";
rtOut->Text += "\n";

int iVal2 = 8.2;
rtOut->Text += "Declare: int data type (iVal)  with literal 8.2: int iVal = 8.2;\n";
rtOut->Text += "Assigning a floating-point literal to an integer results in a compiler warning:\n";
// Warning 1 warning C4244: 'initializing' : conversion from 'double' to 'int', possible loss of data
rtOut->Text += "Warning    1 warning C4244: 'initializing' : conversion from 'double' to 'int', possible loss of data\n";
rtOut->Text += "The code is compiled and the program executes.\n";
rtOut->Text += "The variable holds the value of 8. The decimals are truncated.\n\n";

rtOut->Text += "To us, 8 and 8.0 are the same, but to C/C++ they aren't the same.\n";
rtOut->Text += "8 is an integer literal while 8.0 is a floating-point literal.\n";

Output

Experiments Declaring Integer & Floating-point Data Types.

Declare: int data type (iVal) with literal 8: int iVal = 8;
Declare: float data type (fVal) with literal 8.0: float fVal = 8.0;

The int data type (iVal) is 8 in this string.
There is no decimal point or decimal numbers.

The float data type (fVal) is 8 in this string.
There is no decimal point or decimal numbers.
In debug mode, the local window shows: iVal: 8 fVal: 8.000000

Declare: int data type (iVal)  with literal 8.2: int iVal = 8.2;
Assigning a floating-point literal to an integer results in a compiler warning:
Warning           1 warning C4244: 'initializing' : conversion from 'double' to 'int', possible loss of data
The code is compiled and the program executes.
The variable holds the value of 8. The decimals are truncated.

To us, 8 and 8.0 are the same, but to C/C++ they aren't the same.
8 is an integer literal while 8.0 is a floating-point literal.

Sample Code Part 2 – Math  with Literals.

// Math.
rtOut->Text = "Math Using Literals With Integer & Floating-point Data Types.\n\n";

rtOut->Text += "iVal equals 8.\n";
rtOut->Text += "Divide iVal by 3 or iVal / 3  results in: " + iVal / 3 + "\n";
rtOut->Text += "The literal 3 is an integer.\n";
rtOut->Text += "An integer divided by an integer stays an integer.\n";
rtOut->Text += "Any decimals are truncated.\n\n";

rtOut->Text += "iVal / 3.0 results in: " + iVal / 3.0 + "\n";
rtOut->Text += "The decimals were NOT truncated.\n";
rtOut->Text += "Using iVal / 3.0 results in a floating-point number since the literal 3.0 is a floating-point number.\n";
rtOut->Text += "Specifically, C++ treats 3.0 as a double-precision floating-point number.\n";
rtOut->Text += "\n";

rtOut->Text += "Literal Suffixes: L, F, L\n\n";

rtOut->Text += "C/C++ use suffixes after a literal to specify its type and \n";
rtOut->Text += "overrides the built-in assumption about the type of a literal.\n\n";

rtOut->Text += "iVal / 3L results in: " + iVal / 3L + ".\n";
rtOut->Text += "The L in this instance means long integer.\n\n";

rtOut->Text += "Does the literal suffix have to follow the number?\n";
rtOut->Text += "Yes. It doesn't like whitespace here.\n";
rtOut->Text += "Using \"iVal / 3.0 L\" results in a compile error:\n";
rtOut->Text += "  error C2065: 'L' : undeclared identifier \n\n";

rtOut->Text += "Does the literal suffix have to be in uppercase? No.\n";
rtOut->Text += "iVal / 3l results in: " + iVal / 3l + "\n\n";

rtOut->Text += "Oddly C/C++ doesn't follow the usual rules of ignoring whitespace and case sensitivity.\n";
rtOut->Text += "The lowercase 'l' can easily be confused with a 1 therefore it is better to use the uppercase L.\n\n";

rtOut->Text += "iVal / 3.0L results in: " + iVal / 3.0L + ".\n";
rtOut->Text += "The L in this instance means long double.\n";
rtOut->Text += "To create confusion, 3L is a long integer while 3.0L is a long double.\n\n";

rtOut->Text += "That leads to the third suffix: f or F for single-precision floating point.\n\n";
rtOut->Text += "iVal / 3.0F results in: " + iVal / 3.0F + ". \n";
rtOut->Text += "iVal / 3.0f results in: " + iVal / 3.0F + ". \n";
rtOut->Text += "iVal / 3F results in compile errors: \n";
rtOut->Text += "  error C2059: syntax error : 'bad suffix on number'\n";
rtOut->Text += "  error C2065: 'F' : undeclared identifier\n";
rtOut->Text += "  error C2146: syntax error : missing ';' before identifier 'F'\n";
rtOut->Text += "3 is an integer, 3.0 is a floating-point number.\n\n";

Output.

Math Using Literals With Integer & Floating-point Data Types.

iVal equals 8.
Divide iVal by 3 or iVal / 3  results in: 2
The literal 3 is an integer.
An integer divided by an integer stays an integer.
Any decimals are truncated.

iVal / 3.0 results in: 2.66666666666667
The decimals were NOT truncated.
Using iVal / 3.0 results in a floating-point number since the literal 3.0 is a floating-point number.
Specifically, C++ treats 3.0 as a double-precision floating-point number.

Literal Suffixes: L, F, L

C/C++ use suffixes after a literal to specify its type and
overrides the built-in assumption about the type of a literal.

iVal / 3L results in: 2.
The L in this instance means long integer.

Does the literal suffix have to follow the number?
Yes. It doesn't like whitespace here.
Using "iVal / 3.0 L" results in a compile error:
error C2065: 'L' : undeclared identifier

Does the literal suffix have to be in uppercase? No.
iVal / 3l results in: 2

Oddly C/C++ doesn't follow the usual rules of ignoring whitespace and case sensitivity.
The lowercase 'l' can easily be confused with a 1 therefore it is better to use the uppercase L.

iVal / 3.0L results in: 2.66666666666667.
The L in this instance means long double.
To create confusion, 3L is a long integer while 3.0L is a long double.

That leads to the third suffix: f or F for single-precision floating point.

iVal / 3.0F results in: 2.666667.
iVal / 3.0f results in: 2.666667.
iVal / 3F results in compile errors:
error C2059: syntax error : 'bad suffix on number'
error C2065: 'F' : undeclared identifier
error C2146: syntax error : missing ';' before identifier 'F'
3 is an integer, 3.0 is a floating-point number.