# Advanced Introduction to C++, Scientific Computing and Machine Learning

Claudius Gros, WS 2019/20

Institut für theoretische Physik
Goethe-University Frankfurt a.M.

# primitive data types

• int, double, char, ... are primitive (predefined) data types
arbitrary complex data types may be defined by the user
• String  is (however) an object, like everything else
• one byte is 8 bits (a boolean would correspond to a bit)
all data must be however addressable
Typ Size Domain Example
bool 1 {true, false} bool b = true;
char 1 [0x0000, 0xFFFF] char c = 'a';
byte 1 [−27, 27−1] = [−128, 127] byte b = 4;
short int 2 [−215, 215−1] = [−32,768, 32767] short int s = 12345;
int 4 [−231, 231−1] =
[−2,147,483,648, 2,147,483,647]
int i = 17;
long int8 [−263, 263−1] long int l =8L;
float 4 [1.40239846 ⋅ 10–45, 3.40282347 ⋅ 1038] float f = 3.14F ;
double 8 [4.94065645841246544 ⋅ 10–324,
1.79769131486231570 ⋅ 10308]
double d = 3.14

• short / long for specialized applications only
• float not used anymore, standard is
double for floating point operations
• 32/64 bits (int/double) used for memory addressing by 32/64 bit processors,
$\rightarrow$ memory restrictions

# example: primitive data types

• sizeof() may depend on CPU used; may be used for any object
returns the number of bytes used (one byte is 8 bits)
• C++ is nice to complex numbers,
typedef defines a new data type
• M_PI $= \pi$
#include <iostream>
#include <stdio.h>
#include <complex>  // complex numbers
using namespace std;

int main()
{
int intArray[5] = { 16, 2, 77, 40, 12071 };
double doubleArray[10];
//
printf("size of        bool   : %4d\n",(int)sizeof(bool));
//
printf("size of        char   : %4d\n",(int)sizeof(char));
printf("\n");
printf("size of        int    : %4d\n",(int)sizeof(int));
printf("size of  short int    : %4d\n",(int)sizeof(short int));
printf("size of   long int    : %4d\n",(int)sizeof(long int));
printf("\n");
printf("size of        float  : %4d\n",(int)sizeof(float));
printf("size of        double : %4d\n",(int)sizeof(double));
printf("size of   long double : %4d\n",(int)sizeof(long double));  // what is that?
printf("\n");
printf("size of      intArray : %4d\n",(int)sizeof(intArray));
printf("size of   doubleArray : %4d\n",(int)sizeof(doubleArray));
//
typedef complex<double> doubleComplex;
printf("\n");
printf("size of doubleComplex : %4d\n",(int)sizeof(doubleComplex));
printf("\n");
//
//
printf("=== =============================== ===\n");
printf("=== having fun with complex numbers ===\n");
printf("=== =============================== ===\n");
doubleComplex a(1.11,2.22),b(0,1);
printf("\n");
printf("a         = %f + %f i\n",a.real(),a.imag());
printf("\n");
//
cout << "a         = " << a       << "\n";
cout << "b         = " << b       << "\n";

cout << "a + b     = " << a + b   << "\n";
cout << "a * b     = " << a * b   << "\n";
cout << "a / b     = " << a / b   << "\n";
cout << "|a|       = " << abs(a)  << "\n";

cout << "a*        = " << conj(a) << "\n";
cout << "norm(b)   = " << norm(b) << "\n";
cout << "exp(b*pi) = " << exp(b*M_PI)  << "\n";  // check precision !
printf("\n");
printf("pi        = %50.48f\n",M_PI);

return 0;
}


# type conversion vs casting

• here: conversion of primitive data types and strings
• later: casting of objects
• sprintf() : writing formatted data to string
• typeid()  can be used also for classes
• to_string()  converts primitive data types to strings
complier bug: for our actual g++ compiler (GCC 4.8.0) to_string() does not work;
#include <iostream>
#include <stdio.h>
#include <typeinfo>    // typeinfo
using namespace std;

int main()
{
//                 implicit type conversion
short a=2000;
int b;
b=a;
printf("a = %5d,  b = %5d\n",a,b);
printf("\n");
//                 explicit type conversion
double x = 10.3;
int y,z;
y = int(x);    // functional notation
z = (int)x;    // c-like cast notation
printf("x = %6.3f,  y = %3d,  z = %3d\n",x,y,z);
printf("\n");
//                 type checking
if (typeid(a) != typeid(b))
{
cout << "a and b are of different types:\n";
cout << "a is: " << typeid(a).name() << '\n';
cout << "b is: " << typeid(b).name() << '\n';
}
//                 converting to strings
printf("\n");
int number = 123;     // number to convert
char strResult[16];   // string (array of char), for the Result
sprintf(strResult, "%d",number);      // write integer to string
printf("number = %d,  strResult = %s\n",number,strResult);
//                 converting from strings
char text[] = "456";  // string to be converted
int intResult;        // number which will contain the result
sscanf (text,"%d",&intResult);        // pointer: &intResult
printf("  text = %s,  intResult = %d\n",text,intResult);
//                 ASCII character table
printf("\n");
printf("=== ===================== ===\n");
printf("=== ASCII character table ===\n");
printf("=== ===================== ===\n");
printf("\n");
for ( int x = 0; x < 128; x++ )
cout << x << ". "<< (char)x << "\n";
printf("\n");
//
return 0;
}


# arithmetic operators

• assignment and arithmetics
SymbolDescriptionExamples
=assignment int i=5;
+  -addition, subtraction int i=5+3; int i=5-3;
*  /multiplication, integer division int i=5*3; int i=9/3;
%modulo int i=14%3;
+  -unary plus/minus int i=+3; int i=-2;
+=  -=  *=   /=assignment and operation i += 5; // i = i + 5
++   --pre-/postfix increment/decrement i++; // i = i + 1

• naming of C++

# mathematical functions

#include <iostream>
#include <math.h>
using namespace std;

int main()
{
double number,dsqrt,dpow,dlog,dlog10,expLog;

cout << "Please enter a number \n";
cin >> number;

dsqrt  = sqrt(number);
dpow   = pow(number,3);
dlog   = log(number);
dlog10 = log10(number);
expLog = log(exp(number));

cout << "\n";
cout << "square root of  " << number << "   is : "
<< dsqrt << "\n";
cout << "        log of  " << number << "   is : "
<< dlog << "\n";
cout << "      log10 of  " << number << "   is : "
<< dlog10 << "\n";
cout << "                " << number << "^3 is : "
<< dpow << "\n";
cout << " exp of log of  " << number << "   is : "
<< expLog << "\n";

return 0;
}


# arrays

• array length is fixed for all C++ versions below C++14
• 10-component integer array
int intArray[10];

• setting/assessing value of array-component k
intArray[k] = 4;             // setting
int b = intArray[k];         // assessing

• array with predefined values
int intArray[3] = {1, 2, 3};
double doubleArray[] = {1.0, 2.0, 3.0};  // [] may be left empty when initializing

• length n of array
note however myString.length() for strings
int n = sizeof(doubleArray) / sizeof(doubleArray[0]);

• multi-dimensional arrays: nxm matrix
int intMatrix[n][m];


# example: arrays

• arrays start always with [0]
• use const int for defining the array length
• C++ doesn't have any built-in reflective support;
e.g. for finding the name of a variable
• C++ does not (!) check array boundaries! Alwasy use
assert() for doing it by hand, turning off
assert() by compling with
g++ -DNDEBUG for production runs
• a good C++ program is full of asserts
/* compile with  g++             -o test.e test.c  */
/*      or with  g++    -DNDEBUG -o test.e test.c  */
/*                      (turns assert()' off)     */
//
#include <iostream>         // input/output handling
#include <stdio.h>          // for formatted input/output
#include <assert.h>         // (assert()' calls abort if arg not true)
#define VARIABLE_NAME(x) #x     // a C++ macro definition
using namespace std;

int main()
{
const int arrayLength = 10;   // array length need to be constant
int goodHabit[arrayLength];   // much better programming
//
cout << "goodHabit has " << sizeof(goodHabit) / sizeof(goodHabit[0])
<< " elements\n\n";
//
goodHabit[0] = 0;                 // first element
for (int i=1;i<arrayLength;i++)   // starting at second element
goodHabit[i] = goodHabit[i-1]+1;
for (int i=0;i<arrayLength;i++)
cout << VARIABLE_NAME(goodHabit)
<< "[" << i << "] = "
<< goodHabit[i] << "\n";
printf("=== ==================== ===\n");
printf("=== array bound checking ===\n");
printf("=== ==================== ===\n");
string stringArray[] = {"apple","banana","oranges"};
for (int i=0;i<6;i++)
{
assert(i>=0);     // array size checking by hand
assert(i<sizeof(stringArray)/sizeof(string));
printf("stringArray[%d] = %s\n",i,stringArray[i].c_str());
}
return 0;
}


# example: matrices

• "Schiffe Versenken": Darstellung"
#include <iostream>  // input/output handling
#include <stdio.h>   // for formatted input/output
using namespace std;

const int X=9;
const int Y=7;

int main()
{
char Spielfeld[Y][X];
int x, y;
char cx, cy;
for (x=0; x<X; x++)
for (y=0; y<Y; y++)
Spielfeld[y][x] = '.';
//
// Anzeige und Eingabe
//
bool SchleifenEnde=false;
int xin, yin;
do {
printf("  ");
for (x=0; x<X; x++)
printf("%3d",x+1);
printf("\n");
//
for (y=0; y<Y; y++)
{
cout << (char)('A'+y) << " ";
for (x=0; x<X; x++)
printf("%3c",Spielfeld[y][x]);
cout << endl;
}
//
cin >> cy >> cx;
xin = cx - '1';
yin = cy - 'A';
if (xin>=0 && xin<X && yin>=0 && yin<Y)
{
Spielfeld[yin][xin] = 'x';
cout << "# (yin,xin): (" << yin
<< "," << xin
<< ")\n\n";
}
else
SchleifenEnde = true;
} while (!SchleifenEnde);
}


# C++ pointers

• pointers point to the (start of the) memory address of an object
• &variable : assessing the pointer of the variable (reference)
• int* intPointer : creates a pointer intPointer to an integer
*intPointer : assesses the value of the memory location
the type (size) of adressed memory cell
• int** intPointPointer : a pointer pointing to an integer-pointer
:: a two-dimensional int-array
• int intArray[] :
intArray is a pointer, pointing to the first element intArray[0]
• main(int argLength, char* argValues[])
argValues[] is an array of pointers
• using pointer explicitly invites bugs to the party;
modern languages like JAVA do not allow it

#include <iostream>

using namespace std;

int main ()
{
int var1   = 20;
int var2[] = {1,2,3};

cout << endl;
cout << "address of var1: " << &var1 << endl;
cout << "address of var2: " <<  var2 << endl;
cout << "address of var2: " << &var2 << endl;

int* ip;         // pointer variable
ip = &var1;      // store address of var1 in pointer variable ip

cout << endl;
cout << "value of var1: " << var1 << endl;
cout << "value of   ip: " <<   ip << endl;
cout << "value of  *ip: " <<  *ip << endl;

ip = var2;       // not &var2 (!), since arrays are already pointers
for (int i=0; i<3; i++)
{
cout << endl;
cout << "address of var2[" << i << "] = "
<< ip << " "
<< &(*ip) << " "
<< &var2[i] << endl;

cout << "  value of var2[" << i << "] = "
<< *ip << " "
<< *(&(*ip)) << " "
<< *(&var2[i]) << endl;

ip++;          // point to the next location (errors likely)
}

return 0;
}


# dynamic memory

• int array_0[5]  : when size of array is known a compiling time
• int array_1[var1]  : not standard, but possibly a
compiler extension:  g++  is o.k. with it (standard from  C++14  and on)
puts the object onto the stack (the stack of locally declared variables)
• int *array_2 = new int[var2]  : when size of array,
viz the value of  var2, is not known a compiling time;
program aborts badly when allocation fails (out of memory);
puts the object onto the heap (dynamically allocated memory)
• int *array_3 = new(nothrow) int[var3]  : idem, but continuing
with a null pointer when allocation fails
• more options for new(..) available for programming experiments
• delete  everything on the heap when not needed anymore
for an explicit garbarge collection (avoiding such a memory leak)
• modern programming languares like JAVA collect their garbage automatically
#include <iostream>      // standard IO
#include <cstdlib>       // for atof

using namespace std;

int main(int argLength, char* argValues[])   // parsing command line arguments
{
if (argLength==1)
{
cout << "please run with an long integer argument\n";
return 0;
}
long int dynamicArraySize = atof(argValues[1]);  // casting string to long
long int gigaByte = 1073741824;
//
cout << endl;
cout << "trying to construct integer arrays of size : "
<< dynamicArraySize << endl;
cout << "using  "
<< dynamicArraySize*sizeof(int)*1.0/gigaByte
<< "  Gigabytes of memory " << endl << endl;
//
int array_1[dynamicArraySize];            // not all compilers like that
cout << "sizeof(array_1)  : "
<<  sizeof(array_1) << endl;
//
int *array_2 = new int[dynamicArraySize]; // arrays are pointers
cout << "sizeof(array_2)  : "
<<  sizeof(array_2) << endl;

int *array_3 = new(nothrow) int[dynamicArraySize];
//
if (array_3 == 0)                         // controlled exit for null pointer
{
cout << "I am out of memory" << endl;
return 0;                                // program failed
}
cout << "sizeof(*array_3) : "
<<  sizeof(*array_3) << endl;
//
cout << "sizeof(int)      : "
<<  sizeof(int) << endl;
//
delete[] array_2;      // deletes the whole array
delete array_3;        // deletes only the first element
//
return 1;
}


# memory usage

• control the usage of your memory with the
Linux shell command top
• size_t, an unsigned integer type which can store
the maximum size of a theoretically possible object of any type
• all CPUs today are 64 bit processors (32 bit CPS had the 4GB memory limit)
#include <iostream>      // standard IO
#include <stdio.h>       // for printf
#include <cstdlib>       // for atof
#include <math.h>        // for the math
#include <time.h>        // ('clock()' measures time in nanoseconds)

using namespace std;

const long int oneGigaByte = 1073741824;   // one Giga Byte

/* **************************************** */
/* *****      time in seconds       ******* */
/* **************************************** */

double timeInSeconds()
{
const double oneSecond = 1.0 / CLOCKS_PER_SEC;
static long int lastTime = clock();
long int actual_time = clock();
long int elapsed_time = actual_time - lastTime;
lastTime = actual_time;
return elapsed_time * oneSecond;     // time passed since last call
}

/* **************************************** */
/* *****            main            ******* */
/* **************************************** */

int main(int argLength, char* argValues[])  // parsing command line arguments
{
if (argLength==1)
{
cout << "please run with a double argument (memory in GB)\n";
return 0;
}
long int dynamicArraySize = (long)(atof(argValues[1])*oneGigaByte*1.0/sizeof(int));
timeInSeconds();                           // initialized

int onePerCent = (int)(dynamicArraySize/100);
//
int *aa = new int[dynamicArraySize];
/*
for (int i=0;i<dynamicArraySize;i++)
for (long int i=0;i<dynamicArraySize;i++)
*/
for (size_t i=0;i<dynamicArraySize;i++)
{
aa[i] = i;
if ((i%onePerCent)==0)
printf("(main) %5.2f GB indices allocated, %5.2f seconds used\n",
i*1.0/oneGigaByte, timeInSeconds());
}
//
printf("\n");
printf("(main) starting infinite loop\n\n");
//
while (true)                   // infinite loop
double a = log(34545.3454);
//
return 1;
}


# aliasing

• int* aPointer an int pointer: *aPointer for value
int& alias an alias (differnt name)
#include <iostream>       // standard IO
using namespace std;

int main()
{
double  a = 10.0;
double& b = a;          // an alias

cout << "a  = " << a << endl;
cout << "b  = " << b << endl << endl;

double *pA = &a;
double *pB = &b;

b = 6.0;

cout << "*pA = " << *pA << endl;
cout << "*pB = " << *pA << endl;

return 1;
}