191 lines
4.2 KiB
C
191 lines
4.2 KiB
C
|
/*
|
||
|
Copyright 2015 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 "istring.h"
|
||
|
#include "array.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);
|
||
|
}
|
||
|
|
||
|
|
||
|
// 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;
|
||
|
|
||
|
*num=quot(0,1);
|
||
|
|
||
|
mode=PP_NUMERATOR_MODE;
|
||
|
for(ptr=str;*ptr!='\0';ptr++){
|
||
|
if(*ptr=='/'){
|
||
|
sscanf(buffer,"%ld",&((*num).numerator));
|
||
|
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){
|
||
|
sscanf(buffer,"%ld",&((*num).numerator));
|
||
|
}
|
||
|
else if(mode==PP_DENOMINATOR_MODE){
|
||
|
sscanf(buffer,"%ld",&((*num).denominator));
|
||
|
}
|
||
|
|
||
|
free(buffer);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
int null_declaration_so_that_the_compiler_does_not_complain;
|
||
|
#endif
|