source: src/libcfa/rational.c@ 37f0da8

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors ctor deferred_resn demangler enum forall-pointer-decay gc_noraii jacob/cs343-translation jenkins-sandbox memory new-ast new-ast-unique-expr new-env no_list persistent-indexer pthread-emulation qualifiedEnum resolv-new string with_gc
Last change on this file since 37f0da8 was 45161b4d, checked in by Peter A. Buhr <pabuhr@…>, 9 years ago

generate implicit typedef right after sue name appears, further fixes storage allocation routines and comments

  • Property mode set to 100644
File size: 5.5 KB
Line 
1// -*- Mode: C -*-
2//
3// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
4//
5// The contents of this file are covered under the licence agreement in the
6// file "LICENCE" distributed with Cforall.
7//
8// rational.c --
9//
10// Author : Peter A. Buhr
11// Created On : Wed Apr 6 17:54:28 2016
12// Last Modified By : Peter A. Buhr
13// Last Modified On : Tue Apr 12 21:26:42 2016
14// Update Count : 21
15//
16
17#include "rational"
18#include "fstream"
19#include "stdlib"
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
54Rational rational() {
55 return (Rational){ 0, 1 };
56} // rational
57
58Rational rational( long int n ) {
59 return (Rational){ n, 1 };
60} // rational
61
62Rational rational( long int n, long int d ) {
63 long int t = simplify( &n, &d ); // simplify
64 return (Rational){ n / t, d / t };
65} // rational
66
67
68// getter/setter for numerator/denominator
69
70long int numerator( Rational r ) {
71 return r.numerator;
72} // numerator
73
74long int numerator( Rational r, long int n ) {
75 long int prev = r.numerator;
76 long int t = gcd( abs( n ), r.denominator ); // simplify
77 r.numerator = n / t;
78 r.denominator = r.denominator / t;
79 return prev;
80} // numerator
81
82long int denominator( Rational r ) {
83 return r.denominator;
84} // denominator
85
86long int denominator( Rational r, long int d ) {
87 long int prev = r.denominator;
88 long int t = simplify( &r.numerator, &d ); // simplify
89 r.numerator = r.numerator / t;
90 r.denominator = d / t;
91 return prev;
92} // denominator
93
94
95// comparison
96
97int ?==?( Rational l, Rational r ) {
98 return l.numerator * r.denominator == l.denominator * r.numerator;
99} // ?==?
100
101int ?!=?( Rational l, Rational r ) {
102 return ! ( l == r );
103} // ?!=?
104
105int ?<?( Rational l, Rational r ) {
106 return l.numerator * r.denominator < l.denominator * r.numerator;
107} // ?<?
108
109int ?<=?( Rational l, Rational r ) {
110 return l < r || l == r;
111} // ?<=?
112
113int ?>?( Rational l, Rational r ) {
114 return ! ( l <= r );
115} // ?>?
116
117int ?>=?( Rational l, Rational r ) {
118 return ! ( l < r );
119} // ?>=?
120
121
122// arithmetic
123
124Rational -?( Rational r ) {
125 Rational t = { -r.numerator, r.denominator };
126 return t;
127} // -?
128
129Rational ?+?( Rational l, Rational r ) {
130 if ( l.denominator == r.denominator ) { // special case
131 Rational t = { l.numerator + r.numerator, l.denominator };
132 return t;
133 } else {
134 Rational t = { l.numerator * r.denominator + l.denominator * r.numerator, l.denominator * r.denominator };
135 return t;
136 } // if
137} // ?+?
138
139Rational ?-?( Rational l, Rational r ) {
140 if ( l.denominator == r.denominator ) { // special case
141 Rational t = { l.numerator - r.numerator, l.denominator };
142 return t;
143 } else {
144 Rational t = { l.numerator * r.denominator - l.denominator * r.numerator, l.denominator * r.denominator };
145 return t;
146 } // if
147} // ?-?
148
149Rational ?*?( Rational l, Rational r ) {
150 Rational t = { l.numerator * r.numerator, l.denominator * r.denominator };
151 return t;
152} // ?*?
153
154Rational ?/?( Rational l, Rational r ) {
155 if ( r.numerator < 0 ) {
156 r.numerator = -r.numerator;
157 r.denominator = -r.denominator;
158 } // if
159 Rational t = { l.numerator * r.denominator, l.denominator * r.numerator };
160 return t;
161} // ?/?
162
163
164// conversion
165
166double widen( Rational r ) {
167 return (double)r.numerator / (double)r.denominator;
168} // widen
169
170// https://rosettacode.org/wiki/Convert_decimal_number_to_rational#C
171Rational narrow( double f, long int md ) {
172 if ( md <= 1 ) { // maximum fractional digits too small?
173 Rational t = rational( f, 1 ); // truncate fraction
174 return t;
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 Rational t = rational( neg ? -h[1] : h[1], k[1] );
201 return t;
202} // narrow
203
204
205// I/O
206
207forall( dtype istype | istream( istype ) )
208istype * ?|?( istype *is, Rational *r ) {
209 long int t;
210 is | &(r->numerator) | &(r->denominator);
211 t = simplify( &(r->numerator), &(r->denominator) );
212 r->numerator /= t;
213 r->denominator /= t;
214 return is;
215} // ?|?
216
217forall( dtype ostype | ostream( ostype ) )
218ostype * ?|?( ostype *os, Rational r ) {
219 return os | r.numerator | '/' | r.denominator;
220} // ?|?
221
222// Local Variables: //
223// tab-width: 4 //
224// End: //
Note: See TracBrowser for help on using the repository browser.