Introduction
When Carl Friedrich Gauss was a little boy his teacher asked the class to sum up all numbers from 1 to 100. Immediately he came up with the answer. How did he do this? We will find out.
- Objectives: vector operations, functions, and how Gauss learned to calculate numbers from 1 to 100
- Requirements: none
Intuitive Solution
Today everybody using R can solve this immediately. You need to create a vector from 1 to 100 and calculate the sum. The vector can be created by creating a sequence with seq. As parameters from and to are defined. Implicitely step size from one number to the next is 1. This could be changed with paramter by. In the next step sum is used to calculate the sum of all elements in this vector.
x <- seq(from = 1, to = 100)
sum(x)
## [1] 5050
This is the intuitive way to solve it, but it is very costly with written addition. So he used a trick.
Gauss’ Solution
He found out that if you sum the first and last number (1 + 100) you have 101. The same for second and second to last value (2 + 98), and so on. You can see a visualisation in the graph. You have an increasing vector with half of all values (red points) and a decreasing vector with the second half of all values (black). Their sum (blue) is always the same.
Let’s try to do the same. We have our vector x with numbers from 1 to 100. Next, we split this vector in a first and second half. With brackets we can access elements of a vector. 1:50 implicitely is a sequence and the same as seq(1, 50). So for the first half we access elements 1 to 50, and for the second half 51 to 100.
x_first_half <- x[1 : 50]
x_first_half
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ## [24] 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 ## [47] 47 48 49 50
x_sec_half <- x[51 : 100]
x_sec_half
## [1] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 ## [18] 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 ## [35] 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
The second half needs decreasing order. Function order is used. Its parameter -x_sec_half refers to decreasing order.
x_sec_half <- x_sec_half[order(-x_sec_half)]
x_sec_half
## [1] 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 ## [18] 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 ## [35] 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51
Now, we add x_first_half and x_sec_half elementwise.
y <- x_first_half + x_sec_half
y
## [1] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 ## [18] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 ## [35] 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101 101
How many elements does y have? Function length can tell us.
length(y)
## [1] 50
So there is 50 times the value 101 – a total of
length(y) * y[1]
## [1] 5050
Extension: Handling of odd Numbers
This code so far only works for even numbers. How to deal with odd numbers, e.g. 1 to 99? An easy solution is to add a Zero at the beginning. Next quest, how can you find out if a number is odd or even. You can use modulo operator %%. If biggest number modulo 2 is zero, it is an even number, otherwise odd. We will use max() function to find maximum number. Then we use ifelse to handle two different cases. If max number mod 2 is 0, then variable x_odd_even is even, otherwise odd.
Attention: ifelse requires a logical value True or False as its first argument. For our comparison it is important to use == instead =. The latter form is used only for assignments, but not for comparisons. This is a very typical source of error.
max_nr <- max(x)
x_odd_even <- ifelse(max_nr %% 2 == 0, "even", "odd")
x_odd_even
## [1] "even"
Hint: You could avoid modulo (%%) if you use function is.odd() or is.even().
At this point we know if max number is odd or even and have to extend x vector by a Zero at the beginning if x is odd, otherwise not.
x <- ifelse(x_odd_even == "odd",
cbind(0, x),
x)
Extension: Writing a Function
This is the right answer, but what about the sum of 1 to 200, or 1 to 400? To answer this you need to see that 101 is the (maximum number+1) and 50 is just maximum number divided by 2. So you end up with the sum formula 1 + 2 + … n = n/2 * (n+1).
We can use this to write a small function. Writing functions is very easy. You need to define a name, here GaussSum. Then you need magic word function and in brackets our parameter n. In this case I defined n=100. This means if you call GaussSum without further parameters, the default parameter n=100 is used. But you are free to define any other number for n. Within curly braces calculation is performed. The result has to be returned from the function to the calling program. This is defined in return.
GaussSum <- function (n = 100) {
gauss <- n/2 * (n+1)
return (gauss)
}
Let’s give it a try and call the function without and with default parameter.
GaussSum()
## [1] 5050
GaussSum(n=100)
## [1] 5050
You see that passing no parameters and passing n=100 has the same result. But any other number works as well.
GaussSum(n=200)
## [1] 20100
Bibliography
More information on Gauss Sum Formula https://betterexplained.com/articles/techniques-for-adding-the-numbers-1-to-100/