meankondo/src/rational_int.c
Ian Jauslin 167980ea43 Update to v1.5.
The update to version 1.5 is rather substantial, and introduces some minor
  backward-incompatibilities:
    * The header "#!symbols" has been replaced by "#!virtual_fields"
    * Multiplying polynomials using the '*' symbol is no longer supported (or,
      rather, the symbolic capabilities of meankondo were enhanced, and the
      syntax has been changed).
    * 'meantools exp' has been removed (its functionality is now handled by
      other means)
    * 'meantoolds derive' has been replaced by 'meantools differentiate'

  * The symbolic capabilities were enhanced: polynomials can now be
    multiplied, added, exponentiated, and their logarithms can be taken
    directly in the configuration file.

  * The flow equation can now be processed after being computed using the
    various "#!postprocess_*" entries.

  * Deprecated kondo_preprocess.

  * Compute the mean using an LU decomposition if possible.

  * More detailed checks for syntax errors in configuration file.

  * Check that different '#!group' entries are indeed uncorrelated.

  * New flags in meankondo: '-p' and '-A'.

  * New tool: meantools expand.

  * Improve conversion to LaTeX using meantools-convert

  * Assign terms randomly to different threads.

  * Multiple bug fixes
2022-06-14 09:26:07 +02:00

219 lines
5.0 KiB
C

/*
Copyright 2015-2022 Ian Jauslin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef RATIONAL_AS_FLOAT
#include "rational_int.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
// define MPFR_USE_VA_LIST to enable the use of mpfr_inits and mpfr_clears
#define MPFR_USE_VA_LIST
#include <mpfr.h>
#include "istring.h"
#include "array.h"
#include "parse_file.h"
Q quot(long int p, long int q){
Q ret;
if(q==0){
fprintf(stderr,"error: %ld/%ld is ill defined\n",p,q);
exit(-1);
}
ret.numerator=p;
ret.denominator=q;
return(ret);
}
// add
Q Q_add(Q x1,Q x2){
Q ret;
ret.denominator=lcm(x1.denominator,x2.denominator);
ret.numerator=x1.numerator*(ret.denominator/x1.denominator)+x2.numerator*(ret.denominator/x2.denominator);
return(Q_simplify(ret));
}
//multiply
Q Q_prod(Q x1,Q x2){
return(Q_simplify(quot(x1.numerator*x2.numerator,x1.denominator*x2.denominator)));
}
// inverse
Q Q_inverse(Q x1){
if(x1.numerator>0){
return(quot(x1.denominator,x1.numerator));
}
else if(x1.numerator<0){
return(quot(-x1.denominator,-x1.numerator));
}
else{
fprintf(stderr,"error: attempting to invert %ld/%ld\n",x1.numerator, x1.denominator);
exit(-1);
}
}
// quotient
Q Q_quot(Q x1, Q x2){
if(x2.numerator>0){
return(Q_simplify(quot(x1.numerator*x2.denominator,x1.denominator*x2.numerator)));
}
else if(x2.numerator<0){
return(Q_simplify(quot(-x1.numerator*x2.denominator,-x1.denominator*x2.numerator)));
}
else{
fprintf(stderr,"error: attempting to invert %ld/%ld\n",x2.numerator, x2.denominator);
exit(-1);
}
}
// compare
int Q_cmp(Q x1, Q x2){
Q quo=Q_quot(x1,x2);
if(quo.numerator > quo.denominator){
return(1);
}
else if(quo.numerator < quo.denominator){
return(-1);
}
else{
return(0);
}
}
// simplify
Q Q_simplify(Q x){
return(quot(x.numerator/gcd(x.numerator,x.denominator),x.denominator/gcd(x.numerator,x.denominator)));
}
//simplify in place
int Q_simplify_inplace(Q* x){
Q ret=Q_simplify(*x);
*x=ret;
return(0);
}
// greatest common divisor
long int gcd(long int x, long int y){
long int ax=labs(x);
long int ay=labs(y);
int security=0;
while(ax!=0 && ay!=0){
if(ax>ay){ax=ax%ay;}
else{ay=ay%ax;}
security++;
if(security>1000000){
fprintf(stderr,"error: could not compute gcd( %ld , %ld ) after %d tries\n",x,y,security);
exit(-1);
}
}
// if both are negative, gcd should be negative (useful for simplification of fractions and product of square roots)
if(x<0 && y<0){
ax*=-1;
ay*=-1;
}
if(labs(ay)>labs(ax)){return(ay);}
else{return(ax);}
}
// least common multiple
long int lcm(long int x,long int y){
if(x!=0 || y!=0){
return((x*y)/gcd(x,y));
}
else{
return(0);
}
}
// approximate value as double
double Q_double_value(Q q){
return(1.0*q.numerator/q.denominator);
}
// approximate value as mpfr float
int Q_mpfr_value(mpfr_t out, Q q){
mpfr_t x;
mpfr_init(out);
mpfr_init(x);
mpfr_set_si(x, q.denominator, MPFR_RNDN);
mpfr_si_div(out, q.numerator, x, MPFR_RNDN);
mpfr_clear(x);
return(0);
}
// print to string
int Q_sprint(Q num, Char_Array* out){
if(num.denominator!=1){
char_array_snprintf(out,"%ld/%ld", num.numerator,num.denominator);
}
else{
char_array_snprintf(out,"%ld",num.numerator);
}
return(0);
}
#define PP_NUMERATOR_MODE 1
#define PP_DENOMINATOR_MODE 2
// read from a string
int str_to_Q(char* str, Q* num){
char* ptr;
int mode;
char* buffer=calloc(str_len(str)+1,sizeof(char));
char* buffer_ptr=buffer;
int ret;
*num=quot(0,1);
mode=PP_NUMERATOR_MODE;
for(ptr=str;*ptr!='\0';ptr++){
if(*ptr=='/'){
ret=read_long_int(buffer,&((*num).numerator));
if(ret<0){
fprintf(stderr,"syntax error: numerator should be an integer, got '%s' in '%s'\n",buffer,str);
exit(-1);
}
buffer_ptr=buffer;
*buffer_ptr='\0';
mode=PP_DENOMINATOR_MODE;
}
else{
buffer_ptr=str_addchar(buffer_ptr,*ptr);
}
}
// last step
if(mode==PP_NUMERATOR_MODE){
ret=read_long_int(buffer,&((*num).numerator));
if(ret<0){
fprintf(stderr,"syntax error: numerator should be an integer, got '%s' in '%s'\n",buffer,str);
exit(-1);
}
}
else if(mode==PP_DENOMINATOR_MODE){
ret=read_long_int(buffer,&((*num).denominator));
if(ret<0){
fprintf(stderr,"syntax error: numerator should be an integer, got '%s' in '%s'\n",buffer,str);
exit(-1);
}
}
free(buffer);
return(0);
}
#else
int null_declaration_so_that_the_compiler_does_not_complain;
#endif