Wednesday 29 February 2012

The ceil Function in C & C++


The <math.h> library in C has several functions to manipulate floats to get integer portions. The ceil function is one:

double ceil(double)
float ceilf(float)
long double ceill(long double)

The ceil function returns the integer nearest to the argument but not less than it. It’s an odd function. The function rounds up except where your argument is an integer in which case it returns the same value. What’s odder is the fact it calculates an integer yet returns a float. Why not return an integer? Not sure, but I suspect there’s some reason. The short answer is I don’t find this function, on its own, very useful.

Here is a snippet from the C standard (C11, N1570).



Sample Code.

I created this sample code in Visual C++ 2010 as a console application.

// The standard library includes the system function.
#include <cstdlib>

// C++ standard I/O library
#include <cstdio>

// The math library.
#include <cmath>

int main()
{

// Header.
printf("Using the ceil function in <cmath> library.\n\n");
printf("The ceil function takes a float value and returns\n");
printf("the nearest integer not less than the argument passed.\n\n");

printf("Positive Numbers\n\n");

printf("Attempt #1\n");
printf("ceil(88.0) returns: %6.2f\n", ceil(88.0));
printf("88.0 is nearest and not less than 88.0.\n\n");

printf("Attempt #2\n");
printf("ceil(88.2) returns: %6.2f\n", ceil(88.2));
printf("88.0 is nearest to 88.2, but is less than it so it returns 89.0.\n\n");

printf("Attempt #3\n");
printf("ceil(88.5) returns: %6.2f\n", ceil(88.5));
printf("88.5 is equidistant between 88.0 & 89.0, but 88.0 is less than 88.5.\n\n");

printf("Attempt #4\n");
printf("ceil(88.8) returns: %6.2f\n", ceil(88.8));
printf("89.0 is nearest to 88.8.\n\n");

printf("Negative Numbers\n\n");

printf("Attempt #1\n");
printf("ceil(-88.0) returns: %6.2f\n", ceil(-88.0));
printf("-88.0 is nearest and not less than -88.0.\n\n");

printf("Attempt #2\n");
printf("ceil(-88.4) returns: %6.2f\n", ceil(-88.4));
printf("-88.0 is nearest and not less than -88.4.\n\n");

printf("Attempt #3\n");
printf("ceil(-88.8) returns: %6.2f\n", ceil(-88.8));
printf("-89.0 is less than -88.8 so it returns -88.0\n\n");

// keep console window open
system("pause");

// return some value
return 0;

} // end main

Here is the console window:


Tuesday 28 February 2012

Single v Double Floating-point Numbers With Trig Functions in C & C++


The <math.h> library in C has several trig functions depending on the argument passed to the function. For the sine value of an angle, they are:

double sin(double)
float sinf(float)
long double sinl(long double)

 In C++, the <cmath> library recognizes these C functions, but uses the sin function for all data types. The function is overloaded.

Does it make a difference what type of floating number to use? What happens with the functions when different types are passed?

Microsoft implements the floating-point data types as:

float          4 bytes            3.4E +/- 38 (7 digits)
double         8 bytes            1.7E +/- 308 (15 digits)
long double    same as double

Visual C++ doesn’t support the long double.

Attempt #1 – Float v Double

I have an angle in radians: 1.1234567890123456789. Assigning this value to a float or double definitely makes a difference and it should.

float  fAngle = 1.1234567890123456789;
double dAngle = 1.1234567890123456789;

fAngle becomes 1.1234568, 7 digits of precision.
dAngle becomes 1.1234567890123457, 16 digits of precision.
 
Attempt #2 – Sine of Float v Double

float  fAngle = 1.1234567890123456789;
double dAngle = 1.1234567890123456789;

float fSine = 0;
double dSine = 0;

fSine = sin(fAngle);
dSine = sin(dAngle);

fSine becomes 0.90160114.
dSine becomes 0.90160112364986666.
The difference is 0.000000016350134024 or 1/100,000,000 or 1/1E08.

Attempt #3 – sin v sinf Functions

In C, the sin function is used for double numbers and sinf for float.

This code

fSine = sinf(fAngle);

and this code

fSine = sinf(dAngle);

result in the same return value of 0.90160114.

In the second instance, the code converts the double value to a float and returns a float.



Sunday 26 February 2012

The tangent & arctangent Functions in C & C++


The <cmath> library in C++ (<math.h> in C) has functions to calculate tangent and arctangent values. The tan function takes an angle measured in radians and returns the tangent value. The atan function takes a tangent value and returns an angle in radians. Both functions use floating-point precision numbers.

Click here for a quick refresher on degrees to radians.

But what is tangent?

The tangent of an angle is defined as the ratio of the opposite side of a right-angle triangle over the adjacent side.


The graph shows the tangent values from -180 to 180 degrees (-pi/2 to pi/2 radians). The range is all real numbers.


 

Tan and Atan Functions in C/C++.

The sample code below defines several one-dimensional arrays to hold:

fDegAngle[5]             angle in degrees (given value).
fRadAngle[5]             angle in radians (calculated from degrees).
fTangent[5]                the tangent value from the C/C++ functions.
fArcTangent[5]           the arctangent value from the C/C++ function.
fRevDegAngle[5]        the angle in degree determined from the arctangent value.

The starting point is to define 5 angles in degrees: 0, 90, 180, 270, 360.


Sample Code.


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.

// Math functions library.
#include <cmath>

// Create constant for PI.
#define PI 3.14159265

...

// tan & atan functions

rtOut->Text = "The tan and atan functions.\n\n";
rtOut->Text += "The range of tangent values is: all real numbers.\n";
rtOut->Text += "The range of arcsine values is: -PI/2 to PI/2 radians or -90 to 90 degrees.\n";
rtOut->Text += "\n";

int i = 0;
double fTangent[5];
double fArctangent[5];
double fRadAngle[5];
double fDegAngle[5];
double fRevDegAngle[5];

// 360 degrees = 2 x PI x radians
// 180 degrees = PI x radians
// 1 degree =  PI / 180 radians
// 90 degree = 90 x PI / 180 radians = 1.570796
// 1 radian = 180 / PI degree

// Calculations
// Loop through for degrees: 0, 90, 180, 270, 360.
for (i; i < 5; i++)
{

  // Set degrees.
  fDegAngle[i] = 90 * i;

  // Need radians.
  fRadAngle[i] = fDegAngle[i] * PI / 180.0;

  // tan(0.785398 rads) = 1
  // pi/4 or 45 degrees
  fTangent[i] = tan(fRadAngle[i]);

  // Returns angle in radians.
  fArctangent[i] = atan(fTangent[i]);

  // Find degree of angle based on arctangent.
  fRevDegAngle[i] = fArctangent[i] * 180 / PI;

} // for

// Display values.
for (i = 0; i < 5; i++)
{
  rtOut->Text += fDegAngle[i] + " degrees is " + fRadAngle[i] + " radians.\n";
  rtOut->Text += "The tangent of " + fRadAngle[i] + " radians is " + fTangent[i] + ".\n";
  rtOut->Text += "The arctangent of " + fTangent[i] + " is " + fArctangent[i] + " radians.\n";
  rtOut->Text += "The arctangent of " + fTangent[i] + " is " + fRevDegAngle[i] + " degrees.\n";
  rtOut->Text += "\n";

} // for

Output.

The tan and atan functions.

The range of tangent values is: all real numbers.
The range of arcsine values is: -PI/2 to PI/2 radians or -90 to 90 degrees.

0 degrees is 0 radians.
The tangent of 0 radians is 0.
The arctangent of 0 is 0 radians.
The arctangent of 0 is 0 degrees.

90 degrees is 1.570796325 radians.
The tangent of 1.570796325 radians is 557135115.020977.
The arctangent of 557135115.020977 is 1.570796325 radians.
The arctangent of 557135115.020977 is 90 degrees.

180 degrees is 3.14159265 radians.
The tangent of 3.14159265 radians is -3.58979347393082E-09.
The arctangent of -3.58979347393082E-09 is -3.58979347393082E-09 radians.
The arctangent of -3.58979347393082E-09 is -2.05680015614866E-07 degrees.

270 degrees is 4.712388975 radians.
The tangent of 4.712388975 radians is 185711735.639238.
The arctangent of 185711735.639238 is 1.57079632141021 radians.
The arctangent of 185711735.639238 is 89.99999979432 degrees.

360 degrees is 6.2831853 radians.
The tangent of 6.2831853 radians is -7.17958694786164E-09.
The arctangent of -7.17958694786164E-09 is -7.17958694786164E-09 radians.
The arctangent of -7.17958694786164E-09 is -4.11360031229732E-07 degrees.
 

C/C++ Standards.

The ISO C Standard specifies separate functions depending on the argument data type (double, float, long double): tan, tanf, tanl, atan, atanf and atanl. The images below show the C standard documentation.

In C++ both the tan and atan functions are overloaded. They accept float, double or long double and return the same data type.




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.





Saturday 25 February 2012

The cosine & arccosine Functions in C & C++

The <cmath> library in C++ (<math.h> in C) has functions to calculate cosine and arccosine values. The cos function takes an angle measured in radians and returns the cosine value. The acos function takes a cosine value and returns an angle in radians. Both functions use floating-point precision numbers.

Click here for a quick refresher on degrees to radians.

But what is cosine?

The cosine of an angle is defined as the ratio of the adjacent side of a right-angle triangle over the hypotenuse.




The graph shows the cosine values from 0 to 360 degrees (0 to 2 pi radians). The range is -1 to 1.

 

Cos and Acos Functions in C/C++.

The sample code below defines several one-dimensional arrays to hold:

fDegAngle[5]            angle in degrees (given value).
fRadAngle[5]            angle in radians (calculated from degrees).
fCosine [5]                the sine value from the C/C++ functions.
fArccosine [5]           the arccosine value from the C/C++ function.
fRevDegAngle[5]      the angle in degree determined from the arccosine value.

The starting point is to define 5 angles in degrees: 0, 90, 180, 270, 360.


Sample Code.

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.

// Math functions library.
#include <cmath>

// Create constant for PI.
#define PI 3.14159265

...

// cosine function

rtOut->Text = "The cosine and arccosine functions.\n\n";
rtOut->Text += "The range of cosine values is: 1 to -1.\n";
rtOut->Text += "The range of arccosine values is: 0 to PI radians or 0 to 180 degrees.\n";
rtOut->Text += "\n";

int i = 0;
double fCosine[5];
double fArccosine[5];
double fRadAngle[5];
double fDegAngle[5];
double fRevDegAngle[5];

// 360 degrees = 2 x PI x radians
// 180 degrees = PI x radians
// 1 degree =  PI / 180 radians
// 90 degree = 90 x PI / 180 radians = 1.570796
// 1 radian = 180 / PI degree

// Calculations
// Loop through for degrees: 0, 90, 180, 270, 360.
for (i; i < 5; i++)
{

  // Set degrees.
  fDegAngle[i] = 90 * i;

  // Need radians.
  fRadAngle[i] = fDegAngle[i] * PI / 180.0;

  // cosin(1.570796 rads) = 0
  fCosine[i] = cos(fRadAngle[i]);

  // Returns angle in radians.
  fArccosine[i] = acos(fCosine[i]);

  // Find degree of angle based on arccosine.
  fRevDegAngle[i] = fArccosine[i] * 180 / PI;

} // for

// Display values.
for (i = 0; i < 5; i++)
{
  rtOut->Text += fDegAngle[i] + " degrees is " + fRadAngle[i] + " radians.\n";
  rtOut->Text += "The cosine of " + fRadAngle[i] + " radians is " + fCosine[i] + ".\n";
  rtOut->Text += "The arccosine of " + fCosine[i] + " is " + fArccosine[i] + " radians.\n";
  rtOut->Text += "The arccosine of " + fCosine[i] + " is " + fRevDegAngle[i] + " degrees.\n";
  rtOut->Text += "\n";

} // for

rtOut->Text += "The small floating point numbers (e.g., 1.79489673696541E-09) are effectively zero.\n";
rtOut->Text += "\n";


Output.

The cosine and arccosine functions.

The range of cosine values is: 1 to -1.
The range of arccosine values is: 0 to PI radians or 0 to 180 degrees.

0 degrees is 0 radians.
The cosine of 0 radians is 1.
The arccosine of 1 is 0 radians.
The arccosine of 1 is 0 degrees.

90 degrees is 1.570796325 radians.
The cosine of 1.570796325 radians is 1.79489673696541E-09.
The arccosine of 1.79489673696541E-09 is 1.570796325 radians.
The arccosine of 1.79489673696541E-09 is 90 degrees.

180 degrees is 3.14159265 radians.
The cosine of 3.14159265 radians is -1.
The arccosine of -1 is 3.14159265358979 radians.
The arccosine of -1 is 180.00000020568 degrees.

270 degrees is 4.712388975 radians.
The cosine of 4.712388975 radians is -5.38468932271781E-09.
The arccosine of -5.38468932271781E-09 is 1.57079633217959 radians.
The arccosine of -5.38468932271781E-09 is 90.00000041136 degrees.

360 degrees is 6.2831853 radians.
The cosine of 6.2831853 radians is 1.
The arccosine of 1 is 0 radians.
The arccosine of 1 is 0 degrees.

The small floating point numbers (e.g., 1.79489673696541E-09) are effectively zero.

C/C++ Standards.

The ISO C Standard specifies separate functions depending on the argument data type (double, float, long double): cos, cosf, cosl, acos, acosf and acosl. The images below show the C standard documentation.

In C++ both the cos and acos functions are overloaded. They accept float, double or long double and return the same data type.