LCOV - code coverage report
Current view: top level - libreoffice/tools/source/generic - fract.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 81 203 39.9 %
Date: 2012-12-27 Functions: 9 16 56.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       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/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      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 .
      18             :  */
      19             : 
      20             : #include <limits.h>
      21             : #include <tools/debug.hxx>
      22             : #include <tools/fract.hxx>
      23             : #include <tools/stream.hxx>
      24             : #include <tools/bigint.hxx>
      25             : 
      26             : /** Compute greates common divisor using Euclidian algorithm
      27             : 
      28             :     As the algorithm works on positive values only, the absolute value
      29             :     of each parameter is used.
      30             : 
      31             :     @param nVal1
      32             :     @param nVal2
      33             : 
      34             :     @note: If one parameter is {0,1}, GetGGT returns 1.
      35             : */
      36      712397 : static long GetGGT( long nVal1, long nVal2 )
      37             : {
      38      712397 :     nVal1 = Abs( nVal1 );
      39      712397 :     nVal2 = Abs( nVal2 );
      40             : 
      41      712397 :     if ( nVal1 <= 1 || nVal2 <= 1 )
      42      669261 :         return 1;
      43             : 
      44      184240 :     while ( nVal1 != nVal2 )
      45             :     {
      46      131563 :         if ( nVal1 > nVal2 )
      47             :         {
      48       66981 :             nVal1 %= nVal2;
      49       66981 :             if ( nVal1 == 0 )
      50       25350 :                 return nVal2;
      51             :         }
      52             :         else
      53             :         {
      54       64582 :             nVal2 %= nVal1;
      55       64582 :             if ( nVal2 == 0 )
      56        8245 :                 return nVal1;
      57             :         }
      58             :     }
      59        9541 :     return nVal1;
      60             : }
      61             : 
      62           0 : static void Reduce( BigInt &rVal1, BigInt &rVal2 )
      63             : {
      64           0 :     BigInt nA( rVal1 );
      65           0 :     BigInt nB( rVal2 );
      66           0 :     nA.Abs();
      67           0 :     nB.Abs();
      68             : 
      69           0 :     if ( nA.IsOne() || nB.IsOne() || nA.IsZero() || nB.IsZero() )
      70             :         return;
      71             : 
      72           0 :     while ( nA != nB )
      73             :     {
      74           0 :         if ( nA > nB )
      75             :         {
      76           0 :             nA %= nB;
      77           0 :             if ( nA.IsZero() )
      78             :             {
      79           0 :                 rVal1 /= nB;
      80           0 :                 rVal2 /= nB;
      81             :                 return;
      82             :             }
      83             :         }
      84             :         else
      85             :         {
      86           0 :             nB %= nA;
      87           0 :             if ( nB.IsZero() )
      88             :             {
      89           0 :                 rVal1 /= nA;
      90           0 :                 rVal2 /= nA;
      91             :                 return;
      92             :             }
      93             :         }
      94             :     }
      95             : 
      96           0 :     rVal1 /= nA;
      97           0 :     rVal2 /= nB;
      98             : }
      99             : 
     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      370825 : Fraction::Fraction( long nNum, long nDen )
     105             : {
     106      370825 :     nNumerator = nNum;
     107      370825 :     nDenominator = nDen;
     108      370825 :     if ( nDenominator < 0 )
     109             :     {
     110        5504 :         nDenominator = -nDenominator;
     111        5504 :         nNumerator   = -nNumerator;
     112             :     }
     113             : 
     114             :     // Reduce through GCD
     115      370825 :     long n = GetGGT( nNumerator, nDenominator );
     116      370825 :     nNumerator   /= n;
     117      370825 :     nDenominator /= n;
     118      370825 : }
     119             : 
     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          12 : Fraction::Fraction( double dVal )
     124             : {
     125          12 :     long nDen = 1;
     126          12 :     long nMAX = LONG_MAX / 10;
     127             : 
     128          12 :     if ( dVal > LONG_MAX || dVal < LONG_MIN )
     129             :     {
     130           0 :         nNumerator   = 0;
     131           0 :         nDenominator = -1;
     132          12 :         return;
     133             :     }
     134             : 
     135         114 :     while ( Abs( (long)dVal ) < nMAX && nDen < nMAX )
     136             :     {
     137          90 :         dVal *= 10;
     138          90 :         nDen *= 10;
     139             :     }
     140          12 :     nNumerator   = (long)dVal;
     141          12 :     nDenominator = nDen;
     142             : 
     143             :     // Reduce through GCD
     144          12 :     long n = GetGGT( nNumerator, nDenominator );
     145          12 :     nNumerator   /= n;
     146          12 :     nDenominator /= n;
     147             : }
     148             : 
     149        6740 : Fraction::operator double() const
     150             : {
     151        6740 :     if ( nDenominator > 0 )
     152        6740 :         return (double)nNumerator / (double)nDenominator;
     153             :     else
     154           0 :         return (double)0;
     155             : }
     156             : 
     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           0 : Fraction& Fraction::operator += ( const Fraction& rVal )
     164             : {
     165           0 :     if ( !rVal.IsValid() )
     166             :     {
     167           0 :         nNumerator   = 0;
     168           0 :         nDenominator = -1;
     169             :     }
     170           0 :     if ( !IsValid() )
     171           0 :         return *this;
     172             : 
     173             :     // (a/b) + (c/d) = ( (a*d) + (c*b) ) / (b*d)
     174           0 :     BigInt nN( nNumerator );
     175           0 :     nN *= BigInt( rVal.nDenominator );
     176           0 :     BigInt nW1Temp( nDenominator );
     177           0 :     nW1Temp *= BigInt( rVal.nNumerator );
     178           0 :     nN += nW1Temp;
     179             : 
     180           0 :     BigInt nD( nDenominator );
     181           0 :     nD *= BigInt( rVal.nDenominator );
     182             : 
     183           0 :     Reduce( nN, nD );
     184             : 
     185           0 :     if ( nN.bIsBig || nD.bIsBig )
     186             :     {
     187           0 :         nNumerator   = 0;
     188           0 :         nDenominator = -1;
     189             :     }
     190             :     else
     191             :     {
     192           0 :         nNumerator   = (long)nN,
     193           0 :         nDenominator = (long)nD;
     194             :     }
     195             : 
     196           0 :     return *this;
     197             : }
     198             : 
     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           0 : Fraction& Fraction::operator -= ( const Fraction& rVal )
     206             : {
     207           0 :     if ( !rVal.IsValid() )
     208             :     {
     209           0 :         nNumerator   = 0;
     210           0 :         nDenominator = -1;
     211             :     }
     212           0 :     if ( !IsValid() )
     213           0 :         return *this;
     214             : 
     215             :     // (a/b) - (c/d) = ( (a*d) - (c*b) ) / (b*d)
     216           0 :     BigInt nN( nNumerator );
     217           0 :     nN *= BigInt( rVal.nDenominator );
     218           0 :     BigInt nW1Temp( nDenominator );
     219           0 :     nW1Temp *= BigInt( rVal.nNumerator );
     220           0 :     nN -= nW1Temp;
     221             : 
     222           0 :     BigInt nD( nDenominator );
     223           0 :     nD *= BigInt( rVal.nDenominator );
     224             : 
     225           0 :     Reduce( nN, nD );
     226             : 
     227           0 :     if ( nN.bIsBig || nD.bIsBig )
     228             :     {
     229           0 :         nNumerator   = 0;
     230           0 :         nDenominator = -1;
     231             :     }
     232             :     else
     233             :     {
     234           0 :         nNumerator   = (long)nN,
     235           0 :         nDenominator = (long)nD;
     236             :     }
     237             : 
     238           0 :     return *this;
     239             : }
     240             : 
     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      169802 : Fraction& Fraction::operator *= ( const Fraction& rVal )
     248             : {
     249      169802 :     if ( !rVal.IsValid() )
     250             :     {
     251           0 :         nNumerator   = 0;
     252           0 :         nDenominator = -1;
     253             :     }
     254      169802 :     if ( !IsValid() )
     255           0 :         return *this;
     256             : 
     257      169802 :     long nGGT1 = GetGGT( nNumerator, rVal.nDenominator );
     258      169802 :     long nGGT2 = GetGGT( rVal.nNumerator, nDenominator );
     259      169802 :     BigInt nN( nNumerator / nGGT1 );
     260      169802 :     nN *= BigInt( rVal.nNumerator / nGGT2 );
     261      169802 :     BigInt nD( nDenominator / nGGT2 );
     262      169802 :     nD *= BigInt( rVal.nDenominator / nGGT1 );
     263             : 
     264      169802 :     if ( nN.bIsBig || nD.bIsBig )
     265             :     {
     266           0 :         nNumerator   = 0;
     267           0 :         nDenominator = -1;
     268             :     }
     269             :     else
     270             :     {
     271      169802 :         nNumerator   = (long)nN,
     272      169802 :         nDenominator = (long)nD;
     273             :     }
     274             : 
     275      169802 :     return *this;
     276             : }
     277             : 
     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         978 : Fraction& Fraction::operator /= ( const Fraction& rVal )
     285             : {
     286         978 :     if ( !rVal.IsValid() )
     287             :     {
     288           0 :         nNumerator   = 0;
     289           0 :         nDenominator = -1;
     290             :     }
     291         978 :     if ( !IsValid() )
     292           0 :         return *this;
     293             : 
     294         978 :     long nGGT1 = GetGGT( nNumerator, rVal.nNumerator );
     295         978 :     long nGGT2 = GetGGT( rVal.nDenominator, nDenominator );
     296         978 :     BigInt nN( nNumerator / nGGT1 );
     297         978 :     nN *= BigInt( rVal.nDenominator / nGGT2 );
     298         978 :     BigInt nD( nDenominator / nGGT2 );
     299         978 :     nD *= BigInt( rVal.nNumerator / nGGT1 );
     300             : 
     301         978 :     if ( nN.bIsBig || nD.bIsBig )
     302             :     {
     303           0 :         nNumerator   = 0;
     304           0 :         nDenominator = -1;
     305             :     }
     306             :     else
     307             :     {
     308         978 :         nNumerator   = (long)nN,
     309         978 :         nDenominator = (long)nD;
     310         978 :         if ( nDenominator < 0 )
     311             :         {
     312           0 :             nDenominator = -nDenominator;
     313           0 :             nNumerator   = -nNumerator;
     314             :         }
     315             :     }
     316             : 
     317         978 :     return *this;
     318             : }
     319             : 
     320             : // Similar to clz_table that can be googled
     321             : const char nbits_table[32] =
     322             : {
     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
     327             : };
     328             : 
     329           0 : static int impl_NumberOfBits( unsigned long nNum )
     330             : {
     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           0 :     const sal_uInt32 nDeBruijn = 0x7DCD629;
     337             : 
     338           0 :     if ( nNum == 0 )
     339           0 :         return 0;
     340             : 
     341             :     // Get it to form like 0000001111111111b
     342           0 :     nNum |= ( nNum >>  1 );
     343           0 :     nNum |= ( nNum >>  2 );
     344           0 :     nNum |= ( nNum >>  4 );
     345           0 :     nNum |= ( nNum >>  8 );
     346           0 :     nNum |= ( nNum >> 16 );
     347             : 
     348             :     sal_uInt32 nNumber;
     349           0 :     int nBonus = 0;
     350             : 
     351             : #if SAL_TYPES_SIZEOFLONG == 4
     352           0 :     nNumber = nNum;
     353             : #elif SAL_TYPES_SIZEOFLONG == 8
     354             :     nNum |= ( nNum >> 32 );
     355             : 
     356             :     if ( nNum & 0x80000000 )
     357             :     {
     358             :         nNumber = sal_uInt32( nNum >> 32 );
     359             :         nBonus = 32;
     360             : 
     361             :         if ( nNumber == 0 )
     362             :             return 32;
     363             :     }
     364             :     else
     365             :         nNumber = sal_uInt32( nNum & 0xFFFFFFFF );
     366             : #else
     367             : #error "Unknown size of long!"
     368             : #endif
     369             : 
     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           0 :     nNumber = nDeBruijn + ( nDeBruijn * nNumber );
     378             : 
     379             :     // 5-bit window indexes the result
     380           0 :     return ( nbits_table[nNumber >> 27] ) + nBonus;
     381             : }
     382             : 
     383             : /** Inaccurate cancellation for a fraction.
     384             : 
     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.
     388             : 
     389             :     @param nSignificantBits denotes, how many significant binary
     390             :     digits to maintain, in both nominator and denominator.
     391             : 
     392             :     @example ReduceInaccurate(8) has an error <1% [1/2^(8-1)] - the
     393             :     largest error occurs with the following pair of values:
     394             : 
     395             :     binary    1000000011111111111111111111111b/1000000000000000000000000000000b
     396             :     =         1082130431/1073741824
     397             :     = approx. 1.007812499
     398             : 
     399             :     A ReduceInaccurate(8) yields 1/1.
     400             : */
     401           0 : void Fraction::ReduceInaccurate( unsigned nSignificantBits )
     402             : {
     403           0 :     if ( !nNumerator || !nDenominator )
     404           0 :         return;
     405             : 
     406             :     // Count with unsigned longs only
     407           0 :     const bool bNeg = ( nNumerator < 0 );
     408           0 :     unsigned long nMul = (unsigned long)( bNeg? -nNumerator: nNumerator );
     409           0 :     unsigned long nDiv = (unsigned long)( nDenominator );
     410             : 
     411             :     DBG_ASSERT(nSignificantBits<65, "More than 64 bit of significance is overkill!");
     412             : 
     413             :     // How much bits can we lose?
     414           0 :     const int nMulBitsToLose = Max( ( impl_NumberOfBits( nMul ) - int( nSignificantBits ) ), 0 );
     415           0 :     const int nDivBitsToLose = Max( ( impl_NumberOfBits( nDiv ) - int( nSignificantBits ) ), 0 );
     416             : 
     417           0 :     const int nToLose = Min( nMulBitsToLose, nDivBitsToLose );
     418             : 
     419             :     // Remove the bits
     420           0 :     nMul >>= nToLose;
     421           0 :     nDiv >>= nToLose;
     422             : 
     423           0 :     if ( !nMul || !nDiv )
     424             :     {
     425             :         // Return without reduction
     426             :         OSL_FAIL( "Oops, we reduced too much..." );
     427           0 :         return;
     428             :     }
     429             : 
     430             :     // Reduce
     431           0 :     long n1 = GetGGT( nMul, nDiv );
     432           0 :     if ( n1 != 1 )
     433             :     {
     434           0 :         nMul /= n1;
     435           0 :         nDiv /= n1;
     436             :     }
     437             : 
     438           0 :     nNumerator = bNeg? -long( nMul ): long( nMul );
     439           0 :     nDenominator = nDiv;
     440             : }
     441             : 
     442       19459 : bool operator == ( const Fraction& rVal1, const Fraction& rVal2 )
     443             : {
     444       19459 :     if ( !rVal1.IsValid() || !rVal2.IsValid() )
     445           0 :         return false;
     446             : 
     447             :     return rVal1.nNumerator == rVal2.nNumerator
     448       19459 :            && rVal1.nDenominator == rVal2.nDenominator;
     449             : }
     450             : 
     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           0 : bool operator < ( const Fraction& rVal1, const Fraction& rVal2 )
     455             : {
     456           0 :     if ( !rVal1.IsValid() || !rVal2.IsValid() )
     457           0 :         return false;
     458             : 
     459           0 :     BigInt nN( rVal1.nNumerator );
     460           0 :     nN *= BigInt( rVal2.nDenominator );
     461           0 :     BigInt nD( rVal1.nDenominator );
     462           0 :     nD *= BigInt( rVal2.nNumerator );
     463             : 
     464           0 :     return nN < nD;
     465             : }
     466             : 
     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           0 : bool operator > ( const Fraction& rVal1, const Fraction& rVal2 )
     471             : {
     472           0 :     if ( !rVal1.IsValid() || !rVal2.IsValid() )
     473           0 :         return false;
     474             : 
     475           0 :     BigInt nN( rVal1.nNumerator );
     476           0 :     nN *= BigInt( rVal2.nDenominator );
     477           0 :     BigInt nD( rVal1.nDenominator);
     478           0 :     nD *= BigInt( rVal2.nNumerator );
     479             : 
     480           0 :     return nN > nD;
     481             : }
     482             : 
     483        4578 : SvStream& operator >> ( SvStream& rIStream, Fraction& rFract )
     484             : {
     485             :     //fdo#39428 SvStream no longer supports operator>>(long&)
     486        4578 :     sal_Int32 nTmp(0);
     487        4578 :     rIStream >> nTmp;
     488        4578 :     rFract.nNumerator = nTmp;
     489        4578 :     rIStream >> nTmp;
     490        4578 :     rFract.nDenominator = nTmp;
     491        4578 :     return rIStream;
     492             : }
     493             : 
     494        4908 : SvStream& operator << ( SvStream& rOStream, const Fraction& rFract )
     495             : {
     496             :     //fdo#39428 SvStream no longer supports operator<<(long)
     497        4908 :     rOStream << sal::static_int_cast<sal_Int32>(rFract.nNumerator);
     498        4908 :     rOStream << sal::static_int_cast<sal_Int32>(rFract.nDenominator);
     499        4908 :     return rOStream;
     500             : }
     501             : 
     502             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10