parse_term.cc

Go to the documentation of this file.
00001 #include "numbpart.cc" /* for calculation of partition numbers */
00002 
00009 
00010 namespace parse_term
00011 {
00012 
00013 signed short int gZ_priority (const char ch)
00014 {
00015   switch (ch)
00016    {
00017      case '+': case '-': return 1;
00018      case '*': case '/': case ':': case '%': return 2;
00019      case '^': return 3;
00020      default: return 0;
00021    } 
00022 }
00023 
00024 bool gZ_mehrstellig(const char ch)
00025 {
00026   switch (ch)
00027    {
00028      case '+': case '-':
00029      case '*': case '/': case ':': case '%':
00030      case '^':
00031       return true;
00032      default: return false;
00033    } 
00034 }
00035 
00036 bool gZ_einstellig(const char ch)
00037 {
00038   switch (ch)
00039    {
00040      case 'F': case 'L': case 'P':
00041      case 'f': case 'p': case 's':
00042      case 'q': case 'i': case 'd':
00043      case 'r':
00044       /*
00045          F - index of Fibonacci number
00046          L - index of Luscas number
00047          P - index of Partition number
00048          f - evaluates factorial of the given argument
00049          p - evaluates the next greater prime number (if argument isn't prime)
00050          s - evaluates the next greater safeprime (if argument isn't safeprime)
00051          q - tests, whether argument is a prime number. If not: abort program.
00052              (this is useful for some loops in scripts calling this program)
00053          i - increment argument by one
00054          d - decrement argument by one
00055          r - square root (truncated)
00056       */
00057       return true;
00058     default: return false;
00059    }
00060 }
00061 
00062 bool gZ_priority_le (const char a, const char b)
00063 {
00064   return gZ_priority(a)<=gZ_priority(b);
00065 }
00066 
00067 bool gZ_priority_gr (const char a, const char b)
00068 {
00069   return gZ_priority(a)>gZ_priority(b);
00070 }
00071 
00072 bool get_number (mpz_t n, char* &s, const char op='R', const char upto_op='\0')
00073 { 
00074   /*
00075      Evaluate the string (array of chars) to a multiple precision number.
00076      The string will be interpreted as a term consisting of numbers,
00077      numeric expressions, parentheses and operation symbols.
00078   */
00079   
00080   while (s[0]==' ') s++; // read over spaces
00081   
00082   bool term_structure_ok = true;
00083   char* s_anf = s; // starting position of the current subterm
00084   char h;
00085   mpz_t tmp;
00086   mpz_init(tmp);
00087 
00088   if (s[0]=='(')
00089     {
00090       s++; // skip leading parenthesis
00091       term_structure_ok=get_number(tmp,s); // evaluate subterm
00092       if (s[0]==')') s++; // skip trailing parenthesis
00093       else 
00094         {
00095           term_structure_ok=false;
00096           cerr << "error: ')' expected at '" << s << "'" << endl; 
00097         }
00098     }
00099   else if (gZ_einstellig(s[0])) // einstellige Funktionssymbole
00100     {
00101       s++; // skip the function symbol
00102       term_structure_ok=get_number(tmp,s,s_anf[0]); // evaluate term (as an argument)
00103     }
00104   else if (s[0]>='0' && s[0]<='9')
00105     { // get subterm (parentheses need be removed beforehand)
00106       char* anf=s;
00107       while (s[0]>='0' && s[0]<='9') s++;
00108       h=s[0]; s[0]='\0';
00109       if (mpz_set_str(tmp, anf, 10))
00110         {
00111           term_structure_ok=false;
00112           s[0]=h;
00113           cerr << "error: number expected at '" << anf << "'" << endl;
00114         }
00115       s[0]=h;
00116     }
00117   else term_structure_ok=false;
00118 
00119   while (s[0]==' ') s++; // over read spaces
00120   if (s[0]=='*' && s[1]=='*') { s[0]=' '; ++s; s[0]='^'; } // "**" -> '^'
00121   h=s[0]; // next operation symbol
00122 
00123   if (term_structure_ok && !gZ_einstellig(op))
00124    {
00125      if (gZ_priority_gr(h,op) || (h=='^' && op=='^'))
00126       {
00127         // operator with higher priority (or rightwise associative)
00128         // evaluate the right term before the left one... 
00129 #ifdef VERBOSE_WARN
00130         if (op=='^' && h=='^') cout << "Warning: a^b^c ambiguent; using a^(b^c)." << endl;
00131 #endif
00132         term_structure_ok=get_number(tmp,++s,h,op);
00133         if (s[0]=='*' && s[1]=='*') { s[0]=' '; ++s; s[0]='^'; } // "**" -> '^'
00134         h=s[0]; // next operation symbol
00135       }
00136    }
00137   
00138   if (term_structure_ok) switch (op)
00139     {
00140     case '\0':
00141       break;
00142     case 'R' :
00143       //cout << "Reset" << endl;
00144       mpz_set(n,tmp);
00145       break;
00146     case 'F' : // Fibonacci number
00147       {
00148        if (mpz_cmp_ui(tmp,100000)>0)
00149         {
00150          cerr << "fibonacci: argument to big: " << tmp << endl;
00151          exit(1);
00152         }
00153        if (mpz_sgn(tmp)<0)
00154         {
00155          cerr << "fibonacci: argument negative: " << tmp << endl;
00156          exit(1);
00157         }
00158 #ifdef VERBOSE_INFO
00159        cout << "computing fibonacci number" << endl;
00160 #endif
00161        mpz_fib_ui(n,mpz_get_ui(tmp));
00162       }
00163       break;
00164     case 'L' : // Lucas number
00165       {
00166        if (mpz_cmp_ui(tmp,100000)>0)
00167         {
00168          cerr << "lucas: argument too big: " << tmp << endl;
00169          exit(1);
00170         }
00171        if (mpz_sgn(tmp)<0)
00172         {
00173          cerr << "lucas: argument negative: " << tmp << endl;
00174          exit(1);
00175         }
00176 #ifdef VERBOSE_INFO
00177        cout << "computing lucas number" << endl;
00178 #endif
00179        mpz_lucnum_ui(n,mpz_get_ui(tmp));
00180       }
00181       break;
00182     case 'P' : // Partition number
00183       {
00184        if (mpz_cmp_ui(tmp,1000000)>0)
00185         {
00186          cerr << "partition number: argument to big: " << tmp << endl;
00187          exit(1);
00188         }
00189        if (mpz_sgn(tmp)<0)
00190         {
00191          cerr << "partition number: argument negative: " << tmp << endl;
00192          exit(1);
00193         }
00194 #ifdef VERBOSE_INFO
00195        cout << "computing partition number" << endl;
00196 #endif
00197        numbpart::numbpart(n,mpz_get_ui(tmp));
00198       }
00199       break;
00200     case 'f' : // evaluate factorial of tmp
00201       {
00202        if (mpz_cmp_ui(tmp,100000)>0)
00203         {
00204          cerr << "factorial: argument to big: " << tmp << endl;
00205          exit(1);
00206         }
00207        if (mpz_sgn(tmp)<0)
00208         {
00209          cerr << "factorial: argument negative: " << tmp << endl;
00210          exit(1);
00211         }
00212 #ifdef VERBOSE_INFO
00213        cout << "computing factorial" << endl;
00214 #endif
00215        mpz_fac_ui(n,mpz_get_ui(tmp));
00216       }
00217       break;
00218     case 'p' : // compute next prime number after tmp (as long as tmp isn't prime)
00219       {
00220         mpz_set(n,tmp); mpz_sub_ui(n,n,1);
00221         do { mpz_nextprime(n,n); } while (!mpz_probab_prime_p(n,50)); 
00222       }
00223       break;
00224     case 's' : // compute next safeprime number after tmp (as long as tmp isn't safeprime)
00225       {
00226         // safeprime: p is prime and (p-1)/2 is prime
00227         mpz_set(n,tmp);
00228         if (mpz_cmp_ui(n,7)<0) mpz_set_ui(n,7);
00229         mpz_sub_ui(n,n,1);
00230         do
00231          {
00232            mpz_nextprime(n,n);
00233            mpz_div_ui(tmp,n,2); // floor(n/2) = (n-1)/2
00234          } while (!mpz_probab_prime_p(tmp,20) || !mpz_probab_prime_p(n,50) ); 
00235       }
00236       break;
00237     case 'q' : // abort program, is tmp is composite
00238       {
00239 #ifdef VERBOSE_NOTICE
00240         cout << "special command q, testing argument..." << endl;
00241 #endif
00242         mpz_set(n,tmp);
00243         if (!mpz_probab_prime_p(n,50))
00244          {
00245            cout << "argument is not prime, aborting program." << endl;
00246            exit(0);
00247          }
00248       }
00249       break;
00250     case 'i' :
00251       mpz_add_ui(n,tmp,1);
00252       break;
00253     case 'd' :
00254       mpz_sub_ui(n,tmp,1);
00255       break;
00256     case 'r' :
00257       mpz_sqrt(n,tmp);
00258       break;
00259     case '+' :
00260       mpz_add(n,n,tmp);
00261       break;
00262     case '-' :
00263       mpz_sub(n,n,tmp);
00264       break;
00265     case '*' : 
00266       mpz_mul(n,n,tmp);
00267       break;
00268     case '/' :
00269     case ':' :
00270       {
00271         mpz_t q;
00272         mpz_init(q);
00273         mpz_div(q,n,tmp);
00274 #ifdef VERBOSE_WARN
00275         mpz_mul(tmp,q,tmp);
00276         if (mpz_cmp(tmp,n)) // is there a residue?
00277          {
00278            cout << "Warning: result of division is truncated!" << endl;
00279          }
00280 #endif
00281         mpz_set(n,q);
00282         mpz_clear(q);
00283       }
00284       break;
00285     case '%' :
00286       mpz_mod(n,n,tmp);
00287       break;
00288     case '^' :
00289 #ifdef VERBOSE_WARN
00290       if (h=='^') cout << "Warning: a^b^c ambiguent; using (a^b)^c." << endl;
00291 #endif
00292       if (!mpz_fits_ulong_p(tmp))
00293        {
00294          cerr << "argument for exponentiation too big!" << endl;
00295          exit(1);
00296        }
00297       mpz_pow_ui(n,n,mpz_get_ui(tmp));
00298       break;
00299     default :
00300       s=--s_anf;
00301       cerr << "error: operation +-*/:^ expected at '" << s << "'" << endl;
00302       term_structure_ok=false;
00303       break;
00304     }
00305   mpz_clear(tmp);
00306 
00307   if ((gZ_einstellig(op) || op=='R') && !(h=='\0'||h==')'||gZ_mehrstellig(h)) ) return false;
00308   if (gZ_einstellig(op)) return term_structure_ok;
00309 
00310   if (term_structure_ok && h!='\0' && h!=')' )
00311    {
00312      // up to now, the term is okay;
00313      // there is no trailing parenthesis and an operator follows.
00314      if (upto_op=='\0') return get_number(n,++s,h);
00315      if (gZ_priority_le(h,upto_op)) return term_structure_ok;
00316      else return get_number(n,++s,h,upto_op);
00317    }
00318   else return term_structure_ok;
00319 }
00320 
00321 } // namespace parse_term

Generated on Wed Nov 7 23:29:25 2007 for Qsieve by  doxygen 1.5.4