PageRenderTime 44ms CodeModel.GetById 2ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 0ms

/src/FreeImage/Source/Metadata/FIRational.cpp

https://bitbucket.org/cabalistic/ogredeps/
C++ | 176 lines | 118 code | 21 blank | 37 comment | 33 complexity | eaac6594f3509112f1ee1b536a78e608 MD5 | raw file
  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
 27void 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
 40FIRational::FIRational() {
 41	_numerator = 0;
 42	_denominator = 0;
 43}
 44
 45/// Constructor with longs
 46FIRational::FIRational(LONG n, LONG d) {
 47	initialize(n, d);
 48}
 49
 50/// Constructor with FITAG
 51FIRational::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
 69FIRational::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
105FIRational::FIRational (const FIRational& r) {
106	initialize(r._numerator, r._denominator);
107}
108
109/// Destructor
110FIRational::~FIRational() {
111}
112
113/// Assignement operator
114FIRational& FIRational::operator=(FIRational& r) {
115	if(this != &r) {
116		initialize(r._numerator, r._denominator);
117	}
118	return *this;
119}
120
121/// Get the numerator
122LONG FIRational::getNumerator() {
123	return _numerator;
124}
125
126/// Get the denominator
127LONG FIRational::getDenominator() {
128	return _denominator;
129}
130
131/// Calculate GCD
132LONG 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 
143void 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
159BOOL 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"
166std::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