1 // ==========================================================
2 // Helper class for rational numbers
3 //
4 // Design and implementation by
5 // - Herv� Drolon <drolon@infonie.fr>
6 //
7 // This file is part of FreeImage 3
8 //
9 // COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
10 // OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
11 // THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
12 // OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
13 // CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
14 // THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
15 // SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
16 // PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
17 // THIS DISCLAIMER.
18 //
19 // Use at your own risk!
20 // ==========================================================
21
22 #include "FreeImage.h"
23 #include "Utilities.h"
24 #include "FIRational.h"
25
26 /// Initialize and normalize a rational number
initialize(LONG n,LONG d)27 void FIRational::initialize(LONG n, LONG d) {
28 if(d) {
29 _numerator = n;
30 _denominator = d;
31 // normalize rational
32 normalize();
33 } else {
34 _numerator = 0;
35 _denominator = 0;
36 }
37 }
38
39 /// Default constructor
FIRational()40 FIRational::FIRational() {
41 _numerator = 0;
42 _denominator = 0;
43 }
44
45 /// Constructor with longs
FIRational(LONG n,LONG d)46 FIRational::FIRational(LONG n, LONG d) {
47 initialize(n, d);
48 }
49
50 /// Constructor with FITAG
FIRational(const FITAG * tag)51 FIRational::FIRational(const FITAG *tag) {
52 switch(FreeImage_GetTagType((FITAG*)tag)) {
53 case FIDT_RATIONAL: // 64-bit unsigned fraction
54 {
55 DWORD *pvalue = (DWORD*)FreeImage_GetTagValue((FITAG*)tag);
56 initialize((LONG)pvalue[0], (LONG)pvalue[1]);
57 break;
58 }
59
60 case FIDT_SRATIONAL: // 64-bit signed fraction
61 {
62 LONG *pvalue = (LONG*)FreeImage_GetTagValue((FITAG*)tag);
63 initialize((LONG)pvalue[0], (LONG)pvalue[1]);
64 break;
65 }
66 }
67 }
68
FIRational(float value)69 FIRational::FIRational(float value) {
70 if (value == (float)((LONG)value)) {
71 _numerator = (LONG)value;
72 _denominator = 1L;
73 } else {
74 int k, count;
75 LONG n[4];
76
77 float x = fabs(value);
78 int sign = (value > 0) ? 1 : -1;
79
80 // make a continued-fraction expansion of x
81 count = -1;
82 for(k = 0; k < 4; k++) {
83 n[k] = (LONG)floor(x);
84 count++;
85 x -= (float)n[k];
86 if(x == 0) break;
87 x = 1 / x;
88 }
89 // compute the rational
90 _numerator = 1;
91 _denominator = n[count];
92
93 for(int i = count - 1; i >= 0; i--) {
94 if(n[i] == 0) break;
95 LONG _num = (n[i] * _numerator + _denominator);
96 LONG _den = _numerator;
97 _numerator = _num;
98 _denominator = _den;
99 }
100 _numerator *= sign;
101 }
102 }
103
104 /// Copy constructor
FIRational(const FIRational & r)105 FIRational::FIRational (const FIRational& r) {
106 initialize(r._numerator, r._denominator);
107 }
108
109 /// Destructor
~FIRational()110 FIRational::~FIRational() {
111 }
112
113 /// Assignement operator
operator =(FIRational & r)114 FIRational& FIRational::operator=(FIRational& r) {
115 if(this != &r) {
116 initialize(r._numerator, r._denominator);
117 }
118 return *this;
119 }
120
121 /// Get the numerator
getNumerator()122 LONG FIRational::getNumerator() {
123 return _numerator;
124 }
125
126 /// Get the denominator
getDenominator()127 LONG FIRational::getDenominator() {
128 return _denominator;
129 }
130
131 /// Calculate GCD
gcd(LONG a,LONG b)132 LONG FIRational::gcd(LONG a, LONG b) {
133 LONG temp;
134 while (b) { // While non-zero value
135 temp = b; // Save current value
136 b = a % b; // Assign remainder of division
137 a = temp; // Copy old value
138 }
139 return a; // Return GCD of numbers
140 }
141
142 /// Normalize numerator / denominator
normalize()143 void FIRational::normalize() {
144 if (_numerator != 1 && _denominator != 1) { // Is there something to do?
145 // Calculate GCD
146 LONG common = gcd(_numerator, _denominator);
147 if (common != 1) { // If GCD is not one
148 _numerator /= common; // Calculate new numerator
149 _denominator /= common; // Calculate new denominator
150 }
151 }
152 if(_denominator < 0) { // If sign is in denominator
153 _numerator *= -1; // Multiply num and den by -1
154 _denominator *= -1; // To keep sign in numerator
155 }
156 }
157
158 /// Checks if this rational number is an Integer, either positive or negative
isInteger()159 BOOL FIRational::isInteger() {
160 if(_denominator == 1 || (_denominator != 0 && (_numerator % _denominator == 0)) || (_denominator == 0 && _numerator == 0))
161 return TRUE;
162 return FALSE;
163 }
164
165 /// Convert as "numerator/denominator"
toString()166 std::string FIRational::toString() {
167 std::ostringstream s;
168 if(isInteger()) {
169 s << intValue();
170 } else {
171 s << _numerator << "/" << _denominator;
172 }
173 return s.str();
174 }
175
176
177