First point to be considered: 10^9
it is possible to be represented with 32 bits (in real, 32 bits reaches up to approximately 4 billion), so the upper limit of the input (which is 10^8
) it is possible to be represented in a signed long int
in C. As far as I can remember, the most modern compilers understand the int
as being 32 bits and flagged. So we don’t need to do big gymnastics with the representation. C also accepts simply putting long
for that guy.
Then, what is the maximum limit for finding the prime? Well, since the number is composed by the sum of squares, it means that any number greater than 10^4
will generate a larger square than 10^8
. Therefore, the maximum limit is 10^4
: if you’ve reached that limit, I can cancel the search for new prime numbers.
I can’t use functions, but I can start sketching with them and then do the process of "opening" them within the code. This helps to organize ideas, but it is not strictly necessary to do so.
What would the code look like then? The idea is to always seek from the beginning (the p1
, p2
, p3
and p4
initials presented in your code). If you reach the maximum number (with the largest prime going to something other than 10^4
), the search failed. If the sum of the primes is greater than the number shown, the search also failed. If the sum falls below the number sought, then we dispense with the lesser of the cousins (p1
), rotate the other 3 a less significant "position" and on top of the new p3
, We’re looking for the "next cousin".
In general, it would be something like this (I won’t consider yet the optimization of the sum to be greater than the past number):
'''
Retornamos o próximo primo ou -1 caso não seja possível definir o próximo primo,
se ele for além do limite máximo
'''
def proximo_primo(p4_old):
# considere inteiro
next = p4_old + 2
while next < 10000:
divisor = 3
while divisor*divisor < next and next % divisor != 0:
divisor += 2
if next % divisor != 0:
return next
next += 2
return -1
def is_soma_quadrado(n):
# considere como inteiros
p1 = 2
p2 = 3
p3 = 5
p4 = 7
# enquanto o próximo primo é válido, continua tentando...
while p4 != -1:
if p1*p1 + p2*p2 + p3*p3 + p4*p4 == n:
return (p1, p2, p3, p4)
# não deu como soma destes primos consecutivos
# vamos rodar os números e tentar o próximo primo
p1, p2, p3 = p2, p3, p4
p4 = proximo_primo(p4)
# retorno para que não é possível fazer essa soma
return (-1, -1, -1, -1)
The primality test is given by the following:
divisor = 3
while divisor*divisor < next and next % divisor != 0:
divisor += 2
if next % divisor != 0:
return next
Here, next
already starts with a value known not to be prime, since the possible values of its arguments are prime and do not receive 2 as argument, never. Besides, the next one next
always is the previous value +2, so it is impossible that next
be even. Therefore, I don’t need to test the division by 2, which is why I start with 3
. Jump the candidate dividers of 2 in 2 to decrease the amount of tests required, since every division with some even number will have 1 as rest.
I have two conditions of stops: the first is if the divisor candidate really has distinct rest of zero (next % divisor == 0
), or if it has burst useful divisor candidates (divisor * divisor < next
). This second part is more or less equivalent to the question whether divisor < sqrt(next)
, but the multiplication of integers is usually lighter than the calculation of the square root. I also avoid considering equality because, if by chance divisor * divisor == next
, So you’re on to the next stop: next % divisor == 0
will return false.
After the loop is completed, I do the checking to see if the reason for the stop was that they ran out of useful candidates to split or if really the number next
is composed. Why it has the if next % divisor != 0
in the end: if true, then next
is really a prime number.
This is the general scheme. For the loop, we would do something like the following:
def laco_leitura():
while True:
n = proxima_leitura()
# aqui, -1 significa fim da leitura
if n == -1:
return
p = is_soma_quadrado(n)
if p[0] != -1:
print('É a soma de alguns primos')
else:
print('impossível representar')
For starters, still in this kind of style python code, we will remove returns, break
, and functions. Gradually.
First, let’s unroll proximo_primo
to stop the ties without using return
(if I actually unfold its content within is_soma_quadrado
, the return
act as break
, then does not achieve the desired result). I will make a grotesque exchange in the external condition: put a ret == -1
on condition of continuation and instead of using a return
, I’ll make an assignment ret = next
. This will cause the loop to end and, in case the loop stops for breaking the maximum limit, ret
will have the boot value that will be smart -1
:
'''
Retornamos o próximo primo ou -1 caso não seja possível definir o próximo primo,
se ele for além do limite máximo
'''
def proximo_primo(p4_old):
# considere inteiro
ret = -1
next = p4_old + 2
while next < 10000 and ret == -1:
divisor = 3
while divisor*divisor < next and next % divisor != 0:
divisor += 2
if next % divisor != 0:
ret = next
next += 2
return ret
Now, let’s unroll that function within is_soma_quadrado
? To do so, remembering here that in C (even in ANSI), you can declare variable at the beginning of block code, so I will use this in our favor. To that end, I will be assigning p4
only in the last step, when return ret
is called. The fact that the name of the variables does not offer conflict makes it easier to deal with it. Since the value of the variable passed as parameter is read-only, I can put directly p4
where in the Code p4_old
:
def is_soma_quadrado(n):
# considere como inteiros
p1 = 2
p2 = 3
p3 = 5
p4 = 7
# enquanto o próximo primo é válido, continua tentando...
while p4 != -1:
if p1*p1 + p2*p2 + p3*p3 + p4*p4 == n:
return (p1, p2, p3, p4)
# não deu como soma destes primos consecutivos
# vamos rodar os números e tentar o próximo primo
p1, p2, p3 = p2, p3, p4
# fazendo aqui o desenrolar da função proximo_primo
# começo do bloco equivalente à chamada a proximo_primo
# considere inteiro
ret = -1
next = p4 + 2
while next < 10000 and ret == -1:
divisor = 3
while divisor*divisor < next and next % divisor != 0:
divisor += 2
if next % divisor != 0:
ret = next
next += 2
p4 = ret
# fim do bloco equivalente à chamada a proximo_primo
# retorno para que não é possível fazer essa soma
return (-1, -1, -1, -1)
Now, unwind the return
premature. I will use a strategy similar to the previous one, but here the default value will be p = (-1, -1, -1, -1)
and the condition to continue in the loop is that p[0] == -1
. I’ll also put in the else
the case where the number is not the sum of the current primes:
def is_soma_quadrado(n):
p = (-1, -1, -1, -1)
# considere como inteiros
p1 = 2
p2 = 3
p3 = 5
p4 = 7
# enquanto o próximo primo é válido, continua tentando...
while p[0] == -1 and p4 != -1:
if p1*p1 + p2*p2 + p3*p3 + p4*p4 == n:
p = (p1, p2, p3, p4)
# não deu como soma destes primos consecutivos
# vamos rodar os números e tentar o próximo primo
else:
p1, p2, p3 = p2, p3, p4
# fazendo aqui o desenrolar da função proximo_primo
# começo do bloco equivalente à chamada a proximo_primo
# considere inteiro
ret = -1
next = p4 + 2
while next < 10000 and ret == -1:
divisor = 3
while divisor*divisor < next and next % divisor != 0:
divisor += 2
if next % divisor != 0:
ret = next
next += 2
p4 = ret
# fim do bloco equivalente à chamada a proximo_primo
# retorno para que não é possível fazer essa soma
return p
To unwind this function in the read loop is even easier: almost just copy and paste directly. The only difference here is that, instead of using a traditional return, I will directly populate the variable p
(I will also take advantage and exchange the infinite loop for one that is finitely known:
def laco_leitura():
devemos_continuar = True
while devemos_continuar:
n = proxima_leitura()
# aqui, -1 significa fim da leitura
if n == -1:
devemos_continuar = false
else:
# bloco que determina se o número é soma dos quadrados de 4 primos consecutivos
p = (-1, -1, -1, -1)
# considere como inteiros
p1 = 2
p2 = 3
p3 = 5
p4 = 7
# enquanto o próximo primo é válido, continua tentando...
while p[0] == -1 and p4 != -1:
if p1*p1 + p2*p2 + p3*p3 + p4*p4 == n:
p = (p1, p2, p3, p4)
# não deu como soma destes primos consecutivos
# vamos rodar os números e tentar o próximo primo
else:
p1, p2, p3 = p2, p3, p4
# fazendo aqui o desenrolar da função proximo_primo
# começo do bloco equivalente à chamada a proximo_primo
# considere inteiro
ret = -1
next = p4 + 2
while next < 10000 and ret == -1:
divisor = 3
while divisor*divisor < next and next % divisor != 0:
divisor += 2
if next % divisor != 0:
ret = next
next += 2
p4 = ret
# fim do bloco equivalente à chamada a proximo_primo
# fim do bloco que determina se o número é soma dos quadrados de 4 primos consecutivos
if p[0] != -1:
print('É a soma de alguns primos')
else:
print('impossível representar')
Now I could totally eliminate the variable p
, but I don’t think that will be necessary. Transposing to c, the first thing I would do is change the while
stemming from proximo_primo
for a for
classic:
- begins with
divisor = 3
- the condition is
divisor*divisor < next && next % divisor != 0
- the increment is
divisor += 2
Thus, the loop body remains basically empty. I need to take care not to lose the reference to divisor
and go out of scope. Soon, divisor
would need to be declared out of of the boot block for
. Besides, I still have challenges with 2 points:
- get rid of the tuple
p
- treat reading
As it stands in the question
The sequence only works for the first input, and then simply deletes
I am here assuming that several entries are provided for the same execution. So, how do I know you have finished reading? The pattern in most of the questions I usually see is to have a stop entry, but that’s not described here. Has either corner that the end of the input is indicated by the EOF
of stdin
, and so I will treat here.
For this, the reading continues to be using scanf("%d", &n)
, but I’ll guard the exit from scanf
. According to the documentation (Okay, I know it’s C++, but at this particular point C++ was designed to be fully compatible part), if you couldn’t read anything, a EOF
as output. So just check if returned EOF
or continue happy processing. I will do this as mischievously as possible: create a variable to indicate that you have reached EOF
starting with truth, update it with the output of the scanf
and check both in the loop and before doing any computation (in practice simulating a break
of an infinite loop), its value:
int devemos_continuar = 1;
long n;
while (devemos_continuar) {
devemos_continuar = scanf("%ld", &n) != EOF;
if (devemos_continuar ) {
...
}
}
This is how we treat reading. All that remains is to get rid of p
. To get rid of her, I’m gonna use p1, p2, p3, p4
to serve as "bearers" of the values of the tuple positions. Thus, I need to take care to, when it is the case to give a return of something bad, treat it correctly:
int devemos_continuar = 1;
long n;
while (devemos_continuar) {
devemos_continuar = scanf("%ld", &n) != EOF;
if (devemos_continuar) {
// grossamente equivalente ao "p = (-1, -1, -1, -1)"
long prim1 = -1, prim2 = -1, prim3 = -1, prim4 = -1;
{
// bloco que determina se o número é soma dos quadrados de 4 primos consecutivos
long p1 = 2, p2 = 3, p3 = 5, p4 = 7;
// enquanto o próximo primo é válido, continua tentando...
while (prim1 == -1 && p4 != -1) {
if (p1*p1 + p2*p2 + p3*p3 + p4*p4 == n) {
// grossamente equivalente ao "p = (p1, p2, p3, p4)"
prim1 = p1;
prim2 = p2;
prim3 = p3;
prim4 = p4;
} else {
// não deu como soma destes primos consecutivos
// vamos rodar os números e tentar o próximo primo
p1 = p2;
p2 = p3;
p3 = p4;
// fazendo aqui o desenrolar da função proximo_primo
// começo do bloco equivalente à chamada a proximo_primo
{
long ret = -1;
long next = p4 + 2;
while (next < 10000 && ret == -1) {
long divisor;
for (divisor = 3; divisor*divisor < next && next % divisor != 0; divisor += 2);
if (next % divisor != 0) {
ret = next;
}
next += 2;
}
p4 = ret
}
}
}
}
if (prim1 != -1) {
printf("É a soma de alguns primos\n");
} else {
printf("impossível representar\n");
}
}
}
We can improve performance in case of negatives: prevent you from trying to continue calculating when the sum is greater than the past number. So where do we have
...
while (prim1 == -1 && p4 != -1) {
if (p1*p1 + p2*p2 + p3*p3 + p4*p4 == n) {
...
we will put the sum less than or equal to the number passed at the beginning of the loop, and only updating it at the end of the while
:
long soma = p1*p1 + p2*p2 + p3*p3 + p4*p4;
...
while (prim1 == -1 && p4 != -1 && soma <= n) {
if (soma == n) {
...
}
// ... acha o novo p4 e chega no final do while ...
soma = p1*p1 + p2*p2 + p3*p3 + p4*p4;
}
...
See working on Ideone.
To fit the output formatting, we just need to print using the values of prim1
, prim2
, prim3
and prim4
. Follow below full code:
#include <stdio.h>
int main() {
int devemos_continuar = 1;
long n;
while (devemos_continuar) {
devemos_continuar = scanf("%ld", &n) != EOF;
if (devemos_continuar) {
// grossamente equivalente ao "p = (-1, -1, -1, -1)"
long prim1 = -1, prim2 = -1, prim3 = -1, prim4 = -1;
{
// bloco que determina se o número é soma dos quadrados de 4 primos consecutivos
long p1 = 2, p2 = 3, p3 = 5, p4 = 7;
long soma = p1*p1 + p2*p2 + p3*p3 + p4*p4;
// enquanto o próximo primo é válido, continua tentando...
while (prim1 == -1 && p4 != -1 && soma <= n) {
if (soma == n) {
// grossamente equivalente ao "p = (p1, p2, p3, p4)"
prim1 = p1;
prim2 = p2;
prim3 = p3;
prim4 = p4;
} else {
// não deu como soma destes primos consecutivos
// vamos rodar os números e tentar o próximo primo
p1 = p2;
p2 = p3;
p3 = p4;
// fazendo aqui o desenrolar da função proximo_primo
// começo do bloco equivalente à chamada a proximo_primo
{
long ret = -1;
long next = p4 + 2;
while (next < 10000 && ret == -1) {
long divisor;
for (divisor = 3; divisor*divisor < next && next % divisor != 0; divisor += 2);
if (next % divisor != 0) {
ret = next;
}
next += 2;
}
p4 = ret;
}
}
soma = p1*p1 + p2*p2 + p3*p3 + p4*p4;
}
}
if (prim1 != -1) {
printf("%ldˆ2 + %ldˆ2 + %ldˆ2 + %ldˆ2\n", prim1, prim2, prim3, prim4);
} else {
printf("Impossivel a representacao\n");
}
}
}
return 0;
}
Already answered in: https://answall.com/questions/441099/verifi-se-n%C3%bamero-%C3%A9-equals-%C3%A0-sum-of-the-squares-of-4%C3%bameros-primes-consecutive/441126
– anonimo
@anonimo I saw this code, however, as I am still starting in C, it is difficult to understand what the person did in python
– Marcelly
Can’t use functions neither break nor vectors? Dude, it’s gonna be really slow and boring, but you can do it...
– Jefferson Quesado