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

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