⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 roots.c

📁 calc大数库
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "roots.h"
#include "integer.h"
#include <stdio.h>
#include <stdlib.h>
#include "fun.h"
#include "stack.h"

/* This code was written by Sean Seefried when he was a vacation student
 * with me at UQ Maths. Dept.
 */
/* Simple linked list implementation of polynomial sequence */
typedef struct _PolySeq {
  POLYI poly;
  struct _PolySeq *next;
} *PolySeq;

/* 
 * Adds a POLYI to the end of a PolySeq.  If supplied PolySeq is NULL then a 
 *  new PolySeq is created.
 */
PolySeq addPolySeqTerm(PolySeq ps, POLYI P)
{
  PolySeq CURSOR=ps;
  if (ps == NULL) {
    if ((ps=mmalloc(sizeof (struct _PolySeq))) == NULL)
      return NULL;
    else {
      ps->poly=COPYPI(P);
      ps->next=NULL;
    }
  } else {
    while (CURSOR->next) 
      CURSOR=CURSOR->next; 
    /* CURSOR now points to last term */
    CURSOR->next=mmalloc(sizeof (struct _PolySeq));
    CURSOR->next->poly=COPYPI(P);
    CURSOR->next->next=NULL;
  }
  return ps;
}

/* 
 * Frees a polynomial sequence previously created with createPolySeq 
 */
void freePolySeq(PolySeq ps)
{
  PolySeq CURSOR=ps;
  PolySeq prev;
  while(CURSOR) {
    prev=CURSOR;
    DELETEPI(CURSOR->poly);
    CURSOR=CURSOR->next;
    ffree(prev, sizeof (struct _PolySeq)); 
  }
}
void printPolySeq(PolySeq ps) 
{
  PolySeq CURSOR=ps;
  printf("{");
  if (ps) {
    PRINTPI(CURSOR->poly);
    while (CURSOR->next) {
      printf(", ");
      CURSOR=CURSOR->next;
      PRINTPI(CURSOR->poly);
    }
  }
  printf("}\n");
}

void printPolySeqEval(PolySeq ps, MPR *R) 
{
  PolySeq CURSOR=ps;
  int i;
  printf("{");
  if (ps) {
    i = SIGN_AT_R_PI(CURSOR->poly, R);
    printf("%d", i);
    while (CURSOR->next) {
      printf(", ");
      CURSOR=CURSOR->next;
      i = SIGN_AT_R_PI(CURSOR->poly, R);
      printf("%d", i);
    }
  }
  printf("}\n");
}
/*
 * Returns the number of sign variations in the Polynomial Sequence at the 
 * evualated at the supplied value.
 * A sign variation exists between two non-zero numbers c[p] and c[q] (p<q)
 * of a finite or infinite sequence of numbers, c[1], c[2], c[3],... if the
 * following hold:
 * i. for q = p + 1, c[p] and c[q] have opposite signs.
 * ii. for q >= p +2, the numbers c[p+1], ..., c[q-1] are all zero and c[p]
 * and c[q] have opposite signs.
 */


int signVar(PolySeq PS, MPR *R) 
{
  int prev=SIGN_AT_R_PI(PS->poly, R);
  /* previous polynomial in sequence's value at I */
  int vars=0; /* number of variations */
  MPR *Z=ZEROR();
  int sign;
  PolySeq CURSOR=PS;
  while (CURSOR) {
    /* skip polynomials that evaluate to zero */
    sign = SIGN_AT_R_PI(CURSOR->poly, R);
    while (sign == 0 && CURSOR->next) {
      CURSOR=CURSOR->next;
      sign = SIGN_AT_R_PI(CURSOR->poly, R);
    }
    if (prev != 0 && (prev*sign < 0))
      vars++;
    prev=sign;
    CURSOR=CURSOR->next;
  }
  FREEMPR(Z);
  return vars;
}

/* 
 * Returns a polynomial sequence that is the sturm sequence of the supplied 
 * polynomial.  See Akritas, Elements of Computer Algebra, p341 
 */ 
PolySeq sturmSeq(POLYI Pptr)
{
  POLYI R1=COPYPI(Pptr);
  POLYI R2=DERIVPI(R1);
  POLYI TR, R; /* temp remainder, remainder, modified remainder */
  MPI *CONT;
  PolySeq ps=NULL;
  
  ps = addPolySeqTerm(ps, R1);
  /* It is possible that Pptr was a constant polynomial. Hence its derivative
   * is zero or NULL.  The Sturm sequence should consists of one term - Pptr.
   */
  if (R2 != NULL) 
    ps = addPolySeqTerm(ps, R2);
  else {
    DELETEPI(R1);
    return ps;
  }
  while ((DEGREEPI(TR=MODPI(R1,R2)) != 0) && TR != NULL) {
    CONT=CONTENTPI2(TR);
    if (SIGNI(CONT) > 0) {
      POLYI TMPI;
      R = PRIMITIVEPI(TR);
      DELETEPI(TR); /* free TR. not needed */

      TMPI = R;
      R = MINUSPI(R);
      DELETEPI(TMPI);
    } else {
      R = PRIMITIVEPI(TR);
      DELETEPI(TR);
    }
    ps = addPolySeqTerm(ps, R);
    TR=R1;
    R1=R2;
    R2=R;
    DELETEPI(TR); /* deletes R1 */
    FREEMPI(CONT);
  }

  if (TR != NULL) { /* can guarantee that this is a constant polynomial */
    MPI *TMP;
    POLYI ONE_P=ONEPI();
    TMP = LEADPI(TR);
    if (SIGNI(TMP) > 0) {
      POLYI NEGONE_P;
      MPI *CONST=MINUS_ONEI();
      NEGONE_P=CONSTANTPI(CONST);
      addPolySeqTerm(ps, NEGONE_P);
      DELETEPI(NEGONE_P);
      FREEMPI(CONST);
    } else {
      addPolySeqTerm(ps, ONE_P);
    }
    DELETEPI(ONE_P);
    FREEMPI(TMP);
  }
  DELETEPI(TR);
  DELETEPI(R1);
  DELETEPI(R2);
  return ps;
}

/*
 * Calculates an upperbound on the positve roots of the supplied polynomial
 * using Cauchy's Rule. See Akritas, Elements of Computer Algebra.
 */
MPR *CAUCHY(POLYI P)
{
  POLYI Q=COPYPI(P);
  POLYI CURSOR;
  MPR *RETVAL=NULL;
  MPI *LEAD;
  MPR *TWO=TWOR();
  int t, deg=DEGREEPI(P);
  /* t a flag, deg is degree of polynomial */
  int  k, k_, k__, lambda=0, i, j, p, q, r;
  MPI *CI_=NULL;
  MPR *CN_=NULL;
  
  /* if the leading coefficient is less than zero then multiply polynomial by
   * -1 */

  LEAD=LEADPI(Q);
  if (SIGNI(LEAD) < 0) {
    MPI *NEGONE=MINUS_ONEI();
    POLYI TMPI;
    TMPI=Q;
    Q=SCALARPI(NEGONE, Q);
    DELETEPI(TMPI); 
    FREEMPI(NEGONE);
  }
  CURSOR=Q;
  while (CURSOR){ 
    if (SIGNI(CURSOR->COEF) < 0) /* count negative terms in poly */
      lambda++;
    CURSOR=CURSOR->NEXT;
  }

  k__ = 0 ; 
  j = BINARYB(LEAD)-1; /* j = log base 2 of LEAD */
  t = 0;
  if (!(lambda==0 || deg==0)) {
    CURSOR=Q;
    while (CURSOR) {
      if (SIGNI(CURSOR->COEF) < 0) {
	k=Q->DEG - CURSOR->DEG;
	CI_ = MULT_I(CURSOR->COEF, -lambda);
	i = BINARYB(CI_)-1; /* i = log base 2 of CI_ */
	p=i-j-1;
	q=p/k;
	r=p-k*q;
	if (r < 0) {
	  r+=k;
	  q--;
	}
	k_ = q + 1;

	if (r == (k-1)) {
	  MPR *TMPR;
	  MPR *POW;
	  POW=POWERR_2(TWO, k*k_);
	  TMPR=MPI_TO_MPR(Q->COEF);
	  CN_ = MULTR(TMPR, POW);
	  FREEMPR(POW);
	  FREEMPR(TMPR);
	  TMPR=MPI_TO_MPR(CI_);
	  if (COMPARER(TMPR, CN_) > 0) {
	    k_ = k_ + 1;
	    } 
	  FREEMPR(CN_);
	  FREEMPR(TMPR); 
	}
	if (t==0 || k_ > k__) {
	  k__ = k_;
	  t = 1;
	}
	FREEMPI(CI_); 
      }
      CURSOR=CURSOR->NEXT;
    }
  }
  RETVAL = POWERR_2(TWO, k__);
  
  FREEMPR(TWO);
  FREEMPI(LEAD);
  DELETEPI(Q);
  return RETVAL;
  
}


/* Returns a newly created Interval if possible.  
 * Returns NULL on error.
 */
Interval createInterval(MPR* left, MPR *right) 
{
  Interval intvl;
  if (!(intvl = malloc (sizeof (struct _Interval))))
    return NULL;
  intvl->left = COPYR(left);
  intvl->right = COPYR(right);
  return intvl;
}
/*-------------------------------------------------------------------*/
/* Frees an interval previously created with createInterval 
 * Undefined behaviour occurs if 'intvl' does not point to a structure of 
 * this type. */
void freeInterval(Interval intvl) 
{
  FREEMPR(intvl->left);
  FREEMPR(intvl->right);
  free(intvl);
}
/*-------------------------------------------------------------------*/

/* Returns a stack of intervals that contain only one root each respectively 
 * of the supplied polynomial.  If there are no roots, it returns an empty
 * stack */
Stack STURM(POLYI P)
{
  
  Stack Bounds=stackNew();
  Stack Results=stackNew();
  PolySeq sseq; /* sturm sequence */
  MPI *ZI, *V;
  MPR *BR, *ZERO=ZEROR(), *TWO = TWOR();
  unsigned debugCounter=0;
  unsigned numRoots, pn_flag=0;
  
  /* must find square free version of polynomial or else 
   * we cannot use the theorm of Sturm.  This is done simply by dividing 
   * the supplied polynomial by the gcd of it and it's derivative */
  POLYI D=DERIVPI(P);
  POLYI G=GCDPI(P,D);
  POLYI Pw=DIVPI(P, G);
  DELETEPI(D);
  DELETEPI(G);

  /* if there is a zero at zero then divide polynomial by X */
  ZI = ZEROI();
  V = VALPI(Pw, ZI);
  if (COMPAREI(V, ZI) == 0) {
    MPI *ONE=ONEI();
    POLYI X=NULL, TMPI;
    PINSERTPI(1, ONE, &X, 0);
    TMPI = Pw;
    Pw = DIVPI(Pw, X);
    DELETEPI(TMPI);
    DELETEPI(X);
    FREEMPI(ONE); 
  }
    FREEMPI(V);
    FREEMPI(ZI); 
  
    while (pn_flag < 2) {
      POLYI TMPPOLY;
      sseq = sturmSeq(Pw);

      BR = CAUCHY(Pw); 
      stackPush(Bounds, createInterval(ZERO, BR));
      FREEMPR(BR);
      /* main loop */
      
      while (!stackEmpty(Bounds) && debugCounter < 20) {
	Interval intvl;
	intvl = stackPop(Bounds);
	numRoots = signVar(sseq, intvl->left) - signVar(sseq, intvl->right);
	debugCounter++;
	/* DEBUG INFO */

	/*	printf("The number of roots in the interval (");
	 PRINTR(intvl->left);
	 printf(", ");
	 PRINTR(intvl->right);
	 printf(") is %d\n", numRoots);     
	 printPolySeqEval(sseq, intvl->left);
	 printPolySeqEval(sseq, intvl->right);         */
	 /* DEBUG END */

	 if (numRoots == 1) {
	   
	   MPR *L, *R;
	   L = intvl->left;
	   R = intvl->right;
	   if (pn_flag == 1) {
	     MPR *TMPR;
	     TMPR = MINUSR(L); /* swap left and right of interval because  
				* they are now negative values */
	     L = MINUSR(R);
	     R = TMPR; 
	}
	   stackPush(Results, createInterval(L, R));
	   if (pn_flag == 1) {
	     FREEMPR(L);
	     FREEMPR(R);
	   } 
	 }
	 else if (numRoots > 1) { /* numroots > 1 */
	   MPR *T, *CENTRE;
	   T = ADDR(intvl->left,intvl->right);
	   CENTRE = RATIOR(T,TWO);
	   FREEMPR(T);  /* New intervals are (L, (L+R)/2) and ((L+R)/2, R) */
	   stackPush(Bounds, createInterval(intvl->left, CENTRE));
	   stackPush(Bounds, createInterval(CENTRE, intvl->right));
	   
	/* debug code */
	   /*	   printf("This interval has been subdivided into: (");
		   PRINTR(intvl->left);
	     printf(", ");
	     PRINTR(CENTRE);
	     printf(") , (");
	     PRINTR(CENTRE);
	     printf(", ");
	     PRINTR(intvl->right);
	     printf(")\n");    */
	   /* debug code end */
	   FREEMPR(CENTRE); 
	 }
	 freeInterval(intvl); 
      }
      TMPPOLY=Pw;
      Pw=P_OF_NEG_X(Pw);
      DELETEPI(TMPPOLY);   
      freePolySeq(sseq);
      pn_flag++;
    }
    stackFree(&Bounds);

    FREEMPR(ZERO);
    FREEMPR(TWO);
    DELETEPI(Pw);
    return Results;
}
/*-------------------------------------------------------------------*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -