bump product version to 4.1.6.2
[LibreOffice.git] / tools / source / generic / fract.cxx
blobcad06a76e72ff57f0ac4a1942e24474437eaab1f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <limits.h>
21 #include <tools/debug.hxx>
22 #include <tools/fract.hxx>
23 #include <tools/stream.hxx>
24 #include <tools/bigint.hxx>
26 /** Compute greates common divisor using Euclidian algorithm
28 As the algorithm works on positive values only, the absolute value
29 of each parameter is used.
31 @param nVal1
32 @param nVal2
34 @note: If one parameter is {0,1}, GetGGT returns 1.
36 static long GetGGT( long nVal1, long nVal2 )
38 nVal1 = std::abs( nVal1 );
39 nVal2 = std::abs( nVal2 );
41 if ( nVal1 <= 1 || nVal2 <= 1 )
42 return 1;
44 while ( nVal1 != nVal2 )
46 if ( nVal1 > nVal2 )
48 nVal1 %= nVal2;
49 if ( nVal1 == 0 )
50 return nVal2;
52 else
54 nVal2 %= nVal1;
55 if ( nVal2 == 0 )
56 return nVal1;
59 return nVal1;
62 static void Reduce( BigInt &rVal1, BigInt &rVal2 )
64 BigInt nA( rVal1 );
65 BigInt nB( rVal2 );
66 nA.Abs();
67 nB.Abs();
69 if ( nA.IsOne() || nB.IsOne() || nA.IsZero() || nB.IsZero() )
70 return;
72 while ( nA != nB )
74 if ( nA > nB )
76 nA %= nB;
77 if ( nA.IsZero() )
79 rVal1 /= nB;
80 rVal2 /= nB;
81 return;
84 else
86 nB %= nA;
87 if ( nB.IsZero() )
89 rVal1 /= nA;
90 rVal2 /= nA;
91 return;
96 rVal1 /= nA;
97 rVal2 /= nB;
100 // Initialized by setting nNum as nominator and nDen as denominator
101 // Negative values in the denominator are invalid and cause the
102 // inversion of both nominator and denominator signs
103 // in order to return the correct value.
104 Fraction::Fraction( long nNum, long nDen )
106 nNumerator = nNum;
107 nDenominator = nDen;
108 if ( nDenominator < 0 )
110 nDenominator = -nDenominator;
111 nNumerator = -nNumerator;
114 // Reduce through GCD
115 long n = GetGGT( nNumerator, nDenominator );
116 nNumerator /= n;
117 nDenominator /= n;
120 // If dVal > LONG_MAX, the fraction is set as invalid.
121 // Otherwise, dVal and denominator are multiplied with 10, until one of them
122 // is larger than (LONG_MAX / 10) and the fraction is reduced with GCD
123 Fraction::Fraction( double dVal )
125 long nDen = 1;
126 long nMAX = LONG_MAX / 10;
128 if ( dVal > LONG_MAX || dVal < LONG_MIN )
130 nNumerator = 0;
131 nDenominator = -1;
132 return;
135 while ( std::abs( (long)dVal ) < nMAX && nDen < nMAX )
137 dVal *= 10;
138 nDen *= 10;
140 nNumerator = (long)dVal;
141 nDenominator = nDen;
143 // Reduce through GCD
144 long n = GetGGT( nNumerator, nDenominator );
145 nNumerator /= n;
146 nDenominator /= n;
149 Fraction::operator double() const
151 if ( nDenominator > 0 )
152 return (double)nNumerator / (double)nDenominator;
153 else
154 return (double)0;
157 // This methods first validates both values.
158 // If one of the arguments is invalid, the whole operation is invalid.
159 // For addition both fractions are extended to match the denominator,
160 // then nominators are added and reduced (through GCD).
161 // Internal datatype for computation is SLong to detect overflows,
162 // which cause the operation to be marked as invalid
163 Fraction& Fraction::operator += ( const Fraction& rVal )
165 if ( !rVal.IsValid() )
167 nNumerator = 0;
168 nDenominator = -1;
170 if ( !IsValid() )
171 return *this;
173 // (a/b) + (c/d) = ( (a*d) + (c*b) ) / (b*d)
174 BigInt nN( nNumerator );
175 nN *= BigInt( rVal.nDenominator );
176 BigInt nW1Temp( nDenominator );
177 nW1Temp *= BigInt( rVal.nNumerator );
178 nN += nW1Temp;
180 BigInt nD( nDenominator );
181 nD *= BigInt( rVal.nDenominator );
183 Reduce( nN, nD );
185 if ( nN.bIsBig || nD.bIsBig )
187 nNumerator = 0;
188 nDenominator = -1;
190 else
192 nNumerator = (long)nN,
193 nDenominator = (long)nD;
196 return *this;
199 // This methods first validates both values.
200 // If one of the arguments is invalid, the whole operation is invalid.
201 // For substraction, both fractions are extended to match the denominator,
202 // then nominators are substracted and reduced (through GCD).
203 // Internal datatype for computation is SLong to detect overflows,
204 // which cause the operation to be marked as invalid
205 Fraction& Fraction::operator -= ( const Fraction& rVal )
207 if ( !rVal.IsValid() )
209 nNumerator = 0;
210 nDenominator = -1;
212 if ( !IsValid() )
213 return *this;
215 // (a/b) - (c/d) = ( (a*d) - (c*b) ) / (b*d)
216 BigInt nN( nNumerator );
217 nN *= BigInt( rVal.nDenominator );
218 BigInt nW1Temp( nDenominator );
219 nW1Temp *= BigInt( rVal.nNumerator );
220 nN -= nW1Temp;
222 BigInt nD( nDenominator );
223 nD *= BigInt( rVal.nDenominator );
225 Reduce( nN, nD );
227 if ( nN.bIsBig || nD.bIsBig )
229 nNumerator = 0;
230 nDenominator = -1;
232 else
234 nNumerator = (long)nN,
235 nDenominator = (long)nD;
238 return *this;
241 // This methods first validates both values.
242 // If one of the arguments is invalid, the whole operation is invalid.
243 // For mutliplication, nominator and denominators are first reduced
244 // (through GCD), and then multiplied.
245 // Internal datatype for computation is BigInt to detect overflows,
246 // which cause the operation to be marked as invalid
247 Fraction& Fraction::operator *= ( const Fraction& rVal )
249 if ( !rVal.IsValid() )
251 nNumerator = 0;
252 nDenominator = -1;
254 if ( !IsValid() )
255 return *this;
257 long nGGT1 = GetGGT( nNumerator, rVal.nDenominator );
258 long nGGT2 = GetGGT( rVal.nNumerator, nDenominator );
259 BigInt nN( nNumerator / nGGT1 );
260 nN *= BigInt( rVal.nNumerator / nGGT2 );
261 BigInt nD( nDenominator / nGGT2 );
262 nD *= BigInt( rVal.nDenominator / nGGT1 );
264 if ( nN.bIsBig || nD.bIsBig )
266 nNumerator = 0;
267 nDenominator = -1;
269 else
271 nNumerator = (long)nN,
272 nDenominator = (long)nD;
275 return *this;
278 // This methods first validates both values.
279 // If one of the arguments is invalid, the whole operation is invalid.
280 // For dividing a/b, we multiply a with the inverse of b.
281 // To avoid overflows, we first reduce both fractions with GCD.
282 // Internal datatype for computation is BigInt to detect overflows,
283 // which cause the operation to be marked as invalid
284 Fraction& Fraction::operator /= ( const Fraction& rVal )
286 if ( !rVal.IsValid() )
288 nNumerator = 0;
289 nDenominator = -1;
291 if ( !IsValid() )
292 return *this;
294 long nGGT1 = GetGGT( nNumerator, rVal.nNumerator );
295 long nGGT2 = GetGGT( rVal.nDenominator, nDenominator );
296 BigInt nN( nNumerator / nGGT1 );
297 nN *= BigInt( rVal.nDenominator / nGGT2 );
298 BigInt nD( nDenominator / nGGT2 );
299 nD *= BigInt( rVal.nNumerator / nGGT1 );
301 if ( nN.bIsBig || nD.bIsBig )
303 nNumerator = 0;
304 nDenominator = -1;
306 else
308 nNumerator = (long)nN,
309 nDenominator = (long)nD;
310 if ( nDenominator < 0 )
312 nDenominator = -nDenominator;
313 nNumerator = -nNumerator;
317 return *this;
320 // Similar to clz_table that can be googled
321 const char nbits_table[32] =
323 32, 1, 23, 2, 29, 24, 14, 3,
324 30, 27, 25, 18, 20, 15, 10, 4,
325 31, 22, 28, 13, 26, 17, 19, 9,
326 21, 12, 16, 8, 11, 7, 6, 5
329 static int impl_NumberOfBits( unsigned long nNum )
331 // http://en.wikipedia.org/wiki/De_Bruijn_sequence
332 // background paper: Using de Bruijn Sequences to Index a 1 in a
333 // Computer Word (1998) Charles E. Leiserson,
334 // Harald Prokop, Keith H. Randall
335 // (e.g. http://citeseer.ist.psu.edu/leiserson98using.html)
336 const sal_uInt32 nDeBruijn = 0x7DCD629;
338 if ( nNum == 0 )
339 return 0;
341 // Get it to form like 0000001111111111b
342 nNum |= ( nNum >> 1 );
343 nNum |= ( nNum >> 2 );
344 nNum |= ( nNum >> 4 );
345 nNum |= ( nNum >> 8 );
346 nNum |= ( nNum >> 16 );
348 sal_uInt32 nNumber;
349 int nBonus = 0;
351 #if SAL_TYPES_SIZEOFLONG == 4
352 nNumber = nNum;
353 #elif SAL_TYPES_SIZEOFLONG == 8
354 nNum |= ( nNum >> 32 );
356 if ( nNum & 0x80000000 )
358 nNumber = sal_uInt32( nNum >> 32 );
359 nBonus = 32;
361 if ( nNumber == 0 )
362 return 32;
364 else
365 nNumber = sal_uInt32( nNum & 0xFFFFFFFF );
366 #else
367 #error "Unknown size of long!"
368 #endif
370 // De facto shift left of nDeBruijn using multiplication (nNumber
371 // is all ones from topmost bit, thus nDeBruijn + (nDeBruijn *
372 // nNumber) => nDeBruijn * (nNumber+1) clears all those bits to
373 // zero, sets the next bit to one, and thus effectively shift-left
374 // nDeBruijn by lg2(nNumber+1). This generates a distinct 5bit
375 // sequence in the msb for each distinct position of the last
376 // leading 0 bit - that's the property of a de Bruijn number.
377 nNumber = nDeBruijn + ( nDeBruijn * nNumber );
379 // 5-bit window indexes the result
380 return ( nbits_table[nNumber >> 27] ) + nBonus;
383 /** Inaccurate cancellation for a fraction.
385 Clip both nominator and denominator to said number of bits. If
386 either of those already have equal or less number of bits used,
387 this method does nothing.
389 @param nSignificantBits denotes, how many significant binary
390 digits to maintain, in both nominator and denominator.
392 @example ReduceInaccurate(8) has an error <1% [1/2^(8-1)] - the
393 largest error occurs with the following pair of values:
395 binary 1000000011111111111111111111111b/1000000000000000000000000000000b
396 = 1082130431/1073741824
397 = approx. 1.007812499
399 A ReduceInaccurate(8) yields 1/1.
401 void Fraction::ReduceInaccurate( unsigned nSignificantBits )
403 if ( !nNumerator || !nDenominator )
404 return;
406 // Count with unsigned longs only
407 const bool bNeg = ( nNumerator < 0 );
408 unsigned long nMul = (unsigned long)( bNeg? -nNumerator: nNumerator );
409 unsigned long nDiv = (unsigned long)( nDenominator );
411 DBG_ASSERT(nSignificantBits<65, "More than 64 bit of significance is overkill!");
413 // How much bits can we lose?
414 const int nMulBitsToLose = std::max( ( impl_NumberOfBits( nMul ) - int( nSignificantBits ) ), 0 );
415 const int nDivBitsToLose = std::max( ( impl_NumberOfBits( nDiv ) - int( nSignificantBits ) ), 0 );
417 const int nToLose = std::min( nMulBitsToLose, nDivBitsToLose );
419 // Remove the bits
420 nMul >>= nToLose;
421 nDiv >>= nToLose;
423 if ( !nMul || !nDiv )
425 // Return without reduction
426 OSL_FAIL( "Oops, we reduced too much..." );
427 return;
430 // Reduce
431 long n1 = GetGGT( nMul, nDiv );
432 if ( n1 != 1 )
434 nMul /= n1;
435 nDiv /= n1;
438 nNumerator = bNeg? -long( nMul ): long( nMul );
439 nDenominator = nDiv;
442 bool operator == ( const Fraction& rVal1, const Fraction& rVal2 )
444 if ( !rVal1.IsValid() || !rVal2.IsValid() )
445 return false;
447 return rVal1.nNumerator == rVal2.nNumerator
448 && rVal1.nDenominator == rVal2.nDenominator;
451 // This methods first validates and reduces both values.
452 // To compare (a/b) with (c/d), extend denominators (b*d), then return
453 // the result of comparing the nominators (a < c)
454 bool operator < ( const Fraction& rVal1, const Fraction& rVal2 )
456 if ( !rVal1.IsValid() || !rVal2.IsValid() )
457 return false;
459 BigInt nN( rVal1.nNumerator );
460 nN *= BigInt( rVal2.nDenominator );
461 BigInt nD( rVal1.nDenominator );
462 nD *= BigInt( rVal2.nNumerator );
464 return nN < nD;
467 // This methods first validates and reduces both values.
468 // To compare (a/b) with (c/d), extend denominators (b*d), then return
469 // the result of comparing nominators (a > c)
470 bool operator > ( const Fraction& rVal1, const Fraction& rVal2 )
472 if ( !rVal1.IsValid() || !rVal2.IsValid() )
473 return false;
475 BigInt nN( rVal1.nNumerator );
476 nN *= BigInt( rVal2.nDenominator );
477 BigInt nD( rVal1.nDenominator);
478 nD *= BigInt( rVal2.nNumerator );
480 return nN > nD;
483 SvStream& operator >> ( SvStream& rIStream, Fraction& rFract )
485 //fdo#39428 SvStream no longer supports operator>>(long&)
486 sal_Int32 nTmp(0);
487 rIStream >> nTmp;
488 rFract.nNumerator = nTmp;
489 rIStream >> nTmp;
490 rFract.nDenominator = nTmp;
491 return rIStream;
494 SvStream& operator << ( SvStream& rOStream, const Fraction& rFract )
496 //fdo#39428 SvStream no longer supports operator<<(long)
497 rOStream << sal::static_int_cast<sal_Int32>(rFract.nNumerator);
498 rOStream << sal::static_int_cast<sal_Int32>(rFract.nDenominator);
499 return rOStream;
502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */