/* 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 #include #include // define MPFR_USE_VA_LIST to enable the use of mpfr_inits and mpfr_clears #define MPFR_USE_VA_LIST #include #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