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