/src/freeimage-svn/FreeImage/trunk/Source/Metadata/FIRational.cpp
Line  | Count  | Source  | 
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  | 
27  | 0  | void FIRational::initialize(LONG n, LONG d) { | 
28  | 0  |   if(d) { | 
29  | 0  |     _numerator = n;  | 
30  | 0  |     _denominator = d;  | 
31  |  |     // normalize rational  | 
32  | 0  |     normalize();  | 
33  | 0  |   } else { | 
34  | 0  |     _numerator = 0;  | 
35  | 0  |     _denominator = 0;  | 
36  | 0  |   }  | 
37  | 0  | }  | 
38  |  |  | 
39  |  | /// Default constructor  | 
40  | 0  | FIRational::FIRational() { | 
41  | 0  |   _numerator = 0;  | 
42  | 0  |   _denominator = 0;  | 
43  | 0  | }  | 
44  |  |  | 
45  |  | /// Constructor with longs  | 
46  | 0  | FIRational::FIRational(LONG n, LONG d) { | 
47  | 0  |   initialize(n, d);  | 
48  | 0  | }  | 
49  |  |  | 
50  |  | /// Constructor with FITAG  | 
51  | 0  | FIRational::FIRational(const FITAG *tag) { | 
52  | 0  |   switch(FreeImage_GetTagType((FITAG*)tag)) { | 
53  | 0  |     case FIDT_RATIONAL:   // 64-bit unsigned fraction   | 
54  | 0  |     { | 
55  | 0  |       DWORD *pvalue = (DWORD*)FreeImage_GetTagValue((FITAG*)tag);  | 
56  | 0  |       initialize((LONG)pvalue[0], (LONG)pvalue[1]);  | 
57  | 0  |       break;  | 
58  | 0  |     }  | 
59  |  |  | 
60  | 0  |     case FIDT_SRATIONAL:  // 64-bit signed fraction   | 
61  | 0  |     { | 
62  | 0  |       LONG *pvalue = (LONG*)FreeImage_GetTagValue((FITAG*)tag);  | 
63  | 0  |       initialize((LONG)pvalue[0], (LONG)pvalue[1]);  | 
64  | 0  |       break;  | 
65  | 0  |     }  | 
66  | 0  |   }  | 
67  | 0  | }  | 
68  |  |  | 
69  | 0  | FIRational::FIRational(float value) { | 
70  | 0  |   if (value == (float)((LONG)value)) { | 
71  | 0  |      _numerator = (LONG)value;  | 
72  | 0  |      _denominator = 1L;  | 
73  | 0  |   } else { | 
74  | 0  |     int k, count;  | 
75  | 0  |     LONG n[4];  | 
76  |  | 
  | 
77  | 0  |     float x = fabs(value);  | 
78  | 0  |     int sign = (value > 0) ? 1 : -1;  | 
79  |  |  | 
80  |  |     // make a continued-fraction expansion of x  | 
81  | 0  |     count = -1;  | 
82  | 0  |     for(k = 0; k < 4; k++) { | 
83  | 0  |       n[k] = (LONG)floor(x);  | 
84  | 0  |       count++;  | 
85  | 0  |       x -= (float)n[k];  | 
86  | 0  |       if(x == 0) break;  | 
87  | 0  |       x = 1 / x;  | 
88  | 0  |     }  | 
89  |  |     // compute the rational  | 
90  | 0  |     _numerator = 1;  | 
91  | 0  |     _denominator = n[count];  | 
92  |  | 
  | 
93  | 0  |     for(int i = count - 1; i >= 0; i--) { | 
94  | 0  |       if(n[i] == 0) break;  | 
95  | 0  |       LONG _num = (n[i] * _numerator + _denominator);  | 
96  | 0  |       LONG _den = _numerator;  | 
97  | 0  |       _numerator = _num;  | 
98  | 0  |       _denominator = _den;  | 
99  | 0  |     }  | 
100  | 0  |     _numerator *= sign;  | 
101  | 0  |   }  | 
102  | 0  | }  | 
103  |  |  | 
104  |  | /// Copy constructor  | 
105  | 0  | FIRational::FIRational (const FIRational& r) { | 
106  | 0  |   initialize(r._numerator, r._denominator);  | 
107  | 0  | }  | 
108  |  |  | 
109  |  | /// Destructor  | 
110  | 0  | FIRational::~FIRational() { | 
111  | 0  | }  | 
112  |  |  | 
113  |  | /// Assignement operator  | 
114  | 0  | FIRational& FIRational::operator=(FIRational& r) { | 
115  | 0  |   if(this != &r) { | 
116  | 0  |     initialize(r._numerator, r._denominator);  | 
117  | 0  |   }  | 
118  | 0  |   return *this;  | 
119  | 0  | }  | 
120  |  |  | 
121  |  | /// Get the numerator  | 
122  | 0  | LONG FIRational::getNumerator() { | 
123  | 0  |   return _numerator;  | 
124  | 0  | }  | 
125  |  |  | 
126  |  | /// Get the denominator  | 
127  | 0  | LONG FIRational::getDenominator() { | 
128  | 0  |   return _denominator;  | 
129  | 0  | }  | 
130  |  |  | 
131  |  | /// Calculate GCD  | 
132  | 0  | LONG FIRational::gcd(LONG a, LONG b) { | 
133  | 0  |   LONG temp;  | 
134  | 0  |   while (b) {   // While non-zero value | 
135  | 0  |     temp = b; // Save current value  | 
136  | 0  |     b = a % b;  // Assign remainder of division  | 
137  | 0  |     a = temp; // Copy old value  | 
138  | 0  |   }  | 
139  | 0  |   return a;   // Return GCD of numbers  | 
140  | 0  | }  | 
141  |  |  | 
142  |  | /// Normalize numerator / denominator   | 
143  | 0  | void FIRational::normalize() { | 
144  | 0  |   if (_numerator != 1 && _denominator != 1) { // Is there something to do? | 
145  |  |      // Calculate GCD  | 
146  | 0  |     LONG common = gcd(_numerator, _denominator);  | 
147  | 0  |     if (common != 1) { // If GCD is not one       | 
148  | 0  |       _numerator /= common; // Calculate new numerator  | 
149  | 0  |       _denominator /= common; // Calculate new denominator  | 
150  | 0  |     }  | 
151  | 0  |   }  | 
152  | 0  |   if(_denominator < 0) { // If sign is in denominator | 
153  | 0  |     _numerator *= -1; // Multiply num and den by -1  | 
154  | 0  |     _denominator *= -1; // To keep sign in numerator  | 
155  | 0  |   }  | 
156  | 0  | }  | 
157  |  |  | 
158  |  | /// Checks if this rational number is an Integer, either positive or negative  | 
159  | 0  | BOOL FIRational::isInteger() { | 
160  | 0  |   if(_denominator == 1 || (_denominator != 0 && (_numerator % _denominator == 0)) || (_denominator == 0 && _numerator == 0))  | 
161  | 0  |     return TRUE;  | 
162  | 0  |   return FALSE;  | 
163  | 0  | }  | 
164  |  |  | 
165  |  | /// Convert as "numerator/denominator"  | 
166  | 0  | std::string FIRational::toString() { | 
167  | 0  |   std::ostringstream s;  | 
168  | 0  |   if(isInteger()) { | 
169  | 0  |     s << intValue();  | 
170  | 0  |   } else { | 
171  | 0  |     s << _numerator << "/" << _denominator;  | 
172  | 0  |   }  | 
173  | 0  |   return s.str();  | 
174  | 0  | }  | 
175  |  |  | 
176  |  |  |