SPL Programming - 3.2 [Doing loop] Multilayer loop

 

Just as if… else may be found in the code block of if and else, there can be for again in the loop body of for, which we call multi-layer loop.

Narcissus number refers to such a three-digit number,the sum of the cube of each digit is equal to the number itself. Now we want to calculate all Narcissus numbers between 100 and 999.

A B C D E
1 for 9 =100*A1 =A1*A1*A1
2 for 0,9 =B1+10*B2 =C1+B2*B2*B2
3 for 0,9 =C2+C3 =D2+C3*C3*C3
4 if D3==E3 >output(D3)

We haven’t learned the concept of set yet, and can’t save all the Narcissus numbers found in one set. So in cell E5, we use the output() function to output the Narcissus numbers, which can be seen in the lower right corner.

A new grammatical form for 0,9 appears in B2 and C3. Usually, the statement for n means that the loop variable will change from 1 to n, but sometimes we want to change the start and end values. We can also write the loop statement as for a,b, which means that the loop variable will change from a to b, where a and b are integers. If b>a, the value of loop variable will be a,a+1,…,b, b-a+1 times in total; if b<a, the value of loop variable will be a,a-1,…,b, a-b+1 times in total.

Cell A1,B2,C3 respectively loops through each digit of the three-digit number. This is code for three-tier loop. The outermost layer A1 loops through the hundreds digit, the middle layer B2 loops through the tens digit, and the innermost layer C3 loops through units digit. Because there are 10 possibilities for tens digit and unis digit from 0 to 9, if it is written as for 10, it needs to subtract 1 in the later operation, which is troublesome, so it is easy to write it as for 0,9 directly.

In multi-layer loop, the complete inner loop will be executed every time the outer loop body is executed. In this way, A1 will loop 9 times and B1 will be executed 9 times; B2 itself will loop 10 times, and C2, as a statement in the loop body of B2, will be executed 9*10=90 times; D3 and E3, as statements in the body of C3, will be executed 9*10*10=900 times.

The three-digit number and the sum of cubes of each digit are calculated by D3 and E3 respectively. The calculation of B1,C1 and C2,D2 is to try to make the calculation amount smaller. When the number of units digit changes in a cycle, the number of hundreds and tens is temporarily unchanged, so it is unnecessary to repeat the calculation for the hundreds and tens every time. This is also a matter of attention when coding. The execution times of inner loop body statements may be very many, and a little less computation will reduce the total calculation amount, thus greatly improving the performance of the program.

Now you can execute the program by yourself, and check the output at the bottom right to see which Narcissus numbers are calculated.

By the way, we use multiplication when we calculate cubic here, and we also used multiplication to calculate square when we talked about quadratic equation before, why not use power() function directly?

Actually, power()can be used when calculating square before, but it can’t be used here. Because power() is calculated by exponent and logarithm, it will return a floating-point number. But it needs to be compared accurately here, and it is not reliable to use floating-point numbers. So we’d rather multiply it three times. Also because of this, we should write for 0,9 instead of for 10, otherwise it is a bit troublesome to write multiplying B2-1 three times.

We did not use power() to calculate square before, on the one hand, it is not difficult to write self multiplication twice, on the other hand, it will be much slower to calculate with exponent and logarithm, so it is also written as self multiplication.

These are also details that you need pay attention to when programming.

This code can also be optimized. If the sum of cubes of each digit is larger than the three-digit number, it is unnecessary to loop the units digit any more. Because when the hundreds and tens are unchanged, when the number of units digit is looped to the next, i.e. added by 1, this cube sum will increase by at least 1 (increase by 1 only when the units digit changes to 1 from 0, and other changes are greater than 1), and the three-digit number itself will only increase by 1. Then, the gap between the three-digit number and the cube sum cannot be smaller (generally the bigger it will be) and they cannot be equal.

That is, once we find D3<E3, C3’s loop is unnecessary to continue. It is impossible to find a Narcissus number under the condition that A1 and B2 are unchanged. It is only a waste of time and calculation.

Most programming languages, including SPL, provide break statement to abort the current loop, and the code is rewritten as follows:

A B C D E
1 for 9 =100*A1 =A1*A1*A1
2 for 0,9 =B1+10*B2 =C1+B2*B2*B2
3 for 0,9 =C2+C3 =D2+C3*C3*C3
4 if D3==E3 >output(D3)
5 else if D3<E3 break

This code has one more line, but the computing performance is much better than before.

In fact, the analysis of single digit just now holds true for tens digit, because the cube of numbers 0-9 must not be less than itself. If C2<D2, then there must be D3<E3. At this time, there is no need to do the third level loop.

The code can be further optimized:

A B C D E F
1 for 9 =100*A1 =A1*A1*A1
2 for 0,9 =B1+10*B2 =C1+B2*B2*B2 if C2<D2 break
3 for 0,9 =C2+C3 =D2+C3*C3*C3
4 if D3==E3 >output(D3)
5 else if D3<E3 break

The above analysis can be extended to the hundreds digit, but it doesn’t make any sense. Please think about the reason here. The optimization of this code is basically over now.