KGC_TEST/KGC/miracl/source/cardano.cpp

178 lines
2.9 KiB
C++

/* Solving cubic x^3+AX+B using Cardano's formula */
/* cl /O2 /GX cardona.cpp zzn2.cpp zzn.cpp big.cpp miracl.lib */
#include <iostream>
#include <ctime>
#include "zzn2.h"
using namespace std;
Miracl precision(50,0);
//
// Shanks method modified to find cube roots
//
ZZn2 shanks(ZZn2 n)
{
int i,s;
Big q,p=get_modulus();
ZZn2 t,W,R,V;
BOOL inv;
if (pow(n,(p*p-1)/3)!=1)
{
// cout << "Not a cubic residue" << endl;
return (ZZn2)0;
}
W=randn2();
while (pow(W,(p*p-1)/3)==1) W=randn2();
s=0;
q=p*p-1;
while (q%3==0)
{
q/=3;
s++;
}
if ((q+1)%3==0)
{
R=pow(n,(q+1)/3);
inv=FALSE;
}
else
{
R=pow(n,(q-1)/3);
inv=TRUE;
}
V=pow(W,q);
forever
{
if (!inv) t=(R*R*R)/n;
else t=(R*R*R)*n;
for (i=0;;i++ )
{
if (t==1) break;
t=t*t*t;
}
if (i==0)
{
if (!inv) return R;
else return (ZZn2)1/R;
}
R=R*pow(V,pow((Big)3,s-i-1));
}
}
int main(int argc, char *argv[])
{
int i,j,lt,gt;
Big p;
ZZn x,A,B,D;
ZZn2 r,r3,r1,r2,CD,cu;
time_t seed;
time(&seed);
irand((long)seed);
//
// Generate a random prime, (not 1 mod 8)
//
cout << "Generate a random prime and a random cubic, and try to solve it!" << endl;
cout << "Solutions might be Complex" << endl << endl;
p=rand(80,2);
while (p%8==1 || !prime(p)) p+=1;
cout << "p= " << p << endl;
cout << "p%24= " << p%24 << endl;
modulo(p);
// Find a cube root of unity
do
{
cu=pow((ZZn2)randn2(),(p*p-1)/3);
} while(cu==1);
// cout << "cube root of unity= " << cu << endl;
A=(ZZn)rand(p);
B=(ZZn)rand(p);
// Generate random parameters
cout << "Finding a root of x^3+AX+B mod p, where" << endl;
cout << "A= " << A << endl;
cout << "B= " << B << endl;
// Cardona's formula
D=(B*B)/4 + (A*A*A)/27;
CD=sqrt((ZZn2)D); // Solution may be "complex"
r1=(ZZn2)-B/2+CD; r2=(ZZn2)-B/2-CD;
r1=shanks(r1); // cube roots
r2=shanks(r2);
if (r1==0 || r2==0)
{
cout << "No roots exist" << endl;
return 0;
}
// search for "right" r2
if (r1*r2!=-A/3)
r2*=cu;
if (r1*r2!=-A/3)
r2*=cu;
r=r1+r2;
cout << "root 1= " << r << endl;
if (r*r*r+A*r+B!=0) cout << "Check failed" << endl;
// try next value for r1
r1*=cu;
if (r1*r2!=-A/3)
r2*=cu;
if (r1*r2!=-A/3)
r2*=cu;
r=r1+r2;
cout << "root 2= " << r << endl;
if (r*r*r+A*r+B!=0) cout << "Check failed" << endl;
r1*=cu;
if (r1*r2!=-A/3)
r2*=cu;
if (r1*r2!=-A/3)
r2*=cu;
r=r1+r2;
cout << "root 3= " << r << endl;
if (r*r*r+A*r+B!=0) cout << "Check failed" << endl;
return 0;
}