Исключение с плавающей точкой (ядро сброшено) для линейного конгруэнтного генератора - PullRequest
0 голосов
/ 30 апреля 2020

Я заканчиваю свой заголовочный файл для программы шифрования на основе линейного конгруэнтного генератора (LCG). Он получает два беззнаковых длинных значения (m и c) и генерирует структуру LCG, используя эти значения. В моем getA () я пытаюсь добавить временную переменную в массив uPrimes (если ее нельзя уменьшить до 1, поэтому ее можно включить при вычислении p), но я продолжаю получать сообщение об ошибке: «Исключение с плавающей запятой (ядро сброшено) ". Он будет работать до конца, но не будет работать так, как нужно, если я не попытаюсь это сделать. В этой последней итерации я попытался присвоить первому значению массива uPrimes значение 1, и как только l oop завершает его, он присваивает значение temp первому значению с тем же результатом. Любая помощь будет принята с благодарностью! (Я заранее прошу прощения за несоответствующие объявления переменных, я беспорядочно играл с типами данных, чтобы попытаться решить проблему)

/* Header guard prevents errors if header is included twice */
#ifndef LCG_H
#define LCG_H
#include <stdlib.h>

struct LinearCongruentialGenerator
{
  unsigned long m; /* modulus */
  unsigned long c; /* increment */
  unsigned long a; /* multiplier */
  unsigned long x; /* value in sequence */
};

/***************************************************************/
/* Initialize an LCG with modulus m and increment c.           */
/* Calculate multiplier a such that:                           */
/*        a = 1+2p, if 4 is a factor of m, otherwise, a = 1+p. */
/*        p = (product of m’s unique prime factors).           */
/*        a < m                                                */
/* Seed value x is same as increment c.                        */
/* If values are invalid for LCG, set all fields to zero.      */
/***************************************************************/
struct LinearCongruentialGenerator makeLCG(unsigned long m, unsigned long c);

/* Update lcg and return next value in the sequence. */
unsigned long getNextRandomValue(struct LinearCongruentialGenerator* lcg);

unsigned long getA(unsigned long m);

int checkInput(unsigned long m, unsigned long c);

struct LinearCongruentialGenerator makeLCG(unsigned long m, unsigned long c)
{
  struct LinearCongruentialGenerator lcg;
  if(checkInput(m,c) && (getA(m)<m && getA(m)>0))
  {  
    lcg.m = m;
    lcg.c = c;
    lcg.a = getA(m);
    lcg.x = c;
  } else
  {
    lcg.m = 0; lcg.c = 0;
    lcg.a = 0; lcg.x = 0;
  }
  return lcg;
}

unsigned long getNextRandomValue(struct LinearCongruentialGenerator* lcg)
{
  lcg->x = ((lcg->a*lcg->x)+lcg->c)%lcg->m;
  return lcg->x;
}

unsigned long getA(unsigned long m)
{
  unsigned long primes[15] = {2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
  int uPrimes[63];
  unsigned long temp = m; int y = 0; int p = 1;
  int prev; int z; unsigned long a; int q = 1;
  uPrimes[0] = 1;
  while(y < 16)
  {
    if(temp % primes[y] == 0)
    {
      if(primes[y] != prev)
      {
        uPrimes[q] = primes[y];
        prev = primes[y];
        q++; y++;
        printf("Unique Prime for %lu is: %d\n", m, uPrimes[q-1]);
      } else temp = temp/primes[y];
    } else y++;
  }
  uPrimes[0] = temp;
  for(z = 0; z < q; z++)
  {
    p = p * uPrimes[z];
    printf("P for %lu is %d\n", m, p);
  }
  if(m % 4 == 0){a = 1+(2*p);}
  else a = 1+p;
  if(a < m && a > 0){return a;}
  else return 0;
}

int checkInput(unsigned long m, unsigned long c)
{
  int x = 2;
  if(c > m || c <= 0){return 0;}
  else 
  {
    while(x < c)
    {
      if(m % x == 0 && c % x == 0)
      {return 0;}
      else x++;
    }
    return 1;
  }
}
#endif


Это тестовый файл, который мне дали для проверки моего заголовочный файл работает как нужно:

#include <stdio.h>
#include "lcg.h"

/* Print LCG values along with a message */
void printLCG(struct LinearCongruentialGenerator* lcg, char* msg)
{
  printf("%s (m=%lu,a=%lu,c=%lu,x=%lu)\n", msg, lcg->m, lcg->a, lcg->c, lcg->x);
}

/* Print message and n values generated by the LCG */
void testValues(struct LinearCongruentialGenerator* lcg, char* msg, int n)
{
  int i;
  printf("%s\n", msg);

  for(i = 0; i < n; ++i)
  {
    unsigned long x = getNextRandomValue(lcg);
    printf("%lu\n", x);
  }
}

/* Create and test a few LCGs */
int main()
{
  struct LinearCongruentialGenerator lcg1 = makeLCG(126,25);
  struct LinearCongruentialGenerator lcg2 = makeLCG(38875,1234);
  struct LinearCongruentialGenerator lcg3 = makeLCG(4611686018427387904,961168601842738797);

  /* Some error cases */
  struct LinearCongruentialGenerator lcg4 = makeLCG(4,3);
  struct LinearCongruentialGenerator lcg5 = makeLCG(0,5);
  struct LinearCongruentialGenerator lcg6 = makeLCG(5,0);


  printLCG(&lcg1, "initialized lcg1");
  printLCG(&lcg2, "initialized lcg2");
  printLCG(&lcg3, "initialized lcg3");

  printLCG(&lcg4, "initialized error test lcg4");
  printLCG(&lcg5, "initialized error test lcg5");
  printLCG(&lcg6, "initialized error test lcg6");

  testValues(&lcg1, "test lcg1", 10);
  testValues(&lcg2, "test lcg2", 10);
  testValues(&lcg3, "test lcg3", 10);

  printLCG(&lcg1, "lcg1 after first test");
  printLCG(&lcg2, "lcg2 after first test");
  printLCG(&lcg3, "lcg3 after first test");

  testValues(&lcg1, "test lcg1 again", 20);

  printLCG(&lcg1, "lcg1 after second test");

  return 0;
}


Ответы [ 2 ]

0 голосов
/ 30 апреля 2020

После очистки (удалив все предупреждения, сделанные clang -Weverything), исправив отключенное, найденное @chux, и добавив немного больше трекинга, я получил это

#include <stdlib.h>
#include <stdio.h>

struct LinearCongruentialGenerator {
  unsigned long m;              /* modulus */
  unsigned long c;              /* increment */
  unsigned long a;              /* multiplier */
  unsigned long x;              /* value in sequence */
};

/***************************************************************/
/* Initialize an LCG with modulus m and increment c.           */
/* Calculate multiplier a such that:                           */
/*        a = 1+2p, if 4 is a factor of m, otherwise, a = 1+p. */
/*        p = (product of m’s unique prime factors).           */
/*        a < m                                                */
/* Seed value x is same as increment c.                        */
/* If values are invalid for LCG, set all fields to zero.      */
/***************************************************************/
struct LinearCongruentialGenerator makeLCG(unsigned long m, unsigned long c);

/* Update lcg and return next value in the sequence. */
unsigned long getNextRandomValue(struct LinearCongruentialGenerator *lcg);

unsigned long getA(unsigned long m);

int checkInput(unsigned long m, unsigned long c);

void printLCG(struct LinearCongruentialGenerator *lcg, char *msg);

void testValues(struct LinearCongruentialGenerator *lcg, char *msg, int n);

struct LinearCongruentialGenerator makeLCG(unsigned long m, unsigned long c)
{
  struct LinearCongruentialGenerator lcg;
  if (checkInput(m, c) && (getA(m) < m && getA(m) > 0)) {
    lcg.m = m;
    lcg.c = c;
    lcg.a = getA(m);
    lcg.x = c;
  } else {
    lcg.m = 0;
    lcg.c = 0;
    lcg.a = 0;
    lcg.x = 0;
  }
  return lcg;
}

unsigned long getNextRandomValue(struct LinearCongruentialGenerator *lcg)
{
  lcg->x = lcg->a * lcg->x;
  lcg->x = lcg->x + lcg->c;
  lcg->x = lcg->x % lcg->m;
  return lcg->x;
}

unsigned long getA(unsigned long m)
{
  unsigned long primes[15] =
      { 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47 };
  unsigned long uPrimes[63];
  unsigned long temp = m;
  unsigned long y = 0;
  unsigned long p = 1;
  unsigned long prev = 0;
  unsigned long z;
  unsigned long a;
  unsigned long q = 1;
  uPrimes[0] = 1;
  while (y < 15) {
    if (temp % primes[y] == 0) {
      if (primes[y] != prev) {
        uPrimes[q] = primes[y];
        prev = primes[y];
        q++;
        y++;
        printf("Unique Prime for %lu is: %lu\n", m, uPrimes[q - 1]);
      } else
        temp = temp / primes[y];
    } else
      y++;
  }
  uPrimes[0] = temp;
  printf("q = %lu\n", q);
  for (z = 0; z < q; z++) {
    p = p * uPrimes[z];
    printf("P for %lu is %lu\n", m, p);
  }
  if (m % 4 == 0) {
    a = 1 + (2 * p);
  } else {
    a = 1 + p;
  }
  printf("getA(m): m = %lu, a = %lu\n", m, a);
  if (a < m && a > 0) {
    return a;
  } else {
    return 0;
  }
}

int checkInput(unsigned long m, unsigned long c)
{
  unsigned long x = 2;
  printf("checkInput(m = %lu, c = %lu)\n", m, c);
  if (c > m || c <= 0) {
    return 0;
  } else {
    while (x < c) {
      if (m % x == 0 && c % x == 0) {
        return 0;
      } else
        x++;
    }
    return 1;
  }
}

/* Print LCG values along with a message */
void printLCG(struct LinearCongruentialGenerator *lcg, char *msg)
{
  printf("%s (m=%lu,a=%lu,c=%lu,x=%lu)\n", msg, lcg->m, lcg->a, lcg->c, lcg->x);
}

/* Print message and n values generated by the LCG */
void testValues(struct LinearCongruentialGenerator *lcg, char *msg, int n)
{
  int i;
  printf("%s\n", msg);

  for (i = 0; i < n; ++i) {
    unsigned long x = getNextRandomValue(lcg);
    printf("%lu\n", x);
  }
}

/* Create and test a few LCGs */
int main(void)
{
  puts("makeLCG(126,25)");
  struct LinearCongruentialGenerator lcg1 = makeLCG(126, 25);
  puts("makeLCG(38875,1234)");
  struct LinearCongruentialGenerator lcg2 = makeLCG(38875, 1234);
  //puts("makeLCG(4611686018427387904,961168601842738797)");
  //struct LinearCongruentialGenerator lcg3 = makeLCG(4611686018427387904,961168601842738797);

  /* Some error cases */
  struct LinearCongruentialGenerator lcg4 = makeLCG(4, 3);
  struct LinearCongruentialGenerator lcg5 = makeLCG(0, 5);
  struct LinearCongruentialGenerator lcg6 = makeLCG(5, 0);


  printLCG(&lcg1, "initialized lcg1");
  printLCG(&lcg2, "initialized lcg2");
  //printLCG(&lcg3, "initialized lcg3");

  printLCG(&lcg4, "initialized error test lcg4");
  printLCG(&lcg5, "initialized error test lcg5");
  printLCG(&lcg6, "initialized error test lcg6");

  testValues(&lcg1, "test lcg1", 10);
  testValues(&lcg2, "test lcg2", 10);
  //testValues(&lcg3, "test lcg3", 10);

  printLCG(&lcg1, "lcg1 after first test");
  printLCG(&lcg2, "lcg2 after first test");
  //printLCG(&lcg3, "lcg3 after first test");

  testValues(&lcg1, "test lcg1 again", 20);

  printLCG(&lcg1, "lcg1 after second test");

  return 0;
}

Компиляция с clang -g3 -O3 -Weverything -std=c11 lcg.c -o lcg и запуск его в отладчике (gdb) дает (здесь!):

makeLCG(126,25)
checkInput(m = 126, c = 25)
Unique Prime for 126 is: 2
Unique Prime for 126 is: 3
Unique Prime for 126 is: 7
q = 4
P for 126 is 126
P for 126 is 252
P for 126 is 756
P for 126 is 5292
getA(m): m = 126, a = 5293
Unique Prime for 126 is: 2
Unique Prime for 126 is: 3
Unique Prime for 126 is: 7
q = 4
P for 126 is 126
P for 126 is 252
P for 126 is 756
P for 126 is 5292
getA(m): m = 126, a = 5293
makeLCG(38875,1234)
checkInput(m = 38875, c = 1234)
Unique Prime for 38875 is: 5
q = 2
P for 38875 is 38875
P for 38875 is 194375
getA(m): m = 38875, a = 194376
Unique Prime for 38875 is: 5
q = 2
P for 38875 is 38875
P for 38875 is 194375
getA(m): m = 38875, a = 194376
checkInput(m = 4, c = 3)
Unique Prime for 4 is: 2
q = 2
P for 4 is 4
P for 4 is 8
getA(m): m = 4, a = 17
Unique Prime for 4 is: 2
q = 2
P for 4 is 4
P for 4 is 8
getA(m): m = 4, a = 17
checkInput(m = 0, c = 5)
checkInput(m = 5, c = 0)
initialized lcg1 (m=0,a=0,c=0,x=0)
initialized lcg2 (m=0,a=0,c=0,x=0)
initialized error test lcg4 (m=0,a=0,c=0,x=0)
initialized error test lcg5 (m=0,a=0,c=0,x=0)
initialized error test lcg6 (m=0,a=0,c=0,x=0)
test lcg1

Program received signal SIGFPE, Arithmetic exception.
0x0000000000400b1b in getNextRandomValue (lcg=<optimized out>) at lcg.c:54
54    lcg->x = lcg->x % lcg->m;

Деление на ноль, потому что getA(m) всегда возвращает ноль, потому что вычисленное значение в a всегда больше, чем m и этот ноль от getA() заставляет makeLCG() вызывать вторую ветвь, которая устанавливает все значения в struct на ноль.

0 голосов
/ 30 апреля 2020

По крайней мере, этой проблемы, primes[15] не существует. 15 primes[0] ... primes[15-1] существует.

Код, возможно, попытался %0, что привело к «Исключению с плавающей запятой (ядро сброшено)». По различным причинам целочисленное деление на 0 или остаток сообщает об ошибке FP.

 unsigned long primes[15] = { ... }

 while(y < 16) {
   if(temp % primes[y] == 0)

Suggest while(y < 15) {

...