// // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // rational.c -- // // Author : Peter A. Buhr // Created On : Wed Apr 6 17:54:28 2016 // Last Modified By : Peter A. Buhr // Last Modified On : Sun May 14 17:25:19 2017 // Update Count : 131 // #include "rational" #include "fstream" #include "stdlib" // helper routines // Calculate greatest common denominator of two numbers, the first of which may be negative. Used to reduce rationals. // alternative: https://en.wikipedia.org/wiki/Binary_GCD_algorithm forall ( otype RationalImpl | arithmetic( RationalImpl ) ) static RationalImpl gcd( RationalImpl a, RationalImpl b ) { for ( ;; ) { // Euclid's algorithm RationalImpl r = a % b; if ( r == (RationalImpl){0} ) break; a = b; b = r; } // for return b; } // gcd forall ( otype RationalImpl | arithmetic( RationalImpl ) ) static RationalImpl simplify( RationalImpl * n, RationalImpl * d ) { if ( *d == (RationalImpl){0} ) { serr | "Invalid rational number construction: denominator cannot be equal to 0." | endl; exit( EXIT_FAILURE ); } // exit if ( *d < (RationalImpl){0} ) { *d = -*d; *n = -*n; } // move sign to numerator return gcd( abs( *n ), *d ); // simplify } // Rationalnumber::simplify // constructors forall ( otype RationalImpl | arithmetic( RationalImpl ) ) void ?{}( Rational(RationalImpl) * r ) { r{ (RationalImpl){0}, (RationalImpl){1} }; } // rational forall ( otype RationalImpl | arithmetic( RationalImpl ) ) void ?{}( Rational(RationalImpl) * r, RationalImpl n ) { r{ n, (RationalImpl){1} }; } // rational forall ( otype RationalImpl | arithmetic( RationalImpl ) ) void ?{}( Rational(RationalImpl) * r, RationalImpl n, RationalImpl d ) { RationalImpl t = simplify( &n, &d ); // simplify r->numerator = n / t; r->denominator = d / t; } // rational // getter for numerator/denominator forall ( otype RationalImpl | arithmetic( RationalImpl ) ) RationalImpl numerator( Rational(RationalImpl) r ) { return r.numerator; } // numerator forall ( otype RationalImpl | arithmetic( RationalImpl ) ) RationalImpl denominator( Rational(RationalImpl) r ) { return r.denominator; } // denominator forall ( otype RationalImpl | arithmetic( RationalImpl ) ) [ RationalImpl, RationalImpl ] ?=?( * [ RationalImpl, RationalImpl ] dest, Rational(RationalImpl) src ) { return *dest = src.[ numerator, denominator ]; } // setter for numerator/denominator forall ( otype RationalImpl | arithmetic( RationalImpl ) ) RationalImpl numerator( Rational(RationalImpl) r, RationalImpl n ) { RationalImpl prev = r.numerator; RationalImpl t = gcd( abs( n ), r.denominator ); // simplify r.numerator = n / t; r.denominator = r.denominator / t; return prev; } // numerator forall ( otype RationalImpl | arithmetic( RationalImpl ) ) RationalImpl denominator( Rational(RationalImpl) r, RationalImpl d ) { RationalImpl prev = r.denominator; RationalImpl t = simplify( &r.numerator, &d ); // simplify r.numerator = r.numerator / t; r.denominator = d / t; return prev; } // denominator // comparison forall ( otype RationalImpl | arithmetic( RationalImpl ) ) int ?==?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { return l.numerator * r.denominator == l.denominator * r.numerator; } // ?==? forall ( otype RationalImpl | arithmetic( RationalImpl ) ) int ?!=?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { return ! ( l == r ); } // ?!=? forall ( otype RationalImpl | arithmetic( RationalImpl ) ) int ??( Rational(RationalImpl) l, Rational(RationalImpl) r ) { return ! ( l <= r ); } // ?>? forall ( otype RationalImpl | arithmetic( RationalImpl ) ) int ?>=?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { return ! ( l < r ); } // ?>=? // arithmetic forall ( otype RationalImpl | arithmetic( RationalImpl ) ) Rational(RationalImpl) +?( Rational(RationalImpl) r ) { Rational(RationalImpl) t = { r.numerator, r.denominator }; return t; } // +? forall ( otype RationalImpl | arithmetic( RationalImpl ) ) Rational(RationalImpl) -?( Rational(RationalImpl) r ) { Rational(RationalImpl) t = { -r.numerator, r.denominator }; return t; } // -? forall ( otype RationalImpl | arithmetic( RationalImpl ) ) Rational(RationalImpl) ?+?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { if ( l.denominator == r.denominator ) { // special case Rational(RationalImpl) t = { l.numerator + r.numerator, l.denominator }; return t; } else { Rational(RationalImpl) t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; return t; } // if } // ?+? forall ( otype RationalImpl | arithmetic( RationalImpl ) ) Rational(RationalImpl) ?-?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { if ( l.denominator == r.denominator ) { // special case Rational(RationalImpl) t = { l.numerator - r.numerator, l.denominator }; return t; } else { Rational(RationalImpl) t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; return t; } // if } // ?-? forall ( otype RationalImpl | arithmetic( RationalImpl ) ) Rational(RationalImpl) ?*?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { Rational(RationalImpl) t = { l.numerator * r.numerator, l.denominator * r.denominator }; return t; } // ?*? forall ( otype RationalImpl | arithmetic( RationalImpl ) ) Rational(RationalImpl) ?/?( Rational(RationalImpl) l, Rational(RationalImpl) r ) { if ( r.numerator < (RationalImpl){0} ) { r.numerator = -r.numerator; r.denominator = -r.denominator; } // if Rational(RationalImpl) t = { l.numerator * r.denominator, l.denominator * r.numerator }; return t; } // ?/? // conversion // forall ( otype RationalImpl | arithmetic( RationalImpl ) ) // double widen( Rational(RationalImpl) r ) { // return (double)r.numerator / (double)r.denominator; // } // widen // // http://www.ics.uci.edu/~eppstein/numth/frap.c // forall ( otype RationalImpl | arithmetic( RationalImpl ) ) // Rational(RationalImpl) narrow( double f, RationalImpl md ) { // if ( md <= 1 ) { // maximum fractional digits too small? // return (Rational(RationalImpl)){ f, 1}; // truncate fraction // } // if // // continued fraction coefficients // RationalImpl m00 = 1, m11 = 1, m01 = 0, m10 = 0; // RationalImpl ai, t; // // find terms until denom gets too big // for ( ;; ) { // ai = (RationalImpl)f; // if ( ! (m10 * ai + m11 <= md) ) break; // t = m00 * ai + m01; // m01 = m00; // m00 = t; // t = m10 * ai + m11; // m11 = m10; // m10 = t; // t = (double)ai; // if ( f == t ) break; // prevent division by zero // f = 1 / (f - (double)t); // if ( f > (double)0x7FFFFFFF ) break; // representation failure // } // return (Rational(RationalImpl)){ m00, m10 }; // } // narrow // I/O forall ( otype RationalImpl | arithmetic( RationalImpl ) ) forall( dtype istype | istream( istype ) | { istype * ?|?( istype *, RationalImpl * ); } ) istype * ?|?( istype * is, Rational(RationalImpl) * r ) { RationalImpl t; is | &(r->numerator) | &(r->denominator); t = simplify( &(r->numerator), &(r->denominator) ); r->numerator /= t; r->denominator /= t; return is; } // ?|? forall ( otype RationalImpl | arithmetic( RationalImpl ) ) forall( dtype ostype | ostream( ostype ) | { ostype * ?|?( ostype *, RationalImpl ); } ) ostype * ?|?( ostype * os, Rational(RationalImpl ) r ) { return os | r.numerator | '/' | r.denominator; } // ?|? // Local Variables: // // tab-width: 4 // // End: //