This sequence of tutorials will help Nanotechnology students transition from Python and Matlab to C++.
In Python and Matlab, all your commands are read by an interpreter:
>>> print( "Hello world!" ) Hello world!
If you want to use a function, you must define it:
>>> def factorial1( n ): if (n == 0) or (n == 1): return n else: return n*factorial1( n - 1 ) >>> def factorial2( n ): result = 1; for k in range( 2, n + 1 ): result *= k; return result; >>> print( factorial1( 5 ) ); 120 >>> print( factorial2( 5 ) ); 120
View this code in repl.it.
Now, to emphasize how much work Python does at each step, consider if you were to change the first 5 into 5.1, and then the second. In the first case, n would now be a floating point number and not an integer.
In the first case, it seems to keep looping:
Notice that the condition will never be true, so this will keep going on and on. You will note, however, that previously, it was doing all the calculations with integers, and now you are doing calculations with floating-point numbers. There are entirely different components of the CPU that perform these computations: the sum of two integers is calculated in the arithmetic logic unit (ALU) and the sum of two floating-point numbers is calculated in the floating-point unit (FPU). Thus, each time an operation occurs, Python must first determine whether the arguments are integers or floating-point numbers, and then it must execute a different instruction.
In the second case, you get the error:
TypeError: range() integer end argument expected, got float.
The problem here is that range requires that its arguments be integers.
If you want to check the arguments, you must use the isinstance(...) function:
>>> def factorial1( n ): if not isinstance( n, (int, long) ) or (n < 0): raise Exception( "n must be a positive integer" ); if n == 0 or n == 1: return 1 else: return n*factorial1( n - 1 ) >>> def factorial2( n ): if not isinstance( n, (int, long) ) or (n < 0): raise Exception( "n must be a positive integer" ); result = 1; for k in range( 2, n + 1 ): result *= k; return result;
View this code in repl.it.
Now, exceptions will be raised if the user tries to call these functions with anything other than positive integers.
We will now look at these functions in C++, and investigate some of the differences.
In C++, you must tell the compiler exactly the type of each variable is before it is ever used. This is called a declaration. The following is an implementation of the two previous functions that we just saw:
#include <iostream> // Function declarations int main(); unsigned int factorial1( unsigned int n ); unsigned int factorial2( unsigned int n ); // Function definitions unsigned int factorial1( unsigned int n ) { if ( n <= 1 ) { return 1; } else { return n*factorial1( n - 1 ); } } unsigned int factorial2( unsigned int n ) { unsigned int result{1}; for ( unsigned int k{2}; k <= n; ++k ) { result *= k; } return result; } int main() { std::cout << factorial1( 5 ) << std::endl; std::cout << factorial2( 5 ) << std::endl; return 0; }
View this code in repl.it.
The first point you will note is that, unlike Python, there are now three functions, and the statements in which you are calculating the factorial of five is in a new function called main().
This is because C++ is not an interpreted environment: instead, the entire file is compiled into a executable program, and when that program is executed, the function that is called is main().
You cannot, for example, in C++ execute some statements, and then look at the output, and then type some more. Instead, you must author the entire syntax-error-free program, compile it, and then execute it. For example, suppose instead you want to calculate factorial2( 6 ), you must recompile and re-execute the entire program. Does this make one programming environment (interpreted versus compiled) better than the other? No, but each has a different purpose.
The interpreted environment of Python and Matlab is excellent for modelling: you can investigate, look at the output, decide what you want to do next, and then carry on from there. You can always change your mind and try something else. If you make a syntax error while entering a command, this isn't an issue, as the interpreter will let you know, and you can try again:
>>> def abs( x ): ... if x < 0: ... return -x ... else: ... return x; ... >>> abs( -3.5 )) File "<stdin>", line 1 abs( -3.5 )) ^ SyntaxError: invalid syntax >>> abs( -3.5 ) 3.5
The compiled environment requires the programmer to determine everything that must be computed prior to compilation, and if the result is insufficient, the programmer must go back to rewrite the code, compile it again, and then execute it again.
On the other hand, Python is interpreted, so each time you enter a command, it must be parsed ("understood") and interpreted ("converted into instructions, which are then executed"). The compiler does this once, so when you execute a compiled program, it is simply executing the instructions. Consequently, Python can be as much as 400 times slower than C++, although fifty to 100 times slower is likely closer to the mark, on average. On the other hand, if it takes 10 ms to execute a Python versus 75 ns for the equivalent code in C++, given that the Python code is generally interacting with a human, it is unlikely to matter. Now, if you call a library in Python, that library may already be compiled, and therefore calling a function in a library may be as fast as the equivalent code in C++.
Thus, interpreted languages (Python and Matlab) are excellent for investigation, while compiled languages are excellent for speed. Throughout this introduction, we will understand why, first by looking at types.
You will recognize parameters in C++, as well as local variables, but the parameter is prefixed by unsigned int. This tells the compiler that any argument passed to this function is a positive integer (unsigned int) (0, 1, 2, ..., 232 - 1). Now, each time you perform any arithmetic operation with n, it will execute the appropriate instruction in the ALU for performing such an operation on such operands.
You will also note that the name of the function is prefixed by int or unsigned int, and this tells the compiler that these functions will return an signed integer (int) (-231, ..., -2, -1, 0, 1, 2, ..., 231 - 1) or a positive integer (unsigned int).
int main(); unsigned int factorial1( unsigned int n ); unsigned int factorial2( unsigned int n );
You will also note that the body of the function, the conditional statement, and what you may recognize as a for loop all have statements that are wrapped by an opening brace and a matching closing brace.
You will note that the conditional statements (if statements) look very similar to Python, except the parentheses around the condition are required in C++. The return statements are similar, and the use of the arithmetic operators appear to be the same or similar.