我正在用c实现一个非常简单的计算机代数系统。我的程序在一段时间后崩溃时遇到了一些问题。
这个想法是有一个像 3^(21+8^(3^100)) + 4 这样的表达式,并看到它等于 2 mod 7。我已经用 java 编写了程序,并试图将它移植到 c。
我就是这样做的:我有一个名为 expr 的结构。它可以是二进制表达式或原子 int
struct expr
{
struct expr* a;
struct expr* b;
char op;
int value;
};
typedef struct expr expr;
expr* new_expr(int i)
{
expr* e = malloc(sizeof(expr));
e->op='i';
e->value = i;
return e;
}
expr* new_expr2(expr* a, expr* b, char op)
{
expr* e = malloc(sizeof(expr));
e->a=a;
e->b=b;
e->op=op;
e->value = 0;
return e;
}
void free_expr(expr* e)
{
free_expr(e->a);
free_expr(e->b);
free(e);
}
/* ... other methods ... */
我怀疑(其中一个)问题是我没有在 gcd 函数中释放内存。这就是我编写 gcd 函数的方式。
expr* gcd(expr* a, expr* b)
{
expr* t = b;
while(!equals(b, zero))
{
t=b;
b=mod(a, b);
a=t;
}
return a;
}
这在java中很好用,但我不确定它是否在c中有效,因为它没有自动垃圾收集。当函数是递归的时,我不确定如何构造它。所以我想我的问题是,我应该把 free_expr 函数放在哪里?mod(a, b) 分配一个新的 expr 结构,因此它最终会创建很多永远不会被释放的 expr。我怀疑这可能是它崩溃的原因。构建这个的正确方法是什么?还是我做错了?
由于代码可维护性,我宁愿在 struct expr 中进行计算,而不是在 int 中进行计算。
谢谢你的帮助。
[编辑] 这是我的模组功能
expr* mod(expr* number, expr* modulo)
{
expr* result;
if(number->op=='i')
{
if(modulo->op=='i')
{
int i = (number->value)%(modulo->value);
while(i<0)
{
i=i+(modulo->value);
}
return new_expr(i);
}
}
switch(number->op)
{
case '+':
result = new_expr(mod(number->a,modulo)->value+mod(number->b,modulo)->value);
break;
case '-':
result = new_expr(mod(number->a,modulo)->value-mod(number->b,modulo)->value);
break;
case '*':
result = new_expr(mod(number->a,modulo)->value*mod(number->b,modulo)->value);
break;
case '/':
result = new_expr(mod(number->a,modulo)->value/mod(number->b,modulo)->value);
break;
case '^':
result = modexpEuler(number->a,number->b, modulo);
break;
}
(result->value)%=(modulo->value);
return result;
}
expr* modexpEuler(expr* a, expr* b, expr* n)
{
if(!(a->op=='i')||!(n->op=='i'))
{
printf("wrong input ");
exit(0);
}
if(equals(b, one))
{
return mod(a,n);
}
if(equals(b, zero))
{
if(b->op=='^'){
printf("adf %d\n",b->a->value);
printf("asdf %d\n", b->b->value);
}else{
printf("asdf %c\n", b->op);
printf("asdf %d\n", b->value);
printf("asdf %d\n", a->value);
printf("asdf %d\n", a->b->value);
}
return copy_expr(zero);
}
if(equals(mod(a, n), zero))
{
return copy_expr(zero);
}
if(b->op == 'i')
{
return expmod(a, b, n);
}
if(equals(gcd(a,n), one))
{
expr* tempA = mod(a, n);
expr* tempB = mod(b, phi(n));
printf("trying to use euler\n");
printf("%d\n",a->value);
printf("%d\n",b->value);
return modexpEuler(tempA, tempB, n);
}
else
{
printf("gcd not 1 ");
exit(0);
}
}
phi(n) 计算欧拉函数。
[编辑 2] 这是我的平等
int equals(expr* a, expr* b)
{
if((a->op)!=(b->op))
{
return 0;
}
if((a->op)=='i')
{
return (a->value)==(b->value);
}else{
return equals(a->a,b->a)&&equals(a->b,b->b);
}
}