Ian Jauslin
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/rational_int.c')
-rw-r--r--src/rational_int.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/src/rational_int.c b/src/rational_int.c
new file mode 100644
index 0000000..ec601a8
--- /dev/null
+++ b/src/rational_int.c
@@ -0,0 +1,190 @@
+/*
+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