Lecture 14: Structure (2)

Structure example: Floating point number

#include <iostream>
#include <cctype>  // isdigit()
#include <cmath>   // pow()
#include <climits> // INT_MAX

using namespace std;

typedef struct Float_t
{
    int sign;
    int exp;
    long mantissa;
} Float;

void normalize_float(Float &f)
{
    while (f.mantissa > 0 && f.mantissa % 10 == 0)
    {
        f.mantissa /= 10;
        f.exp++;
    }
    while (f.mantissa > INT_MAX)
    {
        f.mantissa /= 10;
        f.exp++;
    }
    if (f.mantissa == 0)
    {
        f.exp = 0;
        f.sign = 1;
    }
}

Float parse_float_number(char input_buffer[])
{
    Float result;
    result.sign = 1;
    result.exp = 0;
    result.mantissa = 0;

    int i = 0;
    if (input_buffer[i] == '-')
    {
        result.sign = -1;
        i++;
    }

    if (input_buffer[i] == '0')
    {
        i++;
    }
    else
    {
        while (isdigit(input_buffer[i]))
        {
            result.mantissa = result.mantissa * 10 + input_buffer[i] - '0';
            i++;
        }
    }

    if (input_buffer[i] == '.')
    {
        i++;
        int factor = 1;
        while (isdigit(input_buffer[i]))
        {
            result.mantissa = result.mantissa * 10 + input_buffer[i] - '0';
            factor *= 10;
            i++;
        }
        result.exp = -1 * (int)log10(factor);
    }

    if (input_buffer[i] == 'e' || input_buffer[i] == 'E')
    {
        i++;
        int exp = 0;
        if (input_buffer[i] == '-')
        {
            i++;
            while (isdigit(input_buffer[i]))
            {
                exp = exp * 10 + input_buffer[i] - '0';
                i++;
            }
            result.exp += -1 * exp;
        }
        else
        {
            while (isdigit(input_buffer[i]))
            {
                exp = exp * 10 + input_buffer[i] - '0';
                i++;
            }
            result.exp += exp;
        }
    }
    // normalize the result float
    normalize_float(result);
    return result;
}

void print_float_number(Float number)
{
    if (number.sign == -1)
    {
        cout << "-";
    }
    cout << number.mantissa;
    if (number.exp != 0)
    {
        cout << "e" << number.exp;
    }
}

void clean_up_input_buffer(char input_buffer[])
{
    for (int i = 0; input_buffer[i] != '\0'; i++)
    {
        input_buffer[i] = '\0';
    }
}

Float add(Float a, Float b)
{
    Float result;
    int same_sign = a.sign * b.sign;
    if (a.exp == b.exp)
    {
        result.sign = a.sign;
        result.exp = a.exp;
        result.mantissa = a.mantissa + same_sign * b.mantissa;
    }
    else if (a.exp > b.exp)
    {
        result.sign = a.sign;
        result.exp = a.exp;
        long exp_factor = (long)pow(10, a.exp - b.exp);
        result.mantissa = a.mantissa + same_sign * b.mantissa / exp_factor;
    }
    else
    {
        result.sign = b.sign;
        result.exp = b.exp;
        long exp_factor = (long)pow(10, b.exp - a.exp);
        result.mantissa = b.mantissa + same_sign * a.mantissa / exp_factor;
    }
    if (result.mantissa < 0)
    {
        result.sign *= -1;
        result.mantissa *= -1;
    } else if (result.mantissa == 0) {
        result.sign = 1;
    }
    normalize_float(result);
    return result;
}

Float sub(Float a, Float b)
{
    Float result;
    int same_sign = a.sign * b.sign;
    if (a.exp == b.exp)
    {
        result.sign = a.sign;
        result.exp = a.exp;
        result.mantissa = a.mantissa - same_sign * b.mantissa;
    }
    else if (a.exp > b.exp)
    {
        result.sign = a.sign;
        result.exp = a.exp;
        long exp_factor = (long)pow(10, a.exp - b.exp);
        result.mantissa = a.mantissa - same_sign * b.mantissa / exp_factor;
    }
    else
    {
        result.sign = b.sign;
        result.exp = b.exp;
        long exp_factor = (long)pow(10, b.exp - a.exp);
        result.mantissa = b.mantissa - same_sign * a.mantissa / exp_factor;
    }
    if (result.mantissa < 0)
    {
        result.sign *= -1;
        result.mantissa *= -1;
    } else if (result.mantissa == 0) {
        result.sign = 1;
    }
    normalize_float(result);
    return result;
}

Float mul(Float a, Float b)
{
    Float result;
    result.sign = a.sign * b.sign;
    result.exp = a.exp + b.exp;
    result.mantissa = a.mantissa * b.mantissa;
    normalize_float(result);
    return result;
}

Float div(Float a, Float b)
{
    Float result;
    result.sign = a.sign * b.sign;
    result.exp = a.exp - b.exp;
    result.mantissa = a.mantissa / b.mantissa;
    normalize_float(result);
    return result;
}

int main()
{
    char input_buffer[10000 + 1]; // + 1 for the last '\0'
    Float a, b;

    cout << "Input a float number (a) in (-)xxx.xxx(e|E)(-)(xxx): ";
    cin >> input_buffer;

    a = parse_float_number(input_buffer);

    clean_up_input_buffer(input_buffer);

    cout << "(a) = ";
    print_float_number(a);
    cout << endl;

    cout << "Input a float number (b) in (-)xxx.xxx(e|E)(-)(xxx): ";
    cin >> input_buffer;

    b = parse_float_number(input_buffer);

    clean_up_input_buffer(input_buffer);

    cout << "(b) = ";
    print_float_number(b);
    cout << endl;

    cout << "(a) + (b) = ";
    print_float_number(add(a, b));
    cout << endl;

    cout << "(a) - (b) = ";
    print_float_number(sub(a, b));
    cout << endl;

    cout << "(a) * (b) = ";
    print_float_number(mul(a, b));
    cout << endl;

    cout << "(a) / (b) = ";
    print_float_number(div(a, b));
    cout << endl;

    return 0;
}
$ g++ -g test.cpp && ./a.out
Input a float number (a) in (-)xxx.xxx(e|E)(-)(xxx): -123.456e3
(a) = -123456
Input a float number (b) in (-)xxx.xxx(e|E)(-)(xxx): 456.789e4
(b) = 456789e1
(a) + (b) = 444444e1
(a) - (b) = 469134e1
(a) * (b) = -563933427e3
(a) / (b) = 0
$ 

Structure example: Polynomial Equation

#include <iostream>
#include <cctype> // isdigit()
#include <vector>

using namespace std;

typedef struct Poly_t
{
    int coef;
    int exp;
} Poly;

void normalize(vector<Poly> &poly)
{
    for (int i = 0; i < poly.size(); i++)
    {
        if (poly[i].coef == 0)
        {
            poly.erase(poly.begin() + i);
            i--;
        }
    }
}

vector<Poly> parse_poly(char input_buffer[])
{
    vector<Poly> result;
    int i = 0;
    while (input_buffer[i] != '\0')
    {
        Poly p;
        int sign = 1;
        p.coef = 0;
        p.exp = 0;
        if (input_buffer[i] == '-')
        {
            sign = -1;
            i++;
        }
        else if (input_buffer[i] == '+')
        {
            i++;
        }
        if (input_buffer[i] == '0')
        {
            p.coef = 0;
            i++;
        }
        else
        {
            while (isdigit(input_buffer[i]))
            {
                p.coef = p.coef * 10 + input_buffer[i] - '0';
                i++;
            }
        }
        p.coef *= sign;
        if (input_buffer[i] == 'x')
        {
            i++;
            if (input_buffer[i] == '^')
            {
                i++;
                while (isdigit(input_buffer[i]))
                {
                    p.exp = p.exp * 10 + input_buffer[i] - '0';
                    i++;
                }
            }
        }
        result.push_back(p);
    }
    return result;
}

void print_poly(const vector<Poly> &poly)
{
    if (poly.size() == 0)
    {
        cout << "0";
        return;
    }
    for (int i = 0; i < poly.size(); i++)
    {
        if (poly[i].coef == 0)
        {
            continue;
        }
        if (poly[i].coef >= 1 && i != 0)
        {
            cout << "+" << poly[i].coef;
        }
        else if (poly[i].coef == -1)
        {
            cout << "-";
        }
        else
        {
            cout << poly[i].coef;
        }
        if (poly[i].exp == 0)
        {
            continue;
        }
        else
        {
            cout << "x^" << poly[i].exp;
        }
    }
}

vector<Poly> poly_add(const vector<Poly> &a, const vector<Poly> &b)
{
    vector<Poly> result;
    int i = 0;
    int j = 0;
    while (i < a.size() && j < b.size())
    {
        if (a[i].exp == b[j].exp)
        {
            Poly p;
            p.exp = a[i].exp;
            p.coef = a[i].coef + b[j].coef;
            result.push_back(p);
            i++;
            j++;
        }
        else if (a[i].exp > b[j].exp)
        {
            result.push_back(a[i]);
            i++;
        }
        else
        {
            result.push_back(b[j]);
            j++;
        }
    }
    while (i < a.size())
    {
        result.push_back(a[i]);
        i++;
    }
    while (j < b.size())
    {
        result.push_back(b[j]);
        j++;
    }
    normalize(result);
    return result;
}

void clean_up_input_buffer(char input_buffer[])
{
    for (int i = 0; input_buffer[i] != '\0'; i++)
    {
        input_buffer[i] = '\0';
    }
}

int main()
{
    char input_buffer[10000 + 1];
    vector<Poly> a, b;

    cout << "Enter polynomial a: ";
    cin >> input_buffer;

    a = parse_poly(input_buffer);

    clean_up_input_buffer(input_buffer);

    cout << "Polynomial a: ";
    print_poly(a);
    cout << endl;

    cout << "Enter polynomial b: ";
    cin >> input_buffer;

    b = parse_poly(input_buffer);

    clean_up_input_buffer(input_buffer);

    cout << "Polynomial b: ";
    print_poly(b);
    cout << endl;

    vector<Poly> c = poly_add(a, b);

    cout << "Polynomial c = a + b: ";
    print_poly(c);
    cout << endl;
}
$ g++ -g test.cpp && ./a.out
Enter polynomial a: -30x^3+20x^1
Polynomial a: -30x^3+20x^1
Enter polynomial b: 50x^3-20
Polynomial b: 50x^3-20
Polynomial c = a + b: 20x^3+20x^1-20
$ 

Structure example: Geometry Object

Ref: Computational geometry - Wikipedia

#include <iostream>
#include <vector>

using namespace std;

typedef struct Point_t
{
    int x;
    int y;
} Point;

typedef struct Triangle_t
{
    Point p[3];
} Triangle;

typedef struct Quadrilateral_t
{
    Point p[4];
} Quadrilateral;

typedef struct Polygon_t
{
    vector<Point> p;
} Polygon;

Point parse_point(char input_buffer[], int i)
{
    Point p;
    while (input_buffer[i] != '\0')
    {
        if (input_buffer[i] == '(')
        {
            i++;
        }
        if (input_buffer[i] == '0')
        {
            p.x = 0;
            i++;
        }
        else
        {
            while (isdigit(input_buffer[i]))
            {
                p.x = p.x * 10 + input_buffer[i] - '0';
                i++;
            }
        }
        if (input_buffer[i] == ',')
        {
            i++;
        }
        if (input_buffer[i] == '0')
        {
            p.y = 0;
            i++;
        }
        else
        {
            while (isdigit(input_buffer[i]))
            {
                p.y = p.y * 10 + input_buffer[i] - '0';
                i++;
            }
        }
        if (input_buffer[i] == ')')
        {
            break;
        }
    }
    return p;
}

Triangle parse_triangle(char input_buffer[])
{
    Triangle t;
    int i = 0;
    while (input_buffer[i] != '\0')
    {
        for (int j = 0; j < 3; j++)
        {
            if (input_buffer[i] == '(')
            {
                i++;
            }
            t.p[j] = parse_point(input_buffer, i);
            i += 2;
        }
    }
    return t;
}

Quadrilateral parse_quadrilateral(char input_buffer[])
{
    Quadrilateral q;
    int i = 0;
    while (input_buffer[i] != '\0')
    {
        for (int j = 0; j < 4; j++)
        {
            if (input_buffer[i] == '(')
            {
                i++;
            }
            q.p[j] = parse_point(input_buffer, i);
            i += 2;
        }
    }
    return q;
}

Polygon parse_polygon(char input_buffer[])
{
    Polygon poly;
    int i = 0;
    while (input_buffer[i] != '\0')
    {
        if (input_buffer[i] == '(')
        {
            i++;
        }
        poly.p.push_back(parse_point(input_buffer, i));
        i += 2;
    }
    return poly;
}

void print_geometry(const Point &p)
{
    cout << "(" << p.x << ", " << p.y << ")" << endl;
}

void print_geometry(const Triangle &t)
{
    cout << "Triangle: " << endl;
    for (int i = 0; i < 3; i++)
    {
        print_geometry(t.p[i]);
    }
}

void print_geometry(const Quadrilateral &q)
{
    cout << "Quadrilateral: " << endl;
    for (int i = 0; i < 4; i++)
    {
        print_geometry(q.p[i]);
    }
}

void print_geometry(const Polygon &poly)
{
    cout << "Polygon: " << endl;
    for (int i = 0; i < poly.p.size(); i++)
    {
        print_geometry(poly.p[i]);
    }
}

unsigned long int area(const Triangle &t)
{
    unsigned long int sum = 0;
    for (int i = 0; i < 3; i++)
    {
        sum += t.p[i].x * t.p[(i + 1) % 3].y;
        sum -= t.p[i].y * t.p[(i + 1) % 3].x;
    }
    return sum / 2;
}

unsigned long int area(const Quadrilateral &q)
{
    unsigned long int sum = 0;
    for (int i = 0; i < 4; i++)
    {
        sum += q.p[i].x * q.p[(i + 1) % 4].y;
        sum -= q.p[i].y * q.p[(i + 1) % 4].x;
    }
    return sum / 2;
}

unsigned long int area(const Polygon &poly)
{
    unsigned long int sum = 0;
    for (int i = 0; i < poly.p.size(); i++)
    {
        sum += poly.p[i].x * poly.p[(i + 1) % poly.p.size()].y;
        sum -= poly.p[i].y * poly.p[(i + 1) % poly.p.size()].x;
    }
    return sum / 2;
}

int main()
{
    char input_buffer[10000 + 1];

    cout << "Enter the type of geometry (t|q|p) with points (x,y): ";
    cin.getline(input_buffer, 10000);

    if (input_buffer[0] == 't')
    {
        Triangle t = parse_triangle(input_buffer + 1);
        print_geometry(t);
        cout << "Area: " << area(t) << endl;
    }
    else if (input_buffer[0] == 'q')
    {
        Quadrilateral q = parse_quadrilateral(input_buffer + 1);
        print_geometry(q);
        cout << "Area: " << area(q) << endl;
    }
    else if (input_buffer[0] == 'p')
    {
        Polygon poly = parse_polygon(input_buffer + 1);
        print_geometry(poly);
        cout << "Area: " << area(poly) << endl;
    }
    else
    {
        cout << "Invalid input" << endl;
    }
}
$ g++ -g test.cpp && ./a.out
Enter the type of geometry (t|q|p) with points (x,y): t((0,0),(1,1),(0,4))
Triangle: 
(0, 0)
(1, 1)
(0, 4)
Area: 2
$ g++ -g test.cpp && ./a.out
Enter the type of geometry (t|q|p) with points (x,y): q((0,0),(1,1),(3,4),(0,4))
Quadrilateral: 
(0, 0)
(1, 1)
(3, 4)
(0, 4)
Area: 6
$ g++ -g test.cpp && ./a.out
Enter the type of geometry (t|q|p) with points (x,y): p((0,0),(1,1),(3,4),(4,4),(0,4))
Polygon: 
(0, 0)
(1, 1)
(3, 4)
(4, 4)
(0, 4)
Area: 6
$

Structure example: Vector & Matrix (Mathmatical)

#include <iostream>
#include <vector>
#include <cmath>

using std::cin;
using std::cout;
using std::endl;

typedef struct Vector_t
{
    std::vector<double> unit;
    double length;
} Vector;

typedef struct Matrix_t
{
    std::vector<Vector> row_vectors;
} Matrix;

Vector parse_vector(char input_buffer[], int &i)
{
    Vector v;
    int number = 0
    // parse normal vector
    while (input_buffer[i] != '\0')
    {
        if (input_buffer[i] == '[')
        {
            i++;
        }
        if (input_buffer[i] == '0')
        {
            v.unit.push_back(0);
            i++;
        }
        else
        {
            while (isdigit(input_buffer[i]))
            {
                number = number * 10 + input_buffer[i] - '0';
                i++;
            }
            v.unit.push_back(number);
            number = 0;
        }
        if (input_buffer[i] == ',')
        {
            i++;
        }
        if (input_buffer[i] == ' ')
        {
            i++;
        }
        if (input_buffer[i] == ']')
        {
            break;
        }
    }
    // calc vector length
    for (int j = 0; j < v.unit.size(); j++)
    {
        v.length = v.length + v.unit[j] * v.unit[j];
    }
    v.length = sqrt(v.length);
    // normalize vector
    for (int j = 0; j < v.unit.size(); j++)
    {
        v.unit[j] = v.unit[j] / v.length;
    }
    return v;
}

Matrix parse_matrix(char input_buffer[])
{
    Matrix m;
    // parse matrix
    int i = 0;
    while (input_buffer[i] != '\0')
    {
        if (input_buffer[i] == '[')
        {
            i++;
        }
        while (input_buffer[i] != ']')
        {
            m.row_vectors.push_back(parse_vector(input_buffer, i));
        }
        if (input_buffer[i] == ']')
        {
            i++;
        }
    }
    return m;
}

void print_vector(const Vector &v)
{
    cout << "[";
    for (int i = 0; i < v.unit.size(); i++)
    {
        cout << v.unit[i] * v.length;
        if (i != v.unit.size() - 1)
        {
            cout << ", ";
        }
    }
    cout << "]";
}

void print_matrix(const Matrix &m)
{
    cout << "[";
    for (int i = 0; i < m.row_vectors.size(); i++)
    {
        print_vector(m.row_vectors[i]);
        cout << endl;
    }
    cout << "]";
}

int main()
{
    char input_buffer[10000 + 1];

    cout << "Enter a vector: ";
    cin.getline(input_buffer, 10000);

    int i = 0;
    Vector v = parse_vector(input_buffer, i);

    cout << "Vector v: " << endl;
    print_vector(v);
    cout << endl;
    cout << "Length: " << v.length << endl;
    cout << endl;

    cout << "Enter a matrix: ";
    cin.getline(input_buffer, 10000);

    Matrix m = parse_matrix(input_buffer);

    cout << "Matrix m: " << endl;
    print_matrix(m);
    cout << endl;
}
$ g++ -g test.cpp && ./a.out
Enter a vector: [9,10,11,12]
Vector v: 
[9, 10, 11, 12]
Length: 21.1187

Enter a matrix: [[1,2,3,4][5,6,7,8][9,10,11,12]]
Matrix m: 
[[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]
]
$