In this chapter, you start learning some basics about a few mathematical operations, including prime numbers and the Roman numeral system. Additionally, I present a couple of ideas for number games. The chapter is rounded off by a short introduction to lambdas. With all this knowledge, you should be well prepared for the exercises.
2.1 Introduction
2.1.1 Short Introduction to Division and Modulo
Besides multiplication and division, the modulo operation (%) is also used quite frequently. It is intended to determine the remainder of a division. Let’s illustrate this as follows for integers where division remainders fall under the table:
(5 ∗ 7 + 3) // 7 = 38 // 7 = 5
(5 ∗ 7 + 3) % 7 = 38 % 7 = 3
n / 10: Obviously divides by the value 10. Since Python 3, this returns a floating point number as result. If you need an integer, you can use a type conversion with int(), such as int(value / 10).
n // 10: Also divides by the value 10. Because the // operator performs an integer division without a remainder, it is possible to truncate the last digit with it.
n % 10: Determines the remainder of a division by 10 and thus the last digit.
2.1.2 Short Introduction to Divider
One more small note about naming: For loop variables, short names like i are common, but current_number would also be a readable alternative.
2.1.3 Short Introduction to Prime Numbers
A prime number is a natural number that is greater than 1 and exclusively divisible by itself and by 1. There are two quite understandable algorithms for checking whether a given number is prime or for calculating primes up to a given maximum value.
Optimization: Sieve of Eratosthenes Another algorithm for determining prime numbers up to a given maximum value is called the Sieve of Eratosthenes . It dates back to the Greek mathematician with the same name.
The whole thing works as follows. Initially, all numbers starting at the value 2 up to the given maximum value are written down, for example
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
All numbers are initially considered as potential candidates for prime numbers. Now the numbers that cannot be prime numbers are eliminated step by step. The smallest unmarked number is taken, in this case, the number 2, which corresponds to the first prime number. Now all multiples of it are eliminated, in the example 4, 6, 8, 10, 12, 14:
You continue with the number 3, which is the second prime number. Again, the multiples are eliminated. These are the numbers 6, 9, 12, 15:
The next unmarked number and thus a prime number is 5. The procedure is repeated as long as there are still unmarked numbers after the current prime number:
This leads to the following result for all prime numbers smaller than 15:
2, 3, 5, 7, 11, 13
Limit | Result |
---|---|
25 | [2, 3, 5, 7, 11, 13, 17, 19, 23] |
50 | [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] |
As you can see, numbers are often crossed out several times. If you are mathematically a little more experienced, you can prove that at least one prime factor of a composite number must always be smaller equal to the root of the number itself. The reason is that if x is a divisor greater than sqrt(n), then it holds that p = n/x is smaller than sqrt(n) and thus this value has already been tried. Thus you can optimize the multiples’ elimination. Firstly, you start the elimination with the square of the prime number since all smaller multiples are already eliminated. Secondly, the calculation has to be done only up to the root of the upper limit. More details are supplied under https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes.
2.1.4 Roman Numbers
Roman number | I | V | X | L | C | D | M |
Value | 1 | 5 | 10 | 50 | 100 | 500 | 1000 |
The corresponding value is usually calculated by adding the values of the individual digits from left to right. Normally (see the following rules), the largest number is on the left and the smallest number is on the right, for example, XVI for the value 16.
Rules
- 1.
Addition rule: The same digits next to each other are added, for example XXX = 30. Likewise, this applies to smaller digits after larger ones, so XII = 12.
- 2.
Repetition rule: No more than three identical digits may follow each other. According to rule 1, you could write the number 4 as IIII, which this rule 2 forbids. This is where the subtraction rule comes into play.
- 3.Subtraction rule: If a smaller number symbol appears in front of a larger one, the corresponding value is subtracted. Let’s look again at 4. It can be represented as subtraction 5 − 1. This is expressed as IV in the Roman numeral system. The following rules apply to the subtraction:
I precedes only V and X.
X precedes only L and C.
C precedes only D and M.
Examples
Noteworthy
The Arabic numerals common in our modern world rely on the decimal system. The digits’ position determines their value: thus, 7 can be the number itself, but it can also represent 70 or 700. However, in the Roman numeral system, the V always stands for a 5, regardless of the position.
Because of this particular structure of Roman numerals, many math operations are complex; even a simple addition may cause a bigger or sometimes even a complete change of the number. This becomes very obvious for the numbers 2018 and 2019 or for the addition III + II = V. Even worse, significantly more complex is a multiplication or division—there are speculations that this was one of the factors why the Roman Empire collapsed.
There are special notations for representing larger Roman numerals (in the range of ten thousand and above) because no four or more Ms are allowed to follow each other. This has no relevance for the tasks of this book. If interested, you may consult the Internet or other sources.
2.1.5 Number Games
Perfect numbers
Armstrong numbers
Checksums
In many of the algorithms used below, you subdivide numbers into their digits to be able to perform corresponding number games.
Perfect Numbers
By definition, a number is called a perfect number if its value is equal to the sum of its real divisors (i. e., excluding itself). This may sound a bit strange, but it is quite simple. Let’s consider the number 6 as an example. It possesses as real divisors the numbers 1, 2, and 3. Interestingly, it now holds
1 + 2 + 3 = 6
Let’s look at another counterpart: the number 20, which has the real divisors 1, 2, 4, 5, and 10, but their sum is 22 and not 20.
1 + 2 + 4 + 5 + 10 = 22
Armstrong Numbers
The digits of the number are modeled as x, y, and z and are all in the range from 0 to 9.
For the first equation, there are the following solutions:
[135, 175, 518, 598]
For the second equation, there is no solution for x, y, and z in the range up to 100. If you like, you can verify this yourself when implementing the bonus part of exercise 9—or look at the solutions.
Algorithm for a Simple Checksum
A checksum is coded into various numbers so that it is easy to prove validity. This applies, for example, to credit card numbers and to data transfers via special protocols.
Input | Position calculation | Value | Checksum |
---|---|---|---|
1111 | 1 * 1 + 1 * 2 + 1 * 3 + 1 * 4 | 1 + 2 + 3 + 4 = 10 | 10 % 10 = 0 |
1234 | 1 * 1 + 2 * 2 + 3 * 3 + 4 * 4 | 1 + 4 + 9 + 16 = 30 | 30 % 10 = 0 |
4321 | 4 * 1 + 3 * 2 + 2 * 3 + 1 * 4 | 4 + 6 + 6 + 4 = 20 | 20 % 10 = 0 |
7271 | 7 * 1 + 2 * 2 + 7 * 3 + 1 * 4 | 7 + 4 + 21 + 4 = 36 | 36 % 10 = 6 |
0815 | 0 * 1 + 8 * 2 + 1 * 3 + 5 * 4 | 0 + 16 + 3 + 20 = 39 | 39 % 10 = 9 |
5180 | 5 * 1 + 1 * 2 + 8 * 3 + 0 * 4 | 5 + 2 + 24 + 0 = 31 | 31 % 10 = 1 |
2.1.6 Getting Started with Lambdas
This subsection briefly introduces lambda expressions (lambdas for short). The language construct lambda comes from functional programming. Lambdas reflect the mathematical concept of functions with input, processing, and output, for example a squaring f(x) = x ∗ x. This can also be implemented using functions in Python, but lambdas offer an even shorter notation. Simply speaking, a lambda is a container for some source code or an anonymous function, such as one without a function name. Although lambdas are useful in many ways, sometimes readability and comprehensibility suffer. Therefore the Python style guide (PEP 8) is not necessarily in favor of lambdas.
Lambda Syntax
Please note that the PEP 8 style guide states to not assign a lambda expression and to use a def instead. Occasionally, as in the above case, I name lambdas for a better insight into how things work or to express more clearly what was intended even though they usually encapsulate only a tiny piece of functionality and thus should not be named.
Lambdas in Action with sort( )
2.2 Exercises
2.2.1 Exercise 1: Basic Arithmetic (★✩✩✩✩)
Exercise 1a: Basic Arithmetic Operations (★✩✩✩✩)
Write function calc(m, n) that multiplies two variables m and n of type int, then divides the product by two, and outputs the remainder with respect to division by 7.
Examples
m | n | m * n | m * n // 2 | Result ((n * m // 2) % 7) |
---|---|---|---|---|
6 | 7 | 42 | 21 | 0 |
5 | 5 | 25 | 12 | 5 |
A short reminder: With an integer division, the remainder is truncated. Therefore 25//2 results in the value 12.
Exercise 1b: Statistics (★★✩✩✩)
Count as well as sum up the natural numbers that are divisible by 2 or 7 up to a given maximum value (exclusive) and output it to the console. Write function calc_sum_and_count_all_numbers_div_by_2_or_7(max_exclusive). Extend it so that it returns the two values instead of performing the console output.
Examples
Maximum | Divisible by 2 | Divisible by 7 | Result | |
---|---|---|---|---|
Count | Sum | |||
3 | 2 | -/- | 1 | 2 |
8 | 2, 4, 6 | 7 | 4 | 19 |
15 | 2, 4, 6, 8, 10, 12, 14 | 7, 14 | 8 | 63 |
Exercise 1c: Even or Odd Number (★✩✩✩✩)
Create the functions is_even (n) and is_odd(n) that will check if the passed integer is even or odd, respectively.
2.2.2 Exercise 2: Number as Text (★★✩✩✩)
Write function number_as_text(n) which, for a given positive number, converts the respective digits into corresponding text.
Examples
Input | Result |
---|---|
7 | “SEVEN” |
42 | “FOUR TWO” |
24680 | “TWO FOUR SIX EIGHT ZERO” |
13579 | “ONE THREE FIVE SEVEN NINE” |
2.2.3 Exercise 3: Perfect Numbers (★★✩✩✩)
By definition, a natural number is called a perfect number if its value is equal to the sum of its real divisors. This is true, for example, for the numbers 6 and 28:
1 + 2 + 3 = 6
1 + 2 + 4 + 7 + 14 = 28
Write function calc_perfect_numbers(max_exclusive) that calculates the perfect numbers up to a maximum value, say 10,000.
Examples
Input | Result |
---|---|
1000 | [6, 28, 496] |
10000 | [6, 28, 496, 8128] |
2.2.4 Exercise 4: Prime Numbers (★★✩✩✩)
Write function calc_primes_up_to(max_value) to compute all prime numbers up to a given value. As a reminder, a prime number is a natural number greater than 1 and exclusively divisible by itself and by 1. To compute a prime number, the Sieve of Eratosthenes was described before.
Examples
Input | Result |
---|---|
15 | [2, 3, 5, 7, 11, 13] |
25 | [2, 3, 5, 7, 11, 13, 17, 19, 23] |
50 | [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] |
2.2.5 Exercise 5: Prime Number Pairs (★★✩✩✩)
Examples
Type | Result |
---|---|
twin | {3: 5, 5: 7, 11: 13, 17: 19, 29: 31, 41: 43} |
cousin | {3: 7, 7: 11, 13: 17, 19: 23, 37: 41, 43: 47} |
sexy | {5: 11, 7: 13, 11: 17, 13: 19, 17: 23, 23: 29, 31: 37, 37: 43, 41: 47, 47: 53} |
2.2.6 Exercise 6: Checksum (★★✩✩✩)
Examples
Input | Sum | Result |
---|---|---|
“11111” | 1 + 2 + 3 + 4 + 5 = 15 | 15 % 10 = 5 |
“87654321” | 8 + 14 + 18 + 20 + 20 + 18 + 14 + 8 = 120 | 120 % 10 = 0 |
2.2.7 Exercise 7: Roman Numbers (★★★★✩)
Exercise 7a: Roman Numbers ➤ Decimal Numbers (★★★✩✩)
Write function from_roman_number(roman_number) that computes the corresponding decimal number from a textually valid Roman number .4
Exercise 7b: Decimal Numbers ➤ Roman Numbers (★★★★✩)
Write function to_roman_number(value) that converts a decimal number to a (valid) Roman number.
Examples
Arabic | Roman |
---|---|
17 | “XVII” |
444 | “CDXLIV” |
1971 | “MCMLXXI” |
2020 | “MMXX” |
2.2.8 Exercise 8: Combinatorics (★★✩✩✩)
Exercise 8a: Computation of a2 + b2 = c2
Bonus (★★★✩✩) Reduce the running time of O(n3) to O(n2). If needed, consult Appendix C for an introduction to O-notation.
Exercise 8b: Computation of a2 + b2 = c2 + d2
Bonus (★★★✩✩) Reduce the running time of O(n4) to O(n3).
2.2.9 Exercise 9: Armstrong Numbers (★★✩✩✩)
Write function calc_armstrong_numbers() to compute all Armstrong numbers for x, y, and z (each < 10).
Examples
2.2.10 Exercise 10: Max Change Calculator (★★★★✩)
Suppose you have a collection of coins or numbers of different values. Write function calc_max_possible_change(values) that determines, for positive integers, what amounts can be seamlessly generated with it starting from the value 1. The maximum value should be returned as a result.
Examples
Input | Possible values | Maximum |
---|---|---|
1 | 1 | 1 |
1, 1 | 1, 2 | 2 |
1, 5 | 1 | 1 |
1, 2, 4 | 1, 2, 3, 4, 5, 6, 7 | 7 |
1, 2, 3, 7 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 | 13 |
1, 1, 1, 1, 5, 10, 20, 50 | 1, 2, 3, 4, 5, 6, ... 30, ... 39 | 39 |
2.2.11 Exercise 11: Related Numbers (★★✩✩✩)
Two numbers n1 and n2 are called friends (or related) if the sum of their divisors is equal to the other number:
sum(divisors(n1)) = n2
sum(divisors(n2)) = n1
Write function calc_friends(max_exclusive) to compute all friends numbers up to a passed maximum value.
Examples
Input | Divisors |
---|---|
∑(divisors(220)) = 284 | div(220) = 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110 |
∑(divisors(284)) = 220 | div(284) = 1, 2, 4, 71, 142 |
∑(divisors(1184)) = 1210 | div(1184) = 1, 2, 4, 8, 16, 32, 37, 74, 148, 296, 592 |
∑(divisors(1210)) = 1184 | div(1210) = 1, 2, 5, 10, 11, 22, 55, 110, 121, 242, 605 |
2.2.12 Exercise 12: Prime Factorization (★★★✩✩)
Any natural number greater than 1 can be represented as a multiplication of primes. Remember the fact that 2 is also a prime. Write function calc_prime_factors(value) that returns a list of prime numbers whose multiplication yields the desired number.
Examples
Input | Prime factors | Result |
---|---|---|
8 | 2 * 2 * 2 | [2, 2, 2] |
14 | 2 * 7 | [2, 7] |
42 | 2 * 3 * 7 | [2, 3, 7] |
1155 | 3 * 5 * 7 * 11 | [3, 5, 7, 11] |
2222 | 2 * 11 * 101 | [2, 11, 101] |
2.3 Solutions
2.3.1 Solution 1: Basic Arithmetic (★✩✩✩✩)
Solution 1a: Basic Arithmetic Operations (★✩✩✩✩)
Write function calc(m, n) that multiplies two variables m and n of type int, then divides the product by two, and outputs the remainder with respect to division by 7.
Examples
m | n | m * n | m * n // 2 | Result ((n * m // 2) % 7) |
---|---|---|---|---|
6 | 7 | 42 | 21 | 0 |
5 | 5 | 25 | 12 | 5 |
A reminder: With an integer division, the remainder is truncated. Therefore 25//2 results in the value 12.
Solution 1b: Statistics (★★✩✩✩)
Count as well as sum up the natural numbers that are divisible by 2 or 7 up to a given maximum value (exclusive) and output it to the console. Write function calc_sum_and_count_all_numbers_div_by_2_or_7(max_exclusive). Extend it so that it returns the two values instead of performing the console output.
Examples
Maximum | Divisible by 2 | Divisible by 7 | Result | |
---|---|---|---|---|
Count | Sum | |||
3 | 2 | -/- | 1 | 2 |
8 | 2, 4, 6 | 7 | 4 | 19 |
15 | 2, 4, 6, 8, 10, 12, 14 | 7, 14 | 8 | 63 |
What remains is the desire to return the two values. With Python, this is an easy task since tuples are applicable for this, for example, with return (sum, count) or the even shorter return sum, count.
Please note that there is a minor inconvenience in the two code samples: the shadowing of the built-in function sum() by the local variable named sum. Of course, it is easily possible to use sum_ as a variable name. But due to the small scope, I prefer to stick to the more readable but shadowing name sum. This should never cause a real problem.
If your functions grow and get more complex, please avoid shadowing to prevent bugs.
Blank lines sometimes cause problems when processed in the Python command line interpreter. In IDEs like PyCharm, on the other hand, this is possible without problems. I will use empty lines for the examples if this means clearer source code.
Solution 1c: Even or Odd Number (★✩✩✩✩)
Create functions is_even(n) and is_odd(n) that will check if the passed integer is even or odd, respectively.
Verification
2.3.2 Solution 2: Number as Text (★★✩✩✩)
Write function number_as_text(n) which, for a given positive number, converts the respective digits into corresponding text.
Examples
Input | Result |
---|---|
7 | “SEVEN” |
42 | “FOUR TWO” |
24680 | “TWO FOUR SIX EIGHT ZERO” |
13579 | “ONE THREE FIVE SEVEN NINE” |
Verification
2.3.3 Solution 3: Perfect Numbers (★★✩✩✩)
By definition, a natural number is called a perfect number if its value is equal to the sum of its real divisors. This is true, for example, for the numbers 6 and 28:
1 + 2 + 3 = 6
1 + 2 + 4 + 7 + 14 = 28
Write function calc_perfect_numbers(max_exclusive) that calculates the perfect numbers up to a maximum value, say 10,000.
Examples
Input | Result |
---|---|
1000 | [6, 28, 496] |
10000 | [6, 28, 496, 8128] |
Verification
Implementation Optimization
Conveniently, there is a built-in functionality in Python that sums the elements of a list. This is the function sum(), which you use here.
2.3.4 Solution 4: Prime Numbers (★★✩✩✩)
Write function calc_primes_up_to(max_value) to compute all prime numbers up to a given value. As a reminder, a prime number is a natural number greater than 1 and exclusively divisible by itself and by 1. To compute a prime number, the so-called Sieve of Eratosthenes was described before.
Examples
Input | Result |
---|---|
15 | [2, 3, 5, 7, 11, 13] |
25 | [2, 3, 5, 7, 11, 13, 17, 19, 23] |
50 | [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47] |
Algorithm The algorithm follows the Sieve of Eratosthenes. At first, a list of booleans is created and initialized with True since all numbers are considered potential prime numbers. Mentally, this is analogous to initially writing down the numbers 2, 3, 4, ... up to a given maximum value:
2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
Now, starting at the value 2, the “sieving” is started. Because the number 2 is not crossed out, it is included in the list of prime numbers. Afterwards every multiple of it is crossed out, because they can’t be prime numbers:
Iteratively you look for the next not-eliminated number. In this case, it is 3, which is the second prime number. Once again, all multiples of this number are eliminated:
Verification
2.3.5 Solution 5: Prime Number Pairs (★★✩✩✩)
Compute all pairs of prime numbers with a distance of 2 (twin), 4 (cousin), and 6 (sexy) up to an upper bound for n. For twins then the following is true:
Is_Prime(n) && is_Prime(n + 2)
Examples
Type | Result |
---|---|
Twin | {3: 5, 5: 7, 11: 13, 17: 19, 29: 31, 41: 43} |
Cousin | {3: 7, 7: 11, 13: 17, 19: 23, 37: 41, 43: 47} |
Sexy | {5: 11, 7: 13, 11: 17, 13: 19, 17: 23, 23: 29, 31: 37, 37: 43, 41: 47, 47: 53} |
- 1.
Every time all prime numbers are computed again up to the given maximum value. This can be optimized by performing the computation only once and caching the results appropriately.
- 2.
At the moment, the checks are still all interwoven. It is clearer to use a validation function that checks only one condition and returns only one result.
Optimization of the Implementation
Computing the prime numbers is performed once at the beginning of the function. Thus you achieve a significant performance improvement.
This conversion also lays the foundation to be able to test the whole thing with unit tests.
Verification
2.3.6 Solution 6: Checksum (★★✩✩✩)
Examples
Digits | Sum | Result |
---|---|---|
“11111” | 1 + 2 + 3 + 4 + 5 = 15 | 15 % 10 = 5 |
“87654321” | 8 + 14 + 18 + 20 + 20 + 18 + 14 + 8 = 120 | 120 % 10 = 0 |
Verification
2.3.7 Solution 7: Roman Numbers (★★★★✩)
Solution 7a: Roman Numbers ➤ Decimal Numbers (★★★✩✩)
Write function from_roman_number(roman_number) that computes the corresponding decimal number from a textually valid Roman number .5
Examples
Arabic | Roman |
---|---|
17 | “XVII” |
444 | “CDXLIV” |
1971 | “MCMLXXI” |
2020 | “MMXX” |
Algorithm You must pay particular attention to the addition rule described in section 2.1.1: The relevant value is normally obtained by adding the individual digits’ values from left to right whenever a larger character precedes a smaller one. However, if a smaller number character precedes a larger one, the corresponding value is subtracted.
In the code, I use a nicer variant of the traversal. Using the standard functionality reversed(), you get an iterator that traverses the data in the opposite direction and provides access to the respective element. Shown in the comment is index-based processing, which is a little less Python-like (Pythonic).
Solution 7b: Decimal Numbers ➤ Roman Numbers (★★★★✩)
Write function to_roman_number(value) that converts a decimal number to a (valid) Roman number.
However, this quickly becomes confusing.
Using this enhanced lookup dictionary solves the problem and you get correct answers.
Verification
Without the extraction of the values into a list of tuples, there would have been a duplication of the specifications. Only when specifying expected and roman_number, you have to be a bit careful because this is a bidirectional mapping.
2.3.8 Solution 8: Combinatorics (★★✩✩✩)
Solution 8a: Computation of a2 + b2 = c2
For squaring, simple multiplication provides better readability than the use of pow() or of the operator ** implied in the comment.
Bonus: Reduce the Running Time of O(n3) to O(n2) (★★★✩✩)
Verification
As a result, the decimal digits are truncated. This, in turn, leads to the comparison being successful only for certain values.
Solution 8b: Computation of a2 + b2 = c2 + d2
Please note that both variants are not optimal in respect to performance. The next task is to improve this.
Bonus: Reduce the Running Time of O(n 4) to O(n 3) (★★★✩✩)
Verification
2.3.9 Solution 9: Armstrong Numbers (★★✩✩✩)
Write function calc_armstrong_numbers() to compute all Armstrong numbers for x, y, and z (each < 10).
Examples
Although you could also use the value 0, this is unusual. In the first place, a value assignment with x = 0 and y = 0 would correspond to the value z. However, there is another reason not to start with 0. A leading 0 is used to mark octal numbers, so we will not use it here. By the way, since Python 3.8, octal numbers start with the prefix 0o.
Verification
Bonus (★★★✩✩)
Verification
2.3.10 Solution 10: Max Change Calculator (★★★★✩)
Suppose you have a collection of coins or numbers of different values. Write function calc_max_possible_change(values) that determines, for positive integers, what amounts can be seamlessly generated with it starting from the value 1. The maximum value should be returned as a result.
Examples
Input | Possible values | Maximum |
---|---|---|
1 | 1 | 1 |
1, 1 | 1, 2 | 2 |
1, 5 | 1 | 1 |
1, 2, 4 | 1, 2, 3, 4, 5, 6, 7 | 7 |
1, 2, 3, 7 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 | 13 |
1, 1, 1, 1, 5, 10, 20, 50 | 1, 2, 3, 4, 5, 6, ... , 30, ... , 39 | 39 |
Input | Possible values | Maximum |
---|---|---|
1, 2, 3, 7 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 | 13 |
1, 2, 3, 8 | 1, 2, 3, 4, 5, 6, => _ <= , 8, 9, 10, 11, 12, 13, 14 | 6 |
If you take a look at the two examples, you may recognize for the cases 1, 2, 3, 7 and 1, 2, 3, 8 the clue to simplify the calculation decisively. Instead of always calculating all permutations and then checking for a gap in the number line, here indicated by an underscore (_), it is possible to start at the first number, always add the numbers to the previous sum, and repeat this iteratively until next_number > sum + 1 becomes true.
Verification
2.3.11 Solution 11: Related Numbers (★★✩✩✩)
Two numbers n1 and n2 are called friends (or related) if the sum of their divisors is equal to the other number:
sum(divisors(n1)) = n2
sum(divisors(n2)) = n1
Write method function calc_friends(max_exclusive) to compute all friends numbers up to a passed maximum value.
Examples
Input | Divisors |
---|---|
∑(divisors(220)) = 284 | div(220) = 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110 |
∑(divisors(284)) = 220 | div(284) = 1, 2, 4, 71, 142 |
∑(divisors(1184)) = 1210 | div(1184) = 1, 2, 4, 8, 16, 32, 37, 74, 148, 296, 592 |
∑(divisors(1210)) = 1184 | div(1210) = 1, 2, 5, 10, 11, 22, 55, 110, 121, 242, 605 |
For the implementation, you also use the function find_proper_divisors() to find all real divisors. This was already presented in the introduction. Once again, it shows the advantage of subdividing software into smaller, self-contained functionalities.
Verification
For some numbers I use the notation of separating the digits with an underscore, which is an excellent way to simulate a thousand point. This is especially helpful with larger numbers and serves here only for demonstration.
2.3.12 Solution 12: Prime Factorization (★★★✩✩)
Any natural number greater than 1 can be represented as a multiplication of primes. Remember the fact that 2 is also a prime. Write function calc_prime_factors(value) that returns a list of prime numbers whose multiplication yields the desired number.
Examples
Input | Prime factors | Result |
---|---|---|
8 | 2 * 2 * 2 | [2, 2, 2] |
14 | 2 * 7 | [2, 7] |
42 | 2 * 3 * 7 | [2, 3, 7] |
1155 | 3 * 5 * 7 * 11 | [3, 5, 7, 11] |
2222 | 2 * 11 * 101 | [2, 11, 101] |
Verification
2.4 Summary: What You Learned
This chapter on basic mathematical knowledge introduces the modulo operator, which is quite essential, for example, for the extraction of digits and in the calculation of checksums. The exercises on combinatorics have shown how small tricks can easily reduce the running time by an order of magnitude. Also, prime numbers offer some interesting facets, such as variants to their calculation. In retrospect, this turns out to be much easier than perhaps first thought. In general, when trying to find a solution for a problem, the algorithm and the approach should be roughly understood because then, for example, even the the decomposition into prime factors loses its possible horror.
Now let’s move on to recursion as an important technique to break down a more complex task into several simpler subtasks.