2012-06-28 9 views
6

Estoy tratando de implementar la prueba de primalidad Miller-Rabin de acuerdo con la descripción en FIPS 186-3 C.3.1. No importa lo que haga, no puedo hacer que funcione. Las instrucciones son bastante específicas, y no creo que me haya perdido nada, y sin embargo estoy obteniendo true para valores no primos.Miller-Rabin Prueba de primalidad Implementación FIPS 186-3

¿Qué hice mal?

template <typename R, typename S, typename T> 
T POW(R base, S exponent, const T mod){ 
    T result = 1; 
    while (exponent){ 
     if (exponent & 1) 
      result = (result * base) % mod; 
     exponent >>= 1; 
     base = (base * base) % mod; 
    } 
    return result; 
} 



// used uint64_t to prevent overflow, but only testing with small numbers for now 
bool MillerRabin_FIPS186(uint64_t w, unsigned int iterations = 50){ 
    srand(time(0)); 
    unsigned int a = 0; 
    uint64_t W = w - 1; // dont want to keep calculating w - 1 
    uint64_t m = W; 
    while (!(m & 1)){ 
     m >>= 1; 
     a++; 
    } 

    // skipped getting wlen 
    // when i had this function using my custom arbitrary precision integer class, 
    // and could get len(w), getting it and using it in an actual RBG 
    // made no difference 

    for(unsigned int i = 0; i < iterations; i++){ 
     uint64_t b = (rand() % (W - 3)) + 2; // 2 <= b <= w - 2 
     uint64_t z = POW(b, m, w); 
     if ((z == 1) || (z == W)) 
      continue; 
     else 
      for(unsigned int j = 1; j < a; j++){ 
       z = POW(z, 2, w); 
       if (z == W) 
        continue; 
       if (z == 1) 
        return 0;// Composite 
      } 
    } 
    return 1;// Probably Prime 
} 

esto:

std::cout << MillerRabin_FIPS186(33) << std::endl; 
std::cout << MillerRabin_FIPS186(35) << std::endl; 
std::cout << MillerRabin_FIPS186(37) << std::endl; 
std::cout << MillerRabin_FIPS186(39) << std::endl; 
std::cout << MillerRabin_FIPS186(45) << std::endl; 
std::cout << MillerRabin_FIPS186(49) << std::endl; 

me está dando:

0 
1 
1 
1 
0 
1 
+0

¿Cómo se implementa 'POW()'? – sarnold

+0

¿Podemos ver 'POW'? Veo un error que podría declarar algunos primos como compuestos, pero nada salta al revés. ¿Para qué valores obtienes resultados incorrectos? –

+0

¿Dónde está tu definición de PRISIONERO DE GUERRA? – Antimony

Respuesta

5

La única diferencia entre su aplicación y de Wikipedia es que se le olvidó la segunda instrucción compuesta de retorno. Deberías tener un retorno 0 al final del ciclo.

Editar: Como señaló Daniel, hay una segunda diferencia. El continuar continúa el bucle interno, en lugar del bucle externo como se supone que debe hacerlo.

for(unsigned int i = 0; i < iterations; i++){ 
    uint64_t b = (rand() % (W - 3)) + 2; // 2 <= b <= w - 2 
    uint64_t z = POW(b, m, w); 
    if ((z == 1) || (z == W)) 
     continue; 
    else{ 
     int continueOuter = 0; 
     for(unsigned int j = 1; j < a; j++){ 
      z = POW(z, 2, w); 
      if (z == W) 
       continueOuter = 1; 
       break; 
      if (z == 1) 
       return 0;// Composite 
     } 
     if (continueOuter) {continue;} 
    } 
    return 0; //This is the line you're missing. 
} 
return 1;// Probably Prime 

También, si la entrada es par, que será siempre vuelven probablemente primer puesto a es 0. Usted debe agregar una comprobación adicional en el inicio para eso.

+3

Se espera que una prueba de primalidad no se use en números pares. :) – sarnold

+0

Oh, vamos, esto ciertamente no merece un _downvote _... es un buen punto. :) – sarnold

+0

¿Por qué el voto a favor? Es un problema legítimo y no tenía idea de qué números se estaban probando en el momento en que escribí eso. – Antimony

4

En el bucle interno,

 for(unsigned int j = 1; j < a; j++){ 
      z = POW(z, 2, w); 
      if (z == W) 
       continue; 
      if (z == 1) 
       return 0;// Composite 
     } 

que debiera break; en lugar de continue; cuando z == W. Por continue ing, en la siguiente iteración de ese ciclo, si hay uno, z se convertirá en 1 y posiblemente el candidato sea declarado erróneamente como compuesto. Aquí, eso ocurre para 17, 41, 73, 89 y 97 entre los números primos menores que 100.

+0

http: // ideone.com/xoDHx – calccrypto

+1

Aargh, justo cuando estaba a punto de pulsar enviar, también. Creo que tanto esto como el retorno 0 si este ciclo lo hace, son necesarios. – DSM

+0

Wow, no puedo creer que me haya perdido eso. El continuar solo continúa el ciclo interno, no el ciclo externo como debería. – Antimony

Cuestiones relacionadas