Coverage Report

Created: 2023-12-08 06:53

/src/freeimage-svn/FreeImage/trunk/Source/Metadata/FIRational.cpp
Line
Count
Source (jump to first uncovered line)
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