25#include <osl/diagnose.h>
31#include <boost/rational.hpp>
41static boost::rational<sal_Int32>
toRational(sal_Int32 n, sal_Int32 d)
47 if (
d < -std::numeric_limits<sal_Int32>::max())
49 return boost::rational<sal_Int32>(
n,
d);
54 return nNum < std::numeric_limits<sal_Int32>::min()
55 || nNum > std::numeric_limits<sal_Int32>::max();
63 if (
const auto gcd = std::gcd(nNum, nDen); gcd > 1)
69 "tools.fraction",
"values outside of range we can represent, doing reduction, which will reduce precision");
81 SAL_WARN(
"tools.fraction",
"'Fraction(" << nNum <<
",0)' invalid fraction created" );
84 else if ((nDen == -1 && nNum == std::numeric_limits<sal_Int32>::min()) ||
85 (nNum == -1 && nDen == std::numeric_limits<sal_Int32>::min()))
88 SAL_WARN(
"tools.fraction",
"'Fraction(" << nNum <<
"," << nDen <<
")' invalid fraction created");
97 :
Fraction(sal_Int64(nNum), sal_Int64(nDen))
108 catch (
const boost::bad_rational&)
111 SAL_WARN(
"tools.fraction",
"'Fraction(" << dVal <<
")' invalid fraction created" );
115Fraction::operator double()
const
119 SAL_WARN(
"tools.fraction",
"'double()' on invalid fraction" );
123 return boost::rational_cast<double>(
toRational(mnNumerator, mnDenominator));
137 SAL_WARN(
"tools.fraction",
"'operator +=' with invalid fraction" );
156 SAL_WARN(
"tools.fraction",
"'operator -=' with invalid fraction" );
170 bool checked_multiply_by(boost::rational<sal_Int32>& i,
const boost::rational<sal_Int32>& r)
173 sal_Int32 num = r.numerator();
174 sal_Int32 den = r.denominator();
186 sal_Int32 gcd1 = std::gcd(
i.numerator(), den);
187 sal_Int32 gcd2 = std::gcd(num,
i.denominator());
210 SAL_WARN(
"tools.fraction",
"'operator *=' with invalid fraction" );
216 bool bFail = checked_multiply_by(
a, b);
235 SAL_WARN(
"tools.fraction",
"'operator /=' with invalid fraction" );
269 SAL_WARN(
"tools.fraction",
"'ReduceInaccurate' on invalid fraction" );
286 SAL_WARN(
"tools.fraction",
"'GetNumerator()' on invalid fraction" );
296 SAL_WARN(
"tools.fraction",
"'GetDenominator()' on invalid fraction" );
302Fraction::operator sal_Int32()
const
306 SAL_WARN(
"tools.fraction",
"'operator sal_Int32()' on invalid fraction" );
309 return boost::rational_cast<sal_Int32>(
toRational(mnNumerator, mnDenominator));
342 return !(rVal1 == rVal2);
347 return !(rVal1 > rVal2);
352 return !(rVal1 < rVal2);
359 SAL_WARN(
"tools.fraction",
"'operator ==' with an invalid fraction" );
370 SAL_WARN(
"tools.fraction",
"'operator <' with an invalid fraction" );
381 SAL_WARN(
"tools.fraction",
"'operator >' with an invalid fraction" );
395 if ( dVal > std::numeric_limits<sal_Int32>::max() ||
396 dVal < std::numeric_limits<sal_Int32>::min() ||
398 throw boost::bad_rational();
400 const sal_Int32 nMAX = std::numeric_limits<sal_Int32>::max() / 10;
402 while (
std::abs( dVal ) < nMAX && nDen < nMAX ) {
406 return boost::rational<sal_Int32>( sal_Int32(dVal), nDen );
418 _BitScanReverse(&r, nNum);
421 return 32 - __builtin_clz(nNum);
449 sal_Int32 nMul = rRational.numerator();
450 if (nMul == std::numeric_limits<sal_Int32>::min())
455 const bool bNeg = nMul < 0;
458 sal_Int32 nDiv = rRational.denominator();
460 DBG_ASSERT(nSignificantBits<65,
"More than 64 bit of significance is overkill!");
463 const int nMulBitsToLose = std::max( (
impl_NumberOfBits( nMul ) -
int( nSignificantBits ) ), 0 );
464 const int nDivBitsToLose = std::max( (
impl_NumberOfBits( nDiv ) -
int( nSignificantBits ) ), 0 );
466 const int nToLose = std::min( nMulBitsToLose, nDivBitsToLose );
472 if ( !nMul || !nDiv ) {
474 OSL_FAIL(
"Oops, we reduced too much..." );
478 rRational.assign( bNeg ? -nMul : nMul, nDiv );
492 if( nD1 == 0 || nD2 == 0 )
494 SAL_WARN(
"tools.fraction",
"Invalid parameter for ImplMakeFraction");
500 if ( nN1 < 0 ) {
i = -
i; nN1 = -nN1; }
501 if ( nN2 < 0 ) {
i = -
i; nN2 = -nN2; }
502 if ( nD1 < 0 ) {
i = -
i; nD1 = -nD1; }
503 if ( nD2 < 0 ) {
i = -
i; nD2 = -nD2; }
506 assert( nN1 >= std::numeric_limits<sal_Int32>::min() );
507 assert( nN1 <= std::numeric_limits<sal_Int32>::max( ));
508 assert( nD1 >= std::numeric_limits<sal_Int32>::min() );
509 assert( nD1 <= std::numeric_limits<sal_Int32>::max( ));
510 assert( nN2 >= std::numeric_limits<sal_Int32>::min() );
511 assert( nN2 <= std::numeric_limits<sal_Int32>::max( ));
512 assert( nD2 >= std::numeric_limits<sal_Int32>::min() );
513 assert( nD2 <= std::numeric_limits<sal_Int32>::max( ));
516 boost::rational<sal_Int32> b =
toRational(nN2, nD2);
517 bool bFail = checked_multiply_by(
a, b);
531 bFail = checked_multiply_by(
a, b);
534 return Fraction(
a.numerator(),
a.denominator());
sal_Int32 GetNumerator() const
static Fraction MakeFraction(tools::Long nN1, tools::Long nN2, tools::Long nD1, tools::Long nD2)
Multiply the two fractions represented here and reduce inaccuracy to 32-bits, used by vcl.
void ReduceInaccurate(unsigned nSignificantBits)
Fraction & operator+=(const Fraction &rfrFrac)
Fraction & operator*=(const Fraction &rfrFrac)
sal_Int32 mnNumerator
these two fields form a boost::rational, but I didn't want to put more boost headers into the global ...
sal_Int32 GetDenominator() const
size_t GetHashValue() const
Fraction & operator/=(const Fraction &rfrFrac)
Fraction & operator-=(const Fraction &rfrFrac)
#define DBG_ASSERT(sCon, aError)
Degree100 abs(Degree100 x)
static int impl_NumberOfBits(sal_uInt32 nNum)
Find the number of bits required to represent this number, using the CLZ intrinsic.
Fraction operator-(const Fraction &rVal1, const Fraction &rVal2)
static boost::rational< sal_Int32 > rational_FromDouble(double dVal)
Fraction operator/(const Fraction &rVal1, const Fraction &rVal2)
bool operator>(const Fraction &rVal1, const Fraction &rVal2)
bool operator<(const Fraction &rVal1, const Fraction &rVal2)
Fraction operator+(const Fraction &rVal1, const Fraction &rVal2)
Fraction operator*(const Fraction &rVal1, const Fraction &rVal2)
bool operator==(const Fraction &rVal1, const Fraction &rVal2)
static boost::rational< sal_Int32 > toRational(sal_Int32 n, sal_Int32 d)
bool operator>=(const Fraction &rVal1, const Fraction &rVal2)
bool operator!=(const Fraction &rVal1, const Fraction &rVal2)
bool operator<=(const Fraction &rVal1, const Fraction &rVal2)
static constexpr bool isOutOfRange(sal_Int64 nNum)
static void rational_ReduceInaccurate(boost::rational< sal_Int32 > &rRational, unsigned nSignificantBits)
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
std::enable_if_t<(sizeof(N)==4)> hash_combine(N &nSeed, T const *pValue, size_t nCount)
std::enable_if< std::is_signed< T >::value, bool >::type checked_multiply(T a, T b, T &result)