1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
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.
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 )
44 while ( nVal1
!= nVal2
)
62 static void Reduce( BigInt
&rVal1
, BigInt
&rVal2
)
69 if ( nA
.IsOne() || nB
.IsOne() || nA
.IsZero() || nB
.IsZero() )
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
)
108 if ( nDenominator
< 0 )
110 nDenominator
= -nDenominator
;
111 nNumerator
= -nNumerator
;
114 // Reduce through GCD
115 long n
= GetGGT( nNumerator
, nDenominator
);
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
)
126 long nMAX
= LONG_MAX
/ 10;
128 if ( dVal
> LONG_MAX
|| dVal
< LONG_MIN
)
135 while ( std::abs( (long)dVal
) < nMAX
&& nDen
< nMAX
)
140 nNumerator
= (long)dVal
;
143 // Reduce through GCD
144 long n
= GetGGT( nNumerator
, nDenominator
);
149 Fraction::operator double() const
151 if ( nDenominator
> 0 )
152 return (double)nNumerator
/ (double)nDenominator
;
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() )
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
);
180 BigInt
nD( nDenominator
);
181 nD
*= BigInt( rVal
.nDenominator
);
185 if ( nN
.bIsBig
|| nD
.bIsBig
)
192 nNumerator
= (long)nN
,
193 nDenominator
= (long)nD
;
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() )
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
);
222 BigInt
nD( nDenominator
);
223 nD
*= BigInt( rVal
.nDenominator
);
227 if ( nN
.bIsBig
|| nD
.bIsBig
)
234 nNumerator
= (long)nN
,
235 nDenominator
= (long)nD
;
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() )
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
)
271 nNumerator
= (long)nN
,
272 nDenominator
= (long)nD
;
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() )
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
)
308 nNumerator
= (long)nN
,
309 nDenominator
= (long)nD
;
310 if ( nDenominator
< 0 )
312 nDenominator
= -nDenominator
;
313 nNumerator
= -nNumerator
;
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;
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 );
351 #if SAL_TYPES_SIZEOFLONG == 4
353 #elif SAL_TYPES_SIZEOFLONG == 8
354 nNum
|= ( nNum
>> 32 );
356 if ( nNum
& 0x80000000 )
358 nNumber
= sal_uInt32( nNum
>> 32 );
365 nNumber
= sal_uInt32( nNum
& 0xFFFFFFFF );
367 #error "Unknown size of long!"
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
)
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
);
423 if ( !nMul
|| !nDiv
)
425 // Return without reduction
426 OSL_FAIL( "Oops, we reduced too much..." );
431 long n1
= GetGGT( nMul
, nDiv
);
438 nNumerator
= bNeg
? -long( nMul
): long( nMul
);
442 bool operator == ( const Fraction
& rVal1
, const Fraction
& rVal2
)
444 if ( !rVal1
.IsValid() || !rVal2
.IsValid() )
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() )
459 BigInt
nN( rVal1
.nNumerator
);
460 nN
*= BigInt( rVal2
.nDenominator
);
461 BigInt
nD( rVal1
.nDenominator
);
462 nD
*= BigInt( rVal2
.nNumerator
);
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() )
475 BigInt
nN( rVal1
.nNumerator
);
476 nN
*= BigInt( rVal2
.nDenominator
);
477 BigInt
nD( rVal1
.nDenominator
);
478 nD
*= BigInt( rVal2
.nNumerator
);
483 SvStream
& operator >> ( SvStream
& rIStream
, Fraction
& rFract
)
485 //fdo#39428 SvStream no longer supports operator>>(long&)
488 rFract
.nNumerator
= nTmp
;
490 rFract
.nDenominator
= nTmp
;
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
);
502 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */