summaryrefslogtreecommitdiff
path: root/plugins/FreeImage/Source/Metadata/FIRational.cpp
blob: d383c8d38fe2ee60f12dca7a439b995522683002 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
// ==========================================================
// Helper class for rational numbers
//
// Design and implementation by
// - Hervé Drolon <drolon@infonie.fr>
//
// This file is part of FreeImage 3
//
// COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
// THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE
// OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED
// CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT
// THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY
// SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL
// PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER
// THIS DISCLAIMER.
//
// Use at your own risk!
// ==========================================================

#include "FreeImage.h"
#include "Utilities.h"
#include "FIRational.h"

/// Initialize and normalize a rational number
void FIRational::initialize(LONG n, LONG d) {
	if(d) {
		_numerator = n;
		_denominator = d;
		// normalize rational
		normalize();
	} else {
		_numerator = 0;
		_denominator = 0;
	}
}

/// Default constructor
FIRational::FIRational() {
	_numerator = 0;
	_denominator = 0;
}

/// Constructor with longs
FIRational::FIRational(LONG n, LONG d) {
	initialize(n, d);
}

/// Constructor with FITAG
FIRational::FIRational(const FITAG *tag) {
	switch(FreeImage_GetTagType((FITAG*)tag)) {
		case FIDT_RATIONAL:		// 64-bit unsigned fraction 
		{
			DWORD *pvalue = (DWORD*)FreeImage_GetTagValue((FITAG*)tag);
			initialize((LONG)pvalue[0], (LONG)pvalue[1]);
			break;
		}

		case FIDT_SRATIONAL:	// 64-bit signed fraction 
		{
			LONG *pvalue = (LONG*)FreeImage_GetTagValue((FITAG*)tag);
			initialize((LONG)pvalue[0], (LONG)pvalue[1]);
			break;
		}
	}
}

FIRational::FIRational(float value) {
	if (value == (float)((LONG)value)) {
	   _numerator = (LONG)value;
	   _denominator = 1L;
	} else {
		int k, count;
		LONG n[4];

		float x = fabs(value);
		int sign = (value > 0) ? 1 : -1;

		// make a continued-fraction expansion of x
		count = -1;
		for(k = 0; k < 4; k++) {
			n[k] = (LONG)floor(x);
			count++;
			x -= (float)n[k];
			if(x == 0) break;
			x = 1 / x;
		}
		// compute the rational
		_numerator = 1;
		_denominator = n[count];

		for(int i = count - 1; i >= 0; i--) {
			if(n[i] == 0) break;
			LONG _num = (n[i] * _numerator + _denominator);
			LONG _den = _numerator;
			_numerator = _num;
			_denominator = _den;
		}
		_numerator *= sign;
	}
}

/// Copy constructor
FIRational::FIRational (const FIRational& r) {
	initialize(r._numerator, r._denominator);
}

/// Destructor
FIRational::~FIRational() {
}

/// Assignement operator
FIRational& FIRational::operator=(FIRational& r) {
	if(this != &r) {
		initialize(r._numerator, r._denominator);
	}
	return *this;
}

/// Get the numerator
LONG FIRational::getNumerator() {
	return _numerator;
}

/// Get the denominator
LONG FIRational::getDenominator() {
	return _denominator;
}

/// Calculate GCD
LONG FIRational::gcd(LONG a, LONG b) {
	LONG temp;
	while (b) {		// While non-zero value
		temp = b;	// Save current value
		b = a % b;	// Assign remainder of division
		a = temp;	// Copy old value
	}
	return a;		// Return GCD of numbers
}

/// Normalize numerator / denominator 
void FIRational::normalize() {
	if (_numerator != 1 && _denominator != 1) {	// Is there something to do?
		 // Calculate GCD
		LONG common = gcd(_numerator, _denominator);
		if (common != 1) { // If GCD is not one			
			_numerator /= common;	// Calculate new numerator
			_denominator /= common;	// Calculate new denominator
		}
	}
	if(_denominator < 0) {	// If sign is in denominator
		_numerator *= -1;	// Multiply num and den by -1
		_denominator *= -1;	// To keep sign in numerator
	}
}

/// Checks if this rational number is an Integer, either positive or negative
BOOL FIRational::isInteger() {
	if(_denominator == 1 || (_denominator != 0 && (_numerator % _denominator == 0)) || (_denominator == 0 && _numerator == 0))
		return TRUE;
	return FALSE;
}

/// Convert as "numerator/denominator"
std::string FIRational::toString() {
	std::ostringstream s;
	if(isInteger()) {
		s << intValue();
	} else {
		s << _numerator << "/" << _denominator;
	}
	return s.str();
}