// -*- Mode: C -*- // // 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 : Wed May 4 14:16:14 2016 // Update Count : 25 // #include "rational" #include "fstream" #include "stdlib" #include "math" // floor // constants struct Rational 0 = {0, 1}; struct Rational 1 = {1, 1}; // 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 static long int gcd( long int a, long int b ) { for ( ;; ) { // Euclid's algorithm long int r = a % b; if ( r == 0 ) break; a = b; b = r; } // for return b; } // gcd static long int simplify( long int *n, long int *d ) { if ( *d == 0 ) { serr | "Invalid rational number construction: denominator cannot be equal to 0." | endl; exit( EXIT_FAILURE ); } // exit if ( *d < 0 ) { *d = -*d; *n = -*n; } // move sign to numerator return gcd( abs( *n ), *d ); // simplify } // Rationalnumber::simplify // constructors void ?{}( Rational * r ) { r{ 0, 1 }; } // rational void ?{}( Rational * r, long int n ) { r{ n, 1 }; } // rational void ?{}( Rational * r, long int n, long int d ) { long int t = simplify( &n, &d ); // simplify r->numerator = n / t; r->denominator = d / t; } // rational // getter/setter for numerator/denominator long int numerator( Rational r ) { return r.numerator; } // numerator long int numerator( Rational r, long int n ) { long int prev = r.numerator; long int t = gcd( abs( n ), r.denominator ); // simplify r.numerator = n / t; r.denominator = r.denominator / t; return prev; } // numerator long int denominator( Rational r ) { return r.denominator; } // denominator long int denominator( Rational r, long int d ) { long int prev = r.denominator; long int t = simplify( &r.numerator, &d ); // simplify r.numerator = r.numerator / t; r.denominator = d / t; return prev; } // denominator // comparison int ?==?( Rational l, Rational r ) { return l.numerator * r.denominator == l.denominator * r.numerator; } // ?==? int ?!=?( Rational l, Rational r ) { return ! ( l == r ); } // ?!=? int ??( Rational l, Rational r ) { return ! ( l <= r ); } // ?>? int ?>=?( Rational l, Rational r ) { return ! ( l < r ); } // ?>=? // arithmetic Rational -?( Rational r ) { Rational t = { -r.numerator, r.denominator }; return t; } // -? Rational ?+?( Rational l, Rational r ) { if ( l.denominator == r.denominator ) { // special case Rational t = { l.numerator + r.numerator, l.denominator }; return t; } else { Rational t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator }; return t; } // if } // ?+? Rational ?-?( Rational l, Rational r ) { if ( l.denominator == r.denominator ) { // special case Rational t = { l.numerator - r.numerator, l.denominator }; return t; } else { Rational t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator }; return t; } // if } // ?-? Rational ?*?( Rational l, Rational r ) { Rational t = { l.numerator * r.numerator, l.denominator * r.denominator }; return t; } // ?*? Rational ?/?( Rational l, Rational r ) { if ( r.numerator < 0 ) { r.numerator = -r.numerator; r.denominator = -r.denominator; } // if Rational t = { l.numerator * r.denominator, l.denominator * r.numerator }; return t; } // ?/? // conversion double widen( Rational r ) { return (double)r.numerator / (double)r.denominator; } // widen // https://rosettacode.org/wiki/Convert_decimal_number_to_rational#C Rational narrow( double f, long int md ) { if ( md <= 1 ) { // maximum fractional digits too small? return (Rational){ f, 1}; // truncate fraction } // if // continued fraction coefficients long int a, h[3] = { 0, 1, 0 }, k[3] = { 1, 0, 0 }; long int x, d, n = 1; int i, neg = 0; if ( f < 0 ) { neg = 1; f = -f; } while ( f != floor( f ) ) { n <<= 1; f *= 2; } d = f; // continued fraction and check denominator each step for (i = 0; i < 64; i++) { a = n ? d / n : 0; if (i && !a) break; x = d; d = n; n = x % n; x = a; if (k[1] * a + k[0] >= md) { x = (md - k[0]) / k[1]; if ( ! (x * 2 >= a || k[1] >= md) ) break; i = 65; } // if h[2] = x * h[1] + h[0]; h[0] = h[1]; h[1] = h[2]; k[2] = x * k[1] + k[0]; k[0] = k[1]; k[1] = k[2]; } // for return (Rational){ neg ? -h[1] : h[1], k[1] }; } // narrow // I/O forall( dtype istype | istream( istype ) ) istype * ?|?( istype *is, Rational *r ) { long int t; is | &(r->numerator) | &(r->denominator); t = simplify( &(r->numerator), &(r->denominator) ); r->numerator /= t; r->denominator /= t; return is; } // ?|? forall( dtype ostype | ostream( ostype ) ) ostype * ?|?( ostype *os, Rational r ) { return os | r.numerator | '/' | r.denominator; } // ?|? // Local Variables: // // tab-width: 4 // // End: //