QuantStack
QuantStack
Avatar picture

Sylvain Corlay

  • Scientific software developer, Quant researcher, formerly quant at Bloomberg, and adjunct at Columbia and NYU
  • Founded QuantStack in 2016
  • Jupyter core developer (widgets, bqplot, pythreejs)
Avatar picture

Johan Mabille

  • Scientific software developer, Quant developer, formerly quant developer at HSBC
  • Joined QuantStack in 2016
  • Co-author of xtensor, xsimd, xeus

Summary

  • The basics
  • Functional programming
  • Using the STL
  • Object-oriented programming
  • Memory and low-level data structures
  • Inheritance and polymorphism
  • Generic programming

The basics

Required tools - Windows

  • Git bash (download at https://gitforwindows.org/)
  • CMake (download at https://cmake.org/download/)
  • Visual Studio 2015 Community edition, with C++ component
  • DO NOT INSTALL Visual Studio 2017

Required tools - Linux

  • Git
  • gcc
  • cmake
  • an editor (vim, atom emacs, gedit)

Required tools - OSX

  • Git
  • clang or XCode
  • cmake
  • optional: an editor if you don't want to use xcode

Version Control System

  • Document_v1
  • Document_v2
  • ...
  • Document_vfinal
  • Document_vreallyfinal
  • Document_vreallyfinaliwontmodifyitiswear

Version Control System

  • Will be a requirement for any technical job
  • Is independent from the programming language
  • Git is the most prevalent VCS
  • Github
    • Online collaboration platform
    • Millions of users
    • A social network for developers

Git

Decentralized Version Control System

  • Create a github account
  • Fork https://gitub.com/QuantStack/cpp_dauphine

    git clone <your_repo>
    cd cpp_dauphine;
    git log
                        

Git

git basic
git branch

Git

Create a "document_name.txt" into basics/git_tutorial/

(where name is replace with your last name)

that contains your first name and last name, and your github pseudo


    git checkout -b my_branch
    git add document_XX.txt
    git commit -m "commit message"
                        

Git

git merge

Git

Do not execute the following lines, that's for illustration

Instead, go to https://github.com/QuantStack/cpp_dauphine and open a Pull Request


    git checkout master
    git merge my_branch
                        

Git

Decentralized Version Control System

git decentralized

Git


    git remote -v
    git push origin my_branch
    git remote add upstream http://github.com/QuantStack/cpp_dauphine.git
                        

Git


    git checkout master
    git pull upstream master
    git push origin master
    git branch -d my_branch
    git push origin :my_branch
                        

Git

git rebase1
git rebase2

Git


    git checkout master
    git pull upstream master
    git checkout dev
    git rebase master
                        

A First program


#include <iostream>
#include <cmath>

int main(int argc, char* argv[])
{
    double x1 = 1., y1 = 0.;
    double x2 = 0., y2 = 1.;

    double distance = std::sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    std::cout << "distance = " << distance << std::endl;
    return 0;
}
                        

#include <iostream>      // #include imports functions not built in the language but defined in header files
#include <cmath>         // More generally, # starts a preprocessor directive
                            

int main(int argc, char* argv[]) // Each executable program must have a function called main.
{                                // The body of a function is delimited with curly braces (scope)
                            

    double x0 = 1., y0 = 0.;   // Declaration and initialization of variables x0, y0, x1 and y1.
    double x1 = 0., y1 = 1.;   // C++ is a statically typed language
                            

    // std:: is a namespace qualifier
    double distance = std::sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
    // Writing is done with the output operator <<
    std::cout << "distance = " << distance << std::endl;
                            

    return 0;                  // Return value of the main function (declared to return an int)
}                              // Closes the body (scope) of the function
                            

Building the program

Three steps:

  • Preprocessing
  • Compilation
  • Link

Compilation

compilation

Link

compilation

Compilers / IDE

  • gcc (linux / OSX)
  • Visual Studio (Windows)
  • X Code (OSX)
  • mingw (Windows)

    g++ -o first_program main.cpp
                        

CMake


    mkdir build
    cd build
    cmake ..
    make
                        

    mkdir build
    cd build
    cmake -G "NMake Makefiles" ..
    nmake
                        

Variables

C++ is a statically typed language

  • Variable must be declared with a type
  • This type is final and cannot be changed after the declaration
  • Declaration (and initialization) of variables have the following scheme:
  • 
    type variable_name;
    type variable_name = value;
    type variable_name1 = value1, variable_name2 = value2, ...;
                                
                            

Built-in types

  • character types
  • boolean
  • integers
  • floating-point types
  • C-style arrays

Character types

                            
  • signed char (1 byte = 8 bits)
  • unsigned char (1 byte = 8 bits)
  • char (equivalent to signed or unsigned, but distinct)
  • wchar_t (system dependant, generally 2 or 4 bytes)
  • char16_t (2 bytes = 16 bits)
  • char32_t (4 bytes = 32 bits)

Character types


    const char* c = "character_string";
    char s[17] = "character_string";
                        

Prefer std::string over arrays of characters

Booleans

  • bool (1 byte = 8 bits)
  • 2 possible values, true or false

    bool b1 = true, b2 = false;
    std::cout << std::boolalpha <<"b1: " << b1 << std::endl;
    std::cout << "b2: " << b2 << std::endl;
                        

Integers

                            
  • (unsigned) short (at least 2 bytes = 16 bits)
  • (unsigned) int (at least 4 bytes = 32 bits)
  • (unsigned) long (at least 4 bytes = 32 bits)
  • (unsigned) long long (at least 8 bytes = 64 bits)
  • std::size_t (8 bytes = 64 bits)
  • std::ptrdiff_t (8 bytes = 64 bits)

C++ standard also guarantees


1 == sizeof(char) ≤ sizeof(short) ≤ sizeof(int) ≤ sizeof(long) ≤ sizeof(long long)
                        
types size in bytes lower bound upper bound
short 2 -28 28 - 1
unsigned short 2 0 216
int 4 -216 216 - 1
unsigned int 4 0 232
long long 8 -232 232 - 1
unsigned long long 8 0 264

#include <limits>
#include <iostream>

int main(int argc, char* argv[])
{
    std::cout << "short: " << sizeof(short) << " "
              << std::numeric_limits<short>::min() << " "
              << std::numeric_limits<short>::max() << std::endl;
    std::cout << "int: " << sizeof(int) << " "
              << std::numeric_limits<int>::min() << " "
              << std::numeric_limits<int>::max() << std::endl;
    std::cout << "long: " << sizeof(long) << " "
              << std::numeric_limits<long>::min() << " "
              << std::numeric_limits<long>::max() << std::endl;
    std::cout << "long long: " << sizeof(long long) << " "
              << std::numeric_limits<long long>::min() << " "
              << std::numeric_limits<long long>::max() << std::endl;
}
                        

Integer encoding

  • Unsigned integers: simple conversion to base 2
  • Signed integers: two's complement method
  • 
        int a = 42, b = -42;
        std::cout << std::bitset<32>(a) << std::endl;
        std::cout << std::bitset<32>(b) << std::endl;
                                

Floating-point values

  • float (32 bits)
  • double (64 bits)
  • long double (platform dependent)

IEEE 754 norm

r = (-1)s x m x 2exponent - offset

  • s: bit of sign
  • m: bits of mantissa
  • exponent: bits of exponent
float double
sign 1 1
exponent 8 11
mantissa 23 52
lowest number 1.4 x 10-45 4.9406564854124564 x 10-324
highest number 3.40282346 x 1038 1.7976931348623157 x 10308

C-Style arrays

  • Syntax:
    
    double d[17];
    int i[4];
    d[0] = 1.2;
    d[4] = 2.7;
                                    
  • Statically allocated arrays
  • Cannot be resized
  • Have poor interfaces

Prefer std::arrays over C-style arrays

Arithmetic Operators


    int a = 1, b = 2;

    int c = -a;
    int c2 = +a;

    int d = a + b; int da = a; da += b;
    int e = a - b; int ea = a; ea -= b;
    int f = a * b; int fa = a; fa *= b;
    int g = a / b; int ga = a; ga /= b;
    int h = a % b; int ha = a; ha %= b;
    
                        

Increment/decrement operators


    int a = 2;
    int b = a++;
    int c = ++a;
    int d = a--;
    int e = --a;
                        

Comparison operators


    bool r1 = a == b;
    bool r2 = a != b;
    bool r3 = a < b;
    bool r4 = a ≤ b;
    bool r5 = a > b;
    bool r6 = a ≥ b;
                        

Bitwise operators


    int a = 1, b = 31;
    int c = ~a;
    int d = a & b;  int da = a; da &= b;
    int e = a | b;  int ea = a; ea |= b;
    int f = a ^ b;  int fa = a; fa ^= b;
    int g = a << 1; int ga = a; ga << 1; 
    int h = a >> 1; int ha = a; ha >> 1;
                        

Logical operations


    bool a = true, b = false;
    bool c = !a;
    bool d = a && b;
    bool e = a || b;
                        

if and else


    if(x > 0)
    {
        std::cout << "x is positive" << std::endl;
    }
    else if(x < 0)
    {
        std::cout << "x is negative" << std::endl;
    }
    else
    {
        std:cout << "x is 0" << std::endl;
    }
                        

while


    #include <iostream>

    int main(int argc, char* argv)
    {
        int n = 10;
        while(n ≥ 0)
        {
            std::cout << n << std::endl;
            --n;
        }
        std::cout << "end of loop" << std::endl;
    }
                        

do while


    #include <iostream>

    int main(int argc, char* argv)
    {
        int n = 0;
        do
        {
            std::cout << n << std::endl;
            --n;
        }
        while(n ≥ 0)
        std::cout << "end of loop" << std::endl;
    }
                        

for


    #include <iostream>

    int main(int argc, char* argv)
    {
        for(int i = 0; i< 10; ++i)
        {
            std::cout << i << std::endl;
        }
        std::cout << "end of loop" << std::endl;
    }
                        

break


    #include <iostream>

    int main(int argc, char* argv)
    {
        for(int i = 10; i> 0; --i)
        {
            std::cout << i << std::endl;
            if(i == 3)
            {
                std::cout << "countdown aborted" << std::endl;
                break;
            }
        }
        std::cout << "end of loop" << std::endl;
    }
                        

continue


    #include <iostream>

    int main(int argc, char* argv)
    {
        for(int i = 10; i> 0; --i)
        {
            if(i == 3)
            {
                continue;
            }
            std::cout << i << std::endl;
        }
        std::cout << "end of loop" << std::endl;
    }
                        

switch


    int i = std::rand() % 2;
    switch(i)
    {
    case 0:
        std::cout << "i is even" << std::endl;
        break;
    case 1:
        std::cout << "i is odd" << std::endl;
    default:
        std::cout << "default case" << std::endl;
    }
                        

scope


    int main(int argc, char* argv[])
    {
        int a = 10;
        {
            int b = 4096;
            for(int i = 0; i < a; ++i)
            {
                b /= 2;
                int c = b;
                std::cout << c << std::endl;
            }
            std::cout << c << std::endl; // error: c is not accessible
        }
        std::cout << b << std::endl; // error: b is not accessible
    }
                        

Exercises

Write a program that computes the factorial of a number


    int factorial = 1;
    for(int i = 1; i <= num; ++i)
    {
        factorial *= i;
    }
    std::cout << "The factorial of " << num << " is " << factorial << std::endl;
                            

Write a program to check whether a number is prime or not.


    int nb_div = 0;
    for(int div = 1; i <= num; ++i)
    {
        if(num % div == 0)
        {
            ++nb_div;
        }
    }
    if(nb_div == 2)
    {
        std::cout << "The entered number is a prime number" << std::endl;
    }
    else
    {
        std::cout << "The entered number is not a prime number" << std::endl;
    }
                            

Write a program that computes the sum of the digits of an integer


    int i = num, sum = 0;
    while(i > 0)
    {
        int r = i % 10;
        i /= 10;
        sum += r;
    }
    std::cout << "The sum of digits of " << num << " is " << sum << std::endl;
                            

Write a program that computes the frequency of each digit in a given integer


    for(int i = 0; i < 10; ++i)
    {
        std::cout << "The frequency of " << i << " is ";
        int cnt = 0;
        for(int j = num; j > 0; j /= 10)
        {
            int r = j % 10;
            if(r == i)
            {
                ++cnt;
            }
        }
        std::cout << cnt << std::endl;
    }
                            

Write a program that prints the first n terms of Fibonacci series


    int f1 = 0, f2 = 1;
    std::cout << f1 << " " << f2;
    for(int i = 2; i < n; ++i)
    {
        int f3 = f1 + f2;
        std::cout << " " << f3;
        f1 = f2;
        f2 = f3;
    }
    std::cout << std::endl;