Hope you can help me; I have the following code:
#include <iostream>
#include <math.h>
using namespace std;
long int
cifra (long int b, long int e, long int n)
{
/* Calcula a tal que (b^e)=a MOD n. Algoritmo 3.1 de Allenby & Redfern,1989. */
long int a, i, q, r;
a = 1;
q = b / n;
r = b - q * n;
for (i = 1; i <= e; i )
{
a = a * r;
q = a / n;
a = a - q * n; /* ou, de forma equivalente, a=mod(a,n) */
}
return a;
}
int
main ()
{
long int a, b, e, n;
b = 116104101;
e = 19661;
n = 383768051;
a = cifra (b, e, n);
cout << "a=" << a << endl;
return 0;
}
and this should output
a=199324862
as it does when I used the online C Compiler (https://www.onlinegdb.com/online_c _compiler, which uses g ).
However: if I run it on Code::Blocks with MinGW64 (on Windows 10), I get the wrong result:
a=298405922
Any ideas? Am I doing anything wrong?
CodePudding user response:
It seems that you're assuming that long int is a 64-bit (or larger) integer type, but it's actually a 32-bit type in that particular environment. If you need a certain size type you should use something more explicit like int64_t or uint64_t. Also, you might want to use the remainder operator % to avoid the q variable altogether, e.g. r = b % n or just b %= n:
#include <iostream>
#include <cstdint>
int64_t cifra(int64_t b, int64_t e, int64_t n) {
/* Calcula a tal que (b^e)=a MOD n. Algoritmo 3.1 de Allenby & Redfern,1989. */
int64_t a, i;
a = 1;
b %= n;
for (i = 1; i <= e; i ) {
a = (a * b) % n; /* ou, de forma equivalente, a=mod(a,n) */
}
return a;
}
int main() {
int64_t a, b, e, n;
b = 116104101;
e = 19661;
n = 383768051;
a = cifra(b, e, n);
std::cout << "a=" << a << std::endl;
return 0;
}
CodePudding user response:
Overflow
q * n, a * r, q * n risk overflow.
The width of long is at least 32-bit, yet a full range multiplication obliges 2x long width for the product.
Either:
- Use a wider type for intermediate results.
long longwould suffice for OP's test case ofb = 116104101; e = 19661; n = 383768051;
or
- Perform the math more carefully. Example: Modular exponentiation without range restriction.
int64_t cifra(int64_t b, int64_t e, int64_t n) incorrect with some small corner cases. cifra(b, 0, 1) returns 1 when it should return 0.
// a = 1;
a = n ? 1 : 0;
// or
a = !!n;
// or
a = 1%n;
// or ...
