0

I'm finishing up my header file for a Linear Congruential Generator (LCG) based cipher program. It receives two unsigned long values (m and c) and generates the LCG struct using these values. In my getA() I'm trying to have it add the temp variable to the uPrimes array (in case it cannot be reduced to 1, so it can be included when calculating p) but I keep receiving the error: "Floating point exception (core dumped)". It will run to completion, but does not perform as it needs to, if I do not try to do this. In this latest iteration I attempted to assign the first value of the uPrimes array as 1, and once the while loop finishes it assigns the value of temp to the first value, with the same result. Any help would be greatly appreciated! (I apologize ahead of time for the mismatched variable declarations, I was toying around with the data types haphazardly to try and solve the problem)

/* 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


This is the test file I've been given to verify my header file works as needed:

#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;
}


A. Mitchev
  • 21
  • 4
  • Run in a debugger and examine the variables when the exception occurs. Good chance you'll see a value that looks wrong and then you can debug from there. – kaylum Apr 30 '20 at 03:24
  • I'm not gonna lie, I was told this on my last question and I have no idea why I didn't remember it. I guess frustration just got the better of me, but thank you, I try that now. – A. Mitchev Apr 30 '20 at 03:28

2 Answers2

0

At least this problem, primes[15] does not exist. The 15 primes[0] ... primes[15-1] do exist.

Code may have then attempted %0 resulting in "Floating point exception (core dumped)". For various reasons an integer div by 0 or remainder reports as a FP error.

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

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

Suggest while(y < 15) {

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
0

After cleaning up (removing all warnings made by clang -Weverything), repairing the off-by-one found by @chux, and adding a bit more tracking I got this

#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;
}

Compiling with clang -g3 -O3 -Weverything -std=c11 lcg.c -o lcg and running it in the debugger (gdb) gives (here!):

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;

A division by zero because getA(m) returns always zero because the calculated value in a is always bigger than m and that zero from getA() causes makeLCG() to call the second branch that sets all values in the struct to zero.

deamentiaemundi
  • 5,502
  • 2
  • 12
  • 20
  • Thanks a bunch! I was able to figure most of what you pointed out but you highlighted some things I had still missed. – A. Mitchev May 02 '20 at 06:31