c语言 - 线性全等生成器的浮点异常(核心转储)



我正在完成基于线性同余生成器(LCG)的密码程序的头文件。它接收两个无符号长整型值(m 和 c),并使用这些值生成 LCG 结构。在我的getA()中,我试图让它将temp变量添加到uPrimes数组中(以防它不能减少到1,因此可以在计算p时将其包含在内),但是我不断收到错误:"浮点异常(核心转储)"。它将运行到完成,但如果我不尝试这样做,它不会按需要执行。在最新的迭代中,我尝试将 uPrimes 数组的第一个值分配为 1,一旦 while 循环完成,它将 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: %dn", 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 %dn", 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("%sn", msg);
for(i = 0; i < n; ++i)
{
unsigned long x = getNextRandomValue(lcg);
printf("%lun", 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;
}

至少这个问题,primes[15]不存在。 15primes[0] ... primes[15-1]确实存在。

然后,代码可能尝试%0导致"浮点异常(核心转储)"。 由于各种原因,整数div 乘以 0 或余数报告为 FP 错误。

unsigned long primes[15] = { ... }
while(y < 16) {
if(temp % primes[y] == 0)

建议while(y < 15) {

清理后(删除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: %lun", m, uPrimes[q - 1]);
} else
temp = temp / primes[y];
} else
y++;
}
uPrimes[0] = temp;
printf("q = %lun", q);
for (z = 0; z < q; z++) {
p = p * uPrimes[z];
printf("P for %lu is %lun", m, p);
}
if (m % 4 == 0) {
a = 1 + (2 * p);
} else {
a = 1 + p;
}
printf("getA(m): m = %lu, a = %lun", 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("%sn", msg);
for (i = 0; i < n; ++i) {
unsigned long x = getNextRandomValue(lcg);
printf("%lun", 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中的所有值设置为零的第二个分支。

最新更新