Find_ifs & types & Boole, oh my!
C++ next to the R code. It looks a little busy ’cause C++ needs to do certain things differently.
At the very least you get a gist of what’s going on. I’m gonna go through this in order of things which make most sense. And it’s colour coded for better mental digestion.
R-if-thym & blues
You can afford to have two separate if-statements checking for evenness. There’s other ways, like using vectors and iterators and loops, but there’s nothing to gain in efficiency when you only need to check two values.
The green while
This part is almost exactly the same. But remember that hooplah about ensuring the last value was below the threshold? Originally in the while-loop, it created a new Fibonacci number and then added it. This meant that “while(newfib<thr)” always checked the previous Fibonacci number, so the last time through the loop, it ends up adding a number larger than the threshold. Here, we immediately add the new Fibonacci number, and then create the new one. This way it always adds the most recently checked number, and never goes above the threshold. Swish.
R-oxanne! You don’t have to declare the red type
R represents all numbers the same way. C++ doesn’t. For integers, you tend to use int or long, either signed/unsigned. A long long unsigned (8 bytes / 64 bits) precisely stores integers up to 1.8E+19. Since you rarely deal with numbers that large, you can sacrifice precision for range. You can drop the number of significant digits to 7 or 15 (float or double), and use the bits gained, to have a larger range for the exponent, reaching up to 1.7E ± 308. See here for type ranges. What types to use? Consider what each variable is doing:
- Since s1 and s2 are provided by the user, and checked for evenness by integer division, they are just integers.
- fibc is gotten by adding up s1 and s2, and is only used for finding out which of the first three numbers is even. This is also int.
- fiba, fibb, and newfib are used in the while-loop, and store increasingly larger numbers, so we’ll use double.
- thr is provided by the user, and is likely to be in the range of int or long, but it doesn’t hurt to make it double. fibsum is our final cumulative sum, so that’s double.
- Note: when you mix numbers of different types in a calculation, the lower (less precise) type gets ‘promoted’ to a more precise type. For example, int fibc = s1+s2, which are also both int. But we declare double newfib = fibc. Fibc and s1 and s2 remain unmolested, but the int value of fibc, when put into newfib, is stored as double. Useful!
Orange you glad I left this ’till last?
There may be easier ways of doing this, but I haven’t found it. But hey, it’s a good opportunity to introduce new ideas. We want to store the index of whichever of the first three values is even. We can’t use ‘which’ in C++, so we use an iterator. See ‘unique’ here for a reminder.
- We want fiba, fibb, fibc as a vector, and to work out which is even. We can’t just explicitly put elements into a vector in C++ (unless we do it one-by-one), so we have to initialize it. There’s a number of ways you can initialize/construct it: it can be empty, or each value can be identical, or you can copy a range from somewhere, or you can copy a preexisting vector. The third option is the one to use, here.
- You can explicitly put elements in an array (a fixed-length vector) though.
- Then we copy this whole range into the vector we want to search through.
- The stuff in parentheses, in this context, is called a constructor. By default, if you put an object (fibarr) in the beginning location of a constructor, it refers to the first element, which is numbered . fibarr+3 refers to the th element, which is one-past-the-end, essentially saying ‘up to but not including’, so we have the three elements fiba, fibb, fibbc, numbered ,,.
- This says: search (find_if) through this vector, returning an iterator/pointer to the element which fulfils a certain (IsEven) condition.
- IsEven is a tiny little function which returns a Boolean value (true) if a certain condition (evenness) is met. Otherwise, it returns false. (George Boole is considered the father of computer logic. Like, he banged computer logic’s mom).
- We define this before main, so that main knows what’s happening when IsEven is called. Or we can define it after main, as long as we declare it “bool IsEven (int i)” before. (This function is too small to justify a header-file).
- Anyway, the above line returns an iterator (it) to the first instance of that condition being true (since there can only be one even instance in a group of three sequential Fibonacci numbers, that’s all we need).
- ‘it’ points to the value though, not the index. So here’s a little trick to get the index:
- This finds the distance between the first value and ‘it’. So you add 1 to get the true index.
- We also have setprecision in the final line to specify the number of significant digits to use in returning an answer (7 sig figs / 6 decimal places).
That’s it! Sorted.
Next up: a spectacular proof that works out a formula for generating Fibonacci numbers, without needing to find any earlier Fibonacci numbers. Gosh! Mathemagical.