// 
// 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 : Sat Jul  9 11:18:04 2016
// Update Count     : 40
// 

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

int ?<=?( Rational l, Rational r ) {
	return l < r || 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

// http://www.ics.uci.edu/~eppstein/numth/frap.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 m00 = 1, m11 = 1, m01 = 0, m10 = 0;
	long int ai, t;

	// find terms until denom gets too big
	for ( ;; ) {
		ai = (long int)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 - t);
	  if ( f > (double)0x7FFFFFFF ) break;				// representation failure
	} 
	return (Rational){ m00, m10 };
} // 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: //
