LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/tools/source/generic - fract.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 127 207 61.4 %
Date: 2013-07-09 Functions: 13 16 81.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 <rtl/ustring.hxx>
      22             : #include <tools/debug.hxx>
      23             : #include <tools/fract.hxx>
      24             : #include <tools/lineend.hxx>
      25             : #include <tools/stream.hxx>
      26             : #include <tools/bigint.hxx>
      27             : 
      28             : /** Compute greates common divisor using Euclidian algorithm
      29             : 
      30             :     As the algorithm works on positive values only, the absolute value
      31             :     of each parameter is used.
      32             : 
      33             :     @param nVal1
      34             :     @param nVal2
      35             : 
      36             :     @note: If one parameter is {0,1}, GetGGT returns 1.
      37             : */
      38     3893146 : static long GetGGT( long nVal1, long nVal2 )
      39             : {
      40     3893146 :     nVal1 = std::abs( nVal1 );
      41     3893146 :     nVal2 = std::abs( nVal2 );
      42             : 
      43     3893146 :     if ( nVal1 <= 1 || nVal2 <= 1 )
      44     3213035 :         return 1;
      45             : 
      46     5690614 :     while ( nVal1 != nVal2 )
      47             :     {
      48     4987099 :         if ( nVal1 > nVal2 )
      49             :         {
      50     2480829 :             nVal1 %= nVal2;
      51     2480829 :             if ( nVal1 == 0 )
      52      373247 :                 return nVal2;
      53             :         }
      54             :         else
      55             :         {
      56     2506270 :             nVal2 %= nVal1;
      57     2506270 :             if ( nVal2 == 0 )
      58      283460 :                 return nVal1;
      59             :         }
      60             :     }
      61       23404 :     return nVal1;
      62             : }
      63             : 
      64           0 : static void Reduce( BigInt &rVal1, BigInt &rVal2 )
      65             : {
      66           0 :     BigInt nA( rVal1 );
      67           0 :     BigInt nB( rVal2 );
      68           0 :     nA.Abs();
      69           0 :     nB.Abs();
      70             : 
      71           0 :     if ( nA.IsOne() || nB.IsOne() || nA.IsZero() || nB.IsZero() )
      72           0 :         return;
      73             : 
      74           0 :     while ( nA != nB )
      75             :     {
      76           0 :         if ( nA > nB )
      77             :         {
      78           0 :             nA %= nB;
      79           0 :             if ( nA.IsZero() )
      80             :             {
      81           0 :                 rVal1 /= nB;
      82           0 :                 rVal2 /= nB;
      83           0 :                 return;
      84             :             }
      85             :         }
      86             :         else
      87             :         {
      88           0 :             nB %= nA;
      89           0 :             if ( nB.IsZero() )
      90             :             {
      91           0 :                 rVal1 /= nA;
      92           0 :                 rVal2 /= nA;
      93           0 :                 return;
      94             :             }
      95             :         }
      96             :     }
      97             : 
      98           0 :     rVal1 /= nA;
      99           0 :     rVal2 /= nB;
     100             : }
     101             : 
     102             : // Initialized by setting nNum as nominator and nDen as denominator
     103             : // Negative values in the denominator are invalid and cause the
     104             : // inversion of both nominator and denominator signs
     105             : // in order to return the correct value.
     106     2062901 : Fraction::Fraction( long nNum, long nDen )
     107             : {
     108     2062901 :     nNumerator = nNum;
     109     2062901 :     nDenominator = nDen;
     110     2062901 :     if ( nDenominator < 0 )
     111             :     {
     112       73890 :         nDenominator = -nDenominator;
     113       73890 :         nNumerator   = -nNumerator;
     114             :     }
     115             : 
     116             :     // Reduce through GCD
     117     2062901 :     long n = GetGGT( nNumerator, nDenominator );
     118     2062901 :     nNumerator   /= n;
     119     2062901 :     nDenominator /= n;
     120     2062901 : }
     121             : 
     122             : // If dVal > LONG_MAX, the fraction is set as invalid.
     123             : // Otherwise, dVal and denominator are multiplied with 10, until one of them
     124             : // is larger than (LONG_MAX / 10) and the fraction is reduced with GCD
     125       12577 : Fraction::Fraction( double dVal )
     126             : {
     127       12577 :     long nDen = 1;
     128       12577 :     long nMAX = LONG_MAX / 10;
     129             : 
     130       12577 :     if ( dVal > LONG_MAX || dVal < LONG_MIN )
     131             :     {
     132           0 :         nNumerator   = 0;
     133           0 :         nDenominator = -1;
     134       12577 :         return;
     135             :     }
     136             : 
     137      138298 :     while ( std::abs( (long)dVal ) < nMAX && nDen < nMAX )
     138             :     {
     139      113144 :         dVal *= 10;
     140      113144 :         nDen *= 10;
     141             :     }
     142       12577 :     nNumerator   = (long)dVal;
     143       12577 :     nDenominator = nDen;
     144             : 
     145             :     // Reduce through GCD
     146       12577 :     long n = GetGGT( nNumerator, nDenominator );
     147       12577 :     nNumerator   /= n;
     148       12577 :     nDenominator /= n;
     149             : }
     150             : 
     151      125463 : Fraction::operator double() const
     152             : {
     153      125463 :     if ( nDenominator > 0 )
     154      125463 :         return (double)nNumerator / (double)nDenominator;
     155             :     else
     156           0 :         return (double)0;
     157             : }
     158             : 
     159             : // This methods first validates both values.
     160             : // If one of the arguments is invalid, the whole operation is invalid.
     161             : // For addition both fractions are extended to match the denominator,
     162             : // then nominators are added and reduced (through GCD).
     163             : // Internal datatype for computation is SLong to detect overflows,
     164             : // which cause the operation to be marked as invalid
     165           0 : Fraction& Fraction::operator += ( const Fraction& rVal )
     166             : {
     167           0 :     if ( !rVal.IsValid() )
     168             :     {
     169           0 :         nNumerator   = 0;
     170           0 :         nDenominator = -1;
     171             :     }
     172           0 :     if ( !IsValid() )
     173           0 :         return *this;
     174             : 
     175             :     // (a/b) + (c/d) = ( (a*d) + (c*b) ) / (b*d)
     176           0 :     BigInt nN( nNumerator );
     177           0 :     nN *= BigInt( rVal.nDenominator );
     178           0 :     BigInt nW1Temp( nDenominator );
     179           0 :     nW1Temp *= BigInt( rVal.nNumerator );
     180           0 :     nN += nW1Temp;
     181             : 
     182           0 :     BigInt nD( nDenominator );
     183           0 :     nD *= BigInt( rVal.nDenominator );
     184             : 
     185           0 :     Reduce( nN, nD );
     186             : 
     187           0 :     if ( nN.bIsBig || nD.bIsBig )
     188             :     {
     189           0 :         nNumerator   = 0;
     190           0 :         nDenominator = -1;
     191             :     }
     192             :     else
     193             :     {
     194           0 :         nNumerator   = (long)nN,
     195           0 :         nDenominator = (long)nD;
     196             :     }
     197             : 
     198           0 :     return *this;
     199             : }
     200             : 
     201             : // This methods first validates both values.
     202             : // If one of the arguments is invalid, the whole operation is invalid.
     203             : // For substraction, both fractions are extended to match the denominator,
     204             : // then nominators are substracted and reduced (through GCD).
     205             : // Internal datatype for computation is SLong to detect overflows,
     206             : // which cause the operation to be marked as invalid
     207           0 : Fraction& Fraction::operator -= ( const Fraction& rVal )
     208             : {
     209           0 :     if ( !rVal.IsValid() )
     210             :     {
     211           0 :         nNumerator   = 0;
     212           0 :         nDenominator = -1;
     213             :     }
     214           0 :     if ( !IsValid() )
     215           0 :         return *this;
     216             : 
     217             :     // (a/b) - (c/d) = ( (a*d) - (c*b) ) / (b*d)
     218           0 :     BigInt nN( nNumerator );
     219           0 :     nN *= BigInt( rVal.nDenominator );
     220           0 :     BigInt nW1Temp( nDenominator );
     221           0 :     nW1Temp *= BigInt( rVal.nNumerator );
     222           0 :     nN -= nW1Temp;
     223             : 
     224           0 :     BigInt nD( nDenominator );
     225           0 :     nD *= BigInt( rVal.nDenominator );
     226             : 
     227           0 :     Reduce( nN, nD );
     228             : 
     229           0 :     if ( nN.bIsBig || nD.bIsBig )
     230             :     {
     231           0 :         nNumerator   = 0;
     232           0 :         nDenominator = -1;
     233             :     }
     234             :     else
     235             :     {
     236           0 :         nNumerator   = (long)nN,
     237           0 :         nDenominator = (long)nD;
     238             :     }
     239             : 
     240           0 :     return *this;
     241             : }
     242             : 
     243             : // This methods first validates both values.
     244             : // If one of the arguments is invalid, the whole operation is invalid.
     245             : // For mutliplication, nominator and denominators are first reduced
     246             : // (through GCD), and then multiplied.
     247             : // Internal datatype for computation is BigInt to detect overflows,
     248             : // which cause the operation to be marked as invalid
     249      905578 : Fraction& Fraction::operator *= ( const Fraction& rVal )
     250             : {
     251      905578 :     if ( !rVal.IsValid() )
     252             :     {
     253           0 :         nNumerator   = 0;
     254           0 :         nDenominator = -1;
     255             :     }
     256      905578 :     if ( !IsValid() )
     257           0 :         return *this;
     258             : 
     259      905578 :     long nGGT1 = GetGGT( nNumerator, rVal.nDenominator );
     260      905578 :     long nGGT2 = GetGGT( rVal.nNumerator, nDenominator );
     261      905578 :     BigInt nN( nNumerator / nGGT1 );
     262      905578 :     nN *= BigInt( rVal.nNumerator / nGGT2 );
     263      905578 :     BigInt nD( nDenominator / nGGT2 );
     264      905578 :     nD *= BigInt( rVal.nDenominator / nGGT1 );
     265             : 
     266      905578 :     if ( nN.bIsBig || nD.bIsBig )
     267             :     {
     268      138594 :         nNumerator   = 0;
     269      138594 :         nDenominator = -1;
     270             :     }
     271             :     else
     272             :     {
     273      766984 :         nNumerator   = (long)nN,
     274      766984 :         nDenominator = (long)nD;
     275             :     }
     276             : 
     277      905578 :     return *this;
     278             : }
     279             : 
     280             : // This methods first validates both values.
     281             : // If one of the arguments is invalid, the whole operation is invalid.
     282             : // For dividing a/b, we multiply a with the inverse of b.
     283             : // To avoid overflows, we first reduce both fractions with GCD.
     284             : // Internal datatype for computation is BigInt to detect overflows,
     285             : // which cause the operation to be marked as invalid
     286        2215 : Fraction& Fraction::operator /= ( const Fraction& rVal )
     287             : {
     288        2215 :     if ( !rVal.IsValid() )
     289             :     {
     290           0 :         nNumerator   = 0;
     291           0 :         nDenominator = -1;
     292             :     }
     293        2215 :     if ( !IsValid() )
     294           0 :         return *this;
     295             : 
     296        2215 :     long nGGT1 = GetGGT( nNumerator, rVal.nNumerator );
     297        2215 :     long nGGT2 = GetGGT( rVal.nDenominator, nDenominator );
     298        2215 :     BigInt nN( nNumerator / nGGT1 );
     299        2215 :     nN *= BigInt( rVal.nDenominator / nGGT2 );
     300        2215 :     BigInt nD( nDenominator / nGGT2 );
     301        2215 :     nD *= BigInt( rVal.nNumerator / nGGT1 );
     302             : 
     303        2215 :     if ( nN.bIsBig || nD.bIsBig )
     304             :     {
     305           0 :         nNumerator   = 0;
     306           0 :         nDenominator = -1;
     307             :     }
     308             :     else
     309             :     {
     310        2215 :         nNumerator   = (long)nN,
     311        2215 :         nDenominator = (long)nD;
     312        2215 :         if ( nDenominator < 0 )
     313             :         {
     314           0 :             nDenominator = -nDenominator;
     315           0 :             nNumerator   = -nNumerator;
     316             :         }
     317             :     }
     318             : 
     319        2215 :     return *this;
     320             : }
     321             : 
     322             : // Similar to clz_table that can be googled
     323             : const char nbits_table[32] =
     324             : {
     325             :     32,  1, 23,  2, 29, 24, 14,  3,
     326             :     30, 27, 25, 18, 20, 15, 10,  4,
     327             :     31, 22, 28, 13, 26, 17, 19,  9,
     328             :     21, 12, 16,  8, 11,  7,  6,  5
     329             : };
     330             : 
     331        4164 : static int impl_NumberOfBits( unsigned long nNum )
     332             : {
     333             :     // http://en.wikipedia.org/wiki/De_Bruijn_sequence
     334             :     // background paper: Using de Bruijn Sequences to Index a 1 in a
     335             :     // Computer Word (1998) Charles E. Leiserson,
     336             :     // Harald Prokop, Keith H. Randall
     337             :     // (e.g. http://citeseer.ist.psu.edu/leiserson98using.html)
     338        4164 :     const sal_uInt32 nDeBruijn = 0x7DCD629;
     339             : 
     340        4164 :     if ( nNum == 0 )
     341           0 :         return 0;
     342             : 
     343             :     // Get it to form like 0000001111111111b
     344        4164 :     nNum |= ( nNum >>  1 );
     345        4164 :     nNum |= ( nNum >>  2 );
     346        4164 :     nNum |= ( nNum >>  4 );
     347        4164 :     nNum |= ( nNum >>  8 );
     348        4164 :     nNum |= ( nNum >> 16 );
     349             : 
     350             :     sal_uInt32 nNumber;
     351        4164 :     int nBonus = 0;
     352             : 
     353             : #if SAL_TYPES_SIZEOFLONG == 4
     354        4164 :     nNumber = nNum;
     355             : #elif SAL_TYPES_SIZEOFLONG == 8
     356             :     nNum |= ( nNum >> 32 );
     357             : 
     358             :     if ( nNum & 0x80000000 )
     359             :     {
     360             :         nNumber = sal_uInt32( nNum >> 32 );
     361             :         nBonus = 32;
     362             : 
     363             :         if ( nNumber == 0 )
     364             :             return 32;
     365             :     }
     366             :     else
     367             :         nNumber = sal_uInt32( nNum & 0xFFFFFFFF );
     368             : #else
     369             : #error "Unknown size of long!"
     370             : #endif
     371             : 
     372             :     // De facto shift left of nDeBruijn using multiplication (nNumber
     373             :     // is all ones from topmost bit, thus nDeBruijn + (nDeBruijn *
     374             :     // nNumber) => nDeBruijn * (nNumber+1) clears all those bits to
     375             :     // zero, sets the next bit to one, and thus effectively shift-left
     376             :     // nDeBruijn by lg2(nNumber+1). This generates a distinct 5bit
     377             :     // sequence in the msb for each distinct position of the last
     378             :     // leading 0 bit - that's the property of a de Bruijn number.
     379        4164 :     nNumber = nDeBruijn + ( nDeBruijn * nNumber );
     380             : 
     381             :     // 5-bit window indexes the result
     382        4164 :     return ( nbits_table[nNumber >> 27] ) + nBonus;
     383             : }
     384             : 
     385             : /** Inaccurate cancellation for a fraction.
     386             : 
     387             :     Clip both nominator and denominator to said number of bits. If
     388             :     either of those already have equal or less number of bits used,
     389             :     this method does nothing.
     390             : 
     391             :     @param nSignificantBits denotes, how many significant binary
     392             :     digits to maintain, in both nominator and denominator.
     393             : 
     394             :     @example ReduceInaccurate(8) has an error <1% [1/2^(8-1)] - the
     395             :     largest error occurs with the following pair of values:
     396             : 
     397             :     binary    1000000011111111111111111111111b/1000000000000000000000000000000b
     398             :     =         1082130431/1073741824
     399             :     = approx. 1.007812499
     400             : 
     401             :     A ReduceInaccurate(8) yields 1/1.
     402             : */
     403        2082 : void Fraction::ReduceInaccurate( unsigned nSignificantBits )
     404             : {
     405        2082 :     if ( !nNumerator || !nDenominator )
     406           0 :         return;
     407             : 
     408             :     // Count with unsigned longs only
     409        2082 :     const bool bNeg = ( nNumerator < 0 );
     410        2082 :     unsigned long nMul = (unsigned long)( bNeg? -nNumerator: nNumerator );
     411        2082 :     unsigned long nDiv = (unsigned long)( nDenominator );
     412             : 
     413             :     DBG_ASSERT(nSignificantBits<65, "More than 64 bit of significance is overkill!");
     414             : 
     415             :     // How much bits can we lose?
     416        2082 :     const int nMulBitsToLose = std::max( ( impl_NumberOfBits( nMul ) - int( nSignificantBits ) ), 0 );
     417        2082 :     const int nDivBitsToLose = std::max( ( impl_NumberOfBits( nDiv ) - int( nSignificantBits ) ), 0 );
     418             : 
     419        2082 :     const int nToLose = std::min( nMulBitsToLose, nDivBitsToLose );
     420             : 
     421             :     // Remove the bits
     422        2082 :     nMul >>= nToLose;
     423        2082 :     nDiv >>= nToLose;
     424             : 
     425        2082 :     if ( !nMul || !nDiv )
     426             :     {
     427             :         // Return without reduction
     428             :         OSL_FAIL( "Oops, we reduced too much..." );
     429           0 :         return;
     430             :     }
     431             : 
     432             :     // Reduce
     433        2082 :     long n1 = GetGGT( nMul, nDiv );
     434        2082 :     if ( n1 != 1 )
     435             :     {
     436         949 :         nMul /= n1;
     437         949 :         nDiv /= n1;
     438             :     }
     439             : 
     440        2082 :     nNumerator = bNeg? -long( nMul ): long( nMul );
     441        2082 :     nDenominator = nDiv;
     442             : }
     443             : 
     444      140473 : bool operator == ( const Fraction& rVal1, const Fraction& rVal2 )
     445             : {
     446      140473 :     if ( !rVal1.IsValid() || !rVal2.IsValid() )
     447           0 :         return false;
     448             : 
     449      140473 :     return rVal1.nNumerator == rVal2.nNumerator
     450      140473 :            && rVal1.nDenominator == rVal2.nDenominator;
     451             : }
     452             : 
     453             : // This methods first validates and reduces both values.
     454             : // To compare (a/b) with (c/d), extend denominators (b*d), then return
     455             : // the result of comparing the nominators (a < c)
     456         410 : bool operator < ( const Fraction& rVal1, const Fraction& rVal2 )
     457             : {
     458         410 :     if ( !rVal1.IsValid() || !rVal2.IsValid() )
     459           0 :         return false;
     460             : 
     461         410 :     BigInt nN( rVal1.nNumerator );
     462         410 :     nN *= BigInt( rVal2.nDenominator );
     463         410 :     BigInt nD( rVal1.nDenominator );
     464         410 :     nD *= BigInt( rVal2.nNumerator );
     465             : 
     466         410 :     return nN < nD;
     467             : }
     468             : 
     469             : // This methods first validates and reduces both values.
     470             : // To compare (a/b) with (c/d), extend denominators (b*d), then return
     471             : // the result of comparing nominators (a > c)
     472         410 : bool operator > ( const Fraction& rVal1, const Fraction& rVal2 )
     473             : {
     474         410 :     if ( !rVal1.IsValid() || !rVal2.IsValid() )
     475           0 :         return false;
     476             : 
     477         410 :     BigInt nN( rVal1.nNumerator );
     478         410 :     nN *= BigInt( rVal2.nDenominator );
     479         410 :     BigInt nD( rVal1.nDenominator);
     480         410 :     nD *= BigInt( rVal2.nNumerator );
     481             : 
     482         410 :     return nN > nD;
     483             : }
     484             : 
     485        5362 : SvStream& operator >> ( SvStream& rIStream, Fraction& rFract )
     486             : {
     487             :     //fdo#39428 SvStream no longer supports operator>>(long&)
     488        5362 :     sal_Int32 nTmp(0);
     489        5362 :     rIStream >> nTmp;
     490        5362 :     rFract.nNumerator = nTmp;
     491        5362 :     rIStream >> nTmp;
     492        5362 :     rFract.nDenominator = nTmp;
     493        5362 :     return rIStream;
     494             : }
     495             : 
     496        5678 : SvStream& operator << ( SvStream& rOStream, const Fraction& rFract )
     497             : {
     498             :     //fdo#39428 SvStream no longer supports operator<<(long)
     499        5678 :     rOStream << sal::static_int_cast<sal_Int32>(rFract.nNumerator);
     500        5678 :     rOStream << sal::static_int_cast<sal_Int32>(rFract.nDenominator);
     501        5678 :     return rOStream;
     502             : }
     503             : 
     504             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10