//
// 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 Aug 23 22:38:48 2017
// Update Count     : 154
//

#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.numerator * r.denominator < l.denominator * r.numerator;
} // ?<?

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 );
} // ?>=?


// 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 convert( RationalImpl ); } )
double widen( Rational(RationalImpl) r ) {
 	return convert( r.numerator ) / convert( r.denominator );
} // widen

// http://www.ics.uci.edu/~eppstein/numth/frap.c
forall( otype RationalImpl | arithmetic( RationalImpl ) | { double convert( RationalImpl ); RationalImpl convert( double ); } )
Rational(RationalImpl) narrow( double f, RationalImpl md ) {
	if ( md <= (RationalImpl){1} ) {					// maximum fractional digits too small?
		return (Rational(RationalImpl)){ convert( f ), (RationalImpl){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 = convert( f );
	  if ( ! (m10 * ai + m11 <= md) ) break;
		t = m00 * ai + m01;
		m01 = m00;
		m00 = t;
		t = m10 * ai + m11;
		m11 = m10;
		m10 = t;
		double temp = convert( ai );
	  if ( f == temp ) break;							// prevent division by zero
		f = 1 / (f - temp);
	  if ( f > (double)0x7FFFFFFF ) break;				// representation failure
	} // for
	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: //
