Monday, 20 June 2022

Chapter 25 // Drill 3, 4, 5 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 25 // Drill 3

Using hexadecimal literals, define short unsigned ints with:
  • Every bit set
  • The lowest (least significant bit) set
  • The highest (most significant bit) set
  • The lowest byte set
  • The highest byte set
  • Every second bit set (and the lowest bit 1)
  • Every second bit set (and the lowest bit 0)

Chapter 25 // Drill 4

Print each as a decimal and as a hexadecimal.

Chapter 25 // Drill 5

Do 3 and 4 using bit manipulation operations (|, &, <<) and (only) the literals 1 and 0.


I cheated with drill 3 and just wrote out the binary then converted it to hex using 

5 was annoying because you can directly type out binary literals in C++14 and assign them to things. The challenge came from only using 1 and 0. Like setting the highest byte can be done with 1 << 15 but 15 isn't 1 or 0.

I honestly had no idea how to do the last 2 using only 1 and 0, so I cheated and just used direct binary strings.


Sunday, 19 June 2022

Chapter 25 // Drill 1, 2 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 25 // Drill 1

Run this:
int v = 1; for(int i = 0; i < sizeof(v)*8; ++i) { cout << v << ' '; v << =1; }

I've never seen <<= before. But shifting to the left by 1 is the "cheapest" and "fastest" way to multiply by 2. In some very low-level engine code at work, I often see >> 1 to divide by 2 instead of / 2, however it's not 1995 anymore and Visual Studio will convert divides/multiplies that are powers of 2 to an equivalent shift for you.

The last number will wrap as it's 1 over the max limit of a signed int.

Chapter 25 // Drill 2

Run that again with v declared to be an unsigned int.


.

Saturday, 18 June 2022

Chapter 24 // Exercise 12 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 12

Implement
Matrix<double> operator*(Matrix<double,2>&, Matrix<double>&);
and
Matrix<double, N> operator+(Matrix<double, N>&, Matrix<double, N>&)
If you need to, look up the mathematical definitions in a textbook.


So the first one is already supplied on page 913. Here he refers to it as a vector, but a 1 dimensional matrix is a vector.

For the second I discovered you can't use Bjarne's code to initialise a 3d matrix with a 3d array as it will cause a heap corruption. So I created a little function to use with the inbuilt apply to quickly populate the 3d matrix.

Being able to add a matrix of any incoming dimension was a bit of a head scratcher until I came across this post:

std::transform takes in an iterator to the beginning and end of your container, then uses a function object on each element. Matrix doesn't have iterators but it does supply a pointer to the beginning of the data. So I supplied transform with the raw data pointers, the size of the matrix and a new matrix to put the data into to. This way we don't have to care how many dimensions there actually are.

And with that chapter 24 is done! For once I didn't take 3 months to finish a chapter. Really looking forward to the embedded systems one (which is next) and the final chapter on C programming.

Friday, 17 June 2022

Chapter 24 // Exercise 11 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 11

Write a swap_columns() to match swap_rows() from section 24.5.3. Obviously, to do that you have to read and understand some of the existing Matrix library code. Don't worry too much about efficiency; it is not possible to get swap_columns() to run as fast as swap_rows().


I started off by modifying the swapRow function I did for vectors in exercise 7. Once that was working, I simply switched the subscripting round. Then copied that into a member function for 2d matrixes.

Thursday, 16 June 2022

Chapter 24 // Exercise 10 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 10

How random is your default_random_engine? Write a program that takes two integers n and d as inputs and calls randint(n) d times, recording the result. Output the number of draws for each of [0:n] and "eyeball" how similar the counts are. Try with low values for n and with low values for d to see if drawing only a few random numbers causes obvious biases.


I used some of the code on pg 915/916 but didn't add the normal distribution bit. Originally, the std_lib_facilities file did not seed the default random engine so it wasn't random at all. I changed that a while back and now it uses the pc time as a seed so it's almost always different. On this run, it looked pretty random? That said I just did a 5 draws with a max of 5 over and over and it started to seem pretty suspicious after while. But for a single number I need now and then, it's fine.


Wednesday, 15 June 2022

Chapter 24 // Exercise 9 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 9

Rewrite the non-member apply() functions to return a Matrix of the return type of the function applied; that is, apply(f, a) should return a Matrix<R> where R is the return type of f. Warning: The solution requires information about templates not available in this book.


Fortunately, as I attempted exercise 3, I already had a way to determine the return type of f by checking to see if it was void:
// if the return type of pFunction is not void
if constexpr (!std::is_same_v<std::invoke_result_t<F, decltype(pContainer[0])>, void>)
This uses std::invoke_result which is C++17, but the C++11 alternative is std::result_of. std::is_same is also available in C++11 so I have a feeling, the std metaprogramming library is what he was hinting at:
https://en.cppreference.com/w/cpp/meta

I used the result of invoke_result to determine the return type then create a matrix of that return type and used auto to let the function determine what it should return.

It works for one specific scenario. I still need more practice with metaprogramming to try and fix this as I was scratching my head as to why it just wouldn't deduce the type. This is definitely an exercise to come back to in the future.

Tuesday, 14 June 2022

Chapter 24 // Exercise 8 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 8

Animate the Gaussian elimination.


Honestly had no idea what he meant by this. I assumed just show the matrix being modified after each step?

Whilst doing this I had a look back at my slice function and even though it looks different to the one in Matrix.h it actually does the job! I had a google for C++ solutions on Gaussian Elimination and found this:

Which is way less code, however all that subscripting is hard to read. I prefer having the seperate function to scale, get the dot_product etc.; it's easier to read what's happening. Also, having to modify Bjarne's matrix code to work with vectors was an enjoyable challenge. I created some matrices to test with Bjarne's code from exercise 5 and this produces the same output.

I went into these 5 exercises on Gaussian elimination terrified because maths and whereas I still don't fully get what the point of it is, these exercises were a good lesson on not really needing to understand the bigger picture; just verify that the code is doing the correct thing and that I can read and understand the code.


Monday, 13 June 2022

Chapter 24 // Exercise 7 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 7

Rewrite the Gaussian elimination program without using the Matrix library; that is, use built-in arrays or vectors instead of Matrixes.


For this I initially change the
using MatrixD2 = Numeric_lib::Matrix<double, 2>;
using MatrixD1 = Numeric_lib::Matrix<double, 1>;
to
using MatrixD2 = vector<vector<double>>;
using MatrixD1 = vector<double>;
Then started going through the code and replacing what was red until it compiled. The hardest part was creating a slice for vector for the scale and add....I think my solution is working? I'm terrible at maths though and found this exercise particularly difficult.

Sunday, 12 June 2022

Chapter 24 // Exercise 6 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 6

In the Gaussian elimination example, replace the vector operations dot_product() and scale_and_add() with loops. Test, comment on the clarity of the code.


For this one I simply copied the code from the Matrix.h files. Replacing the one in the back_substitution was horrible. 

We have functions for a reason; to do tasks, remove duplicate code and make it clear what's happening without commenting.

Saturday, 11 June 2022

Chapter 24 // Exercise 5 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 5

Try the Gaussian elimination program with A == { {0 1} {1 0} } and B == { 5 6 } and watch it fail. Then, try elim_with_partial_pivot().


Ok, so after seeing this exercise I have a feeling that A is supposed to be an Identity matrix? I messed around with the program and it always worked after I left A as given above; no matter what B was. I think A is always supposed to be an identity matrix....that is if I understood what maths is fun was going on about.

EDIT - So as this post was scheduled I made this edit 10 mins after moving onto exercise 6 when I realised that my randomMatrix function was complete garbage lol. A does not need to be an identity matrix.

Friday, 10 June 2022

Chapter 24 // Exercise 4 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 4

Get the Gaussian elimination program to work; that is, complete it, get to compile, and test it with a simple program.


First I had to google what in the hell is a gaussian elimination. That didn't help. So I started writing out the code from the book... that didn't really help either.

The code compiled but when running the program, it always errored in the classical elimination bit as the pivot was always 0 on the second round of the for loop.

I guess that was the point though? I think it's always supposed to fail but I honestly have no idea. Anyway, I completed the code, got it to compile and tested it with a simple program so, exercise done I guess??

EDIT - I completed this post, scheduled it then did exercise 5. When starting exercise 6 I realised my randomMatrix generator for a 2d array was complete garbage and that's why it always crashed lol.


Thursday, 9 June 2022

Chapter 24 // Exercise 3 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 3

Expert level only (this cannot be done with the facilities described in this book): Write an apply(f, a) that can take a void(T&), a T(const T&), and their function object equivalents. Hint: Boost::bind.


I was determined to complete this exercise...I mean he basically challenged me by saying it's "Expert level only".

I bashed my head against the wall for many hours. I knew it had something to do with the return type of the function and checking for void. Eventually I posted in our works discord and template wizard Keith came to my rescue. He first suggested to ignore the bind hint and take a look at std::for_each instead.

This helped however I was still having trouble determining if the incoming function at runtime returned void or not. He then hinted at std::result_of. That is deprecated now but I managed to piece together bits from this post on how to use invoke_result:

I got this working for the T(const T&) but it would not compile for void(T&). He then told me to add constexpr to the if (function return type is void), as that would prevent the compiler from doing a compile time branch.....it WORKED.

Getting this small function to work was one hell of a high.




Wednesday, 8 June 2022

Chapter 24 // Exercise 2 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 2

Do exercise 1 again, but with function objects, rather than functions. Hint: Matrix.h contains examples.


So in the header there's already a function object called Mul_assign that you can call with apply like this:
m.apply(Mul_assign<int>(), 3) and that will triple all the elements.

Tuesday, 7 June 2022

Chapter 24 // Exercise 1 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Exercise 1

The function arguments f for a.apply(f) and apply(f,a) are different. Write a triple() function for each and use each to triple the elements of an array { 1 2 3 4 5 }. Define a single triple() function that can be used for both a.apply(triple) and apply(triple, a). Explain why it could be a bad idea to write every function to be used by apply() that way.


I read this exercise and immediately thought "what the fuck?"

After re-reading section 24.5.2 I realised that apply() basically takes in a pointer to a function and then calls that function on each element in the container. So after some messing around the difference is that a.apply() modifies the elements, apply returns a copy. 

Therefore the single triple function needs to both modify the argument and return a value. This is a bad idea as you don't always want function modifying your containers. Giving users the option is always better.




Monday, 6 June 2022

Chapter 24 // Drill 8 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Drill 8

Read six ints into a Matrix<int,2> m(2,3) and print them out.


.

Sunday, 5 June 2022

Chapter 24 // Drill 7 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Drill 7

Read ten complex<double>s from cin (yes, cin supports >>  for complex) and put them into a Matrix. Calculate and output the sum of the ten complex numbers.


Complex does have built in I/O support which is nice. Figuring out how to use cin was annoying though. I eventually discovered it here:

You need to input it as (num,num). 

Saturday, 4 June 2022

Chapter 24 // Drill 6 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Drill 6

Compute a multiplication table for [0,n) * [0, m) and represent it as a 2D Matrix. Take n and from cin and print out the table nicely (assume that m is small enough that the results fit on a line).


.

Friday, 3 June 2022

Chapter 24 // Drill 5 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Drill 5

Read ten floating-point values from input and put them into a Matrix<double>. Matrix has no push_back() so be careful to handle an attempt to enter a wrong number of doubles. Print out the Matrix.


The accompanying MatixIO.h file provides very simple I/O for 1D and 2D matrices. So
Matrix<double> a(4);
cin >> a;
cout << a;

Will read 4 whitespace-seperate doubles delimited by curly braces. For example with a 1D matrix:
{ 1.2 3.4 5.6 7.8 }

These functions will handle reading in the correct amount of numbers and throw errors if the structure isn't exact.

I also added my own method for fun.

Thursday, 2 June 2022

Chapter 24 // Drill 4 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Drill 4

Write a program that takes ints from cin and outputs the sqrt() of each int, or "no square root" if sqrt(x) is illegal for some x (i.e., check your sqrt() return values).


So the std::sqrt function is explained here:

I didn't realise it returned floats, doubles or long doubles. It returns some error handles if something goes wrong defined here:


Wednesday, 1 June 2022

Chapter 24 // Drills 1, 2, 3 - Principles & Practice Using C++

In this exercise I am using Visual Studio 2019 and a modified version of the std_lib_facilities header found here.

Chapter 24 // Drill 1

Print the size of a char, a short, an int, a long, a float, a double, an int*, and a double* (use sizeof, not <limits>).

Chapter 24 // Drill 2

Print out the size as reported by sizeof of Matrix<int> a(10), Matrix<int> b(100), Matrix<double> c(10), Matrix<int, 2> d(10,10), Matrix<int, 3> e(10,10,10).

Chapter 24 // Drill 3

Print out the number of elements of each of the Matrixes from 2.


Dear god, reading this chapter almost sent me to sleep several times...there's just something about matrices that bores the shit out of me.

Matrix.h is a file made up by Bjarne. You can find a copy of it in here:
or here:

The ones with 11 on them I think are for the second edition of the book??