# source:src/libcfa/rational.c@a6151ba

Last change on this file since a6151ba was a6151ba, checked in by Peter A. Buhr <pabuhr@…>, 8 years ago

• Property mode set to `100644`
File size: 5.4 KB
Line
1//
2// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// rational.c --
8//
9// Author           : Peter A. Buhr
10// Created On       : Wed Apr  6 17:54:28 2016
13// Update Count     : 26
14//
15
16#include "rational"
17#include "fstream"
18#include "stdlib"
19#include "math"                                                                                 // floor
20
21
22// constants
23
24struct Rational 0 = {0, 1};
25struct Rational 1 = {1, 1};
26
27
28// helper routines
29
30// Calculate greatest common denominator of two numbers, the first of which may be negative. Used to reduce rationals.
31// alternative: https://en.wikipedia.org/wiki/Binary_GCD_algorithm
32static long int gcd( long int a, long int b ) {
33    for ( ;; ) {                                                                                // Euclid's algorithm
34                long int r = a % b;
35          if ( r == 0 ) break;
36                a = b;
37                b = r;
38    } // for
39        return b;
40} // gcd
41
42static long int simplify( long int *n, long int *d ) {
43    if ( *d == 0 ) {
44                serr | "Invalid rational number construction: denominator cannot be equal to 0." | endl;
45                exit( EXIT_FAILURE );
46    } // exit
47    if ( *d < 0 ) { *d = -*d; *n = -*n; }                               // move sign to numerator
48    return gcd( abs( *n ), *d );                                                // simplify
49} // Rationalnumber::simplify
50
51
52// constructors
53
54void ?{}( Rational * r ) {
55    r{ 0, 1 };
56} // rational
57
58void ?{}( Rational * r, long int n ) {
59    r{ n, 1 };
60} // rational
61
62void ?{}( Rational * r, long int n, long int d ) {
63    long int t = simplify( &n, &d );                                    // simplify
64    r->numerator = n / t;
65        r->denominator = d / t;
66} // rational
67
68
69// getter/setter for numerator/denominator
70
71long int numerator( Rational r ) {
72    return r.numerator;
73} // numerator
74
75long int numerator( Rational r, long int n ) {
76    long int prev = r.numerator;
77    long int t = gcd( abs( n ), r.denominator );                // simplify
78    r.numerator = n / t;
79    r.denominator = r.denominator / t;
80    return prev;
81} // numerator
82
83long int denominator( Rational r ) {
84    return r.denominator;
85} // denominator
86
87long int denominator( Rational r, long int d ) {
88    long int prev = r.denominator;
89    long int t = simplify( &r.numerator, &d );                  // simplify
90    r.numerator = r.numerator / t;
91    r.denominator = d / t;
92    return prev;
93} // denominator
94
95
96// comparison
97
98int ?==?( Rational l, Rational r ) {
99    return l.numerator * r.denominator == l.denominator * r.numerator;
100} // ?==?
101
102int ?!=?( Rational l, Rational r ) {
103    return ! ( l == r );
104} // ?!=?
105
106int ?<?( Rational l, Rational r ) {
107    return l.numerator * r.denominator < l.denominator * r.numerator;
108} // ?<?
109
110int ?<=?( Rational l, Rational r ) {
111    return l < r || l == r;
112} // ?<=?
113
114int ?>?( Rational l, Rational r ) {
115    return ! ( l <= r );
116} // ?>?
117
118int ?>=?( Rational l, Rational r ) {
119    return ! ( l < r );
120} // ?>=?
121
122
123// arithmetic
124
125Rational -?( Rational r ) {
126        Rational t = { -r.numerator, r.denominator };
127    return t;
128} // -?
129
130Rational ?+?( Rational l, Rational r ) {
131    if ( l.denominator == r.denominator ) {                             // special case
132                Rational t = { l.numerator + r.numerator, l.denominator };
133                return t;
134    } else {
135                Rational t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
136                return t;
137    } // if
138} // ?+?
139
140Rational ?-?( Rational l, Rational r ) {
141    if ( l.denominator == r.denominator ) {                             // special case
142                Rational t = { l.numerator - r.numerator, l.denominator };
143                return t;
144    } else {
145                Rational t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
146                return t;
147    } // if
148} // ?-?
149
150Rational ?*?( Rational l, Rational r ) {
151    Rational t = { l.numerator * r.numerator, l.denominator * r.denominator };
152        return t;
153} // ?*?
154
155Rational ?/?( Rational l, Rational r ) {
156    if ( r.numerator < 0 ) {
157                r.numerator = -r.numerator;
158                r.denominator = -r.denominator;
159        } // if
160        Rational t = { l.numerator * r.denominator, l.denominator * r.numerator };
161    return t;
162} // ?/?
163
164
165// conversion
166
167double widen( Rational r ) {
168        return (double)r.numerator / (double)r.denominator;
169} // widen
170
171// https://rosettacode.org/wiki/Convert_decimal_number_to_rational#C
172Rational narrow( double f, long int md ) {
173        if ( md <= 1 ) {                                                                        // maximum fractional digits too small?
174                return (Rational){ f, 1};                                               // truncate fraction
175        } // if
176
177        // continued fraction coefficients
178        long int a, h[3] = { 0, 1, 0 }, k[3] = { 1, 0, 0 };
179        long int x, d, n = 1;
180        int i, neg = 0;
181
182        if ( f < 0 ) { neg = 1; f = -f; }
183        while ( f != floor( f ) ) { n <<= 1; f *= 2; }
184        d = f;
185
186        // continued fraction and check denominator each step
187        for (i = 0; i < 64; i++) {
188                a = n ? d / n : 0;
189          if (i && !a) break;
190                x = d; d = n; n = x % n;
191                x = a;
192                if (k[1] * a + k[0] >= md) {
193                        x = (md - k[0]) / k[1];
194                  if ( ! (x * 2 >= a || k[1] >= md) ) break;
195                        i = 65;
196                } // if
197                h[2] = x * h[1] + h[0]; h[0] = h[1]; h[1] = h[2];
198                k[2] = x * k[1] + k[0]; k[0] = k[1]; k[1] = k[2];
199        } // for
200        return (Rational){ neg ? -h[1] : h[1], k[1] };
201} // narrow
202
203
204// I/O
205
206forall( dtype istype | istream( istype ) )
207istype * ?|?( istype *is, Rational *r ) {
208        long int t;
209    is | &(r->numerator) | &(r->denominator);
210        t = simplify( &(r->numerator), &(r->denominator) );
211    r->numerator /= t;
212    r->denominator /= t;
213    return is;
214} // ?|?
215
216forall( dtype ostype | ostream( ostype ) )
217ostype * ?|?( ostype *os, Rational r ) {
218    return os | r.numerator | '/' | r.denominator;
219} // ?|?
220
221// Local Variables: //
222// tab-width: 4 //
223// End: //
Note: See TracBrowser for help on using the repository browser.