//                               -*- 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.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

// 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: //
