/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
static boost::rational<sal_Int32> rational_FromDouble(double dVal); staticvoid rational_ReduceInaccurate(boost::rational<sal_Int32>& rRational, unsigned nSignificantBits); // Find the number of bits required to represent this number staticint impl_NumberOfBits(sal_uInt32 nNum) { return 32 - std::countl_zero(nNum); }
static boost::rational<sal_Int32> toRational(sal_Int32 n, sal_Int32 d)
{ // https://github.com/boostorg/boost/issues/335 when these are std::numeric_limits<sal_Int32>::min if (n == d) return 1; // tdf#144319 avoid boost::bad_rational e.g. if numerator=-476741369, denominator=-2147483648 if (d < -std::numeric_limits<sal_Int32>::max()) return 0; return boost::rational<sal_Int32>(n, d);
}
// This methods first validates both values. // If one of the arguments is invalid, the whole operation is invalid. // After computation detect if result overflows a sal_Int32 value // which cause the operation to be marked as invalid
Fraction& Fraction::operator += ( const Fraction& rVal )
{ if ( !rVal.mbValid )
mbValid = false;
if ( !mbValid )
{
SAL_WARN( "tools.fraction", "'operator +=' with invalid fraction" ); return *this;
}
boost::rational<sal_Int32> a = toRational(mnNumerator, mnDenominator);
a += toRational(rVal.mnNumerator, rVal.mnDenominator);
mnNumerator = a.numerator();
mnDenominator = a.denominator();
if ( !mbValid )
{
SAL_WARN( "tools.fraction", "'operator -=' with invalid fraction" ); return *this;
}
boost::rational<sal_Int32> a = toRational(mnNumerator, mnDenominator);
a -= toRational(rVal.mnNumerator, rVal.mnDenominator);
mnNumerator = a.numerator();
mnDenominator = a.denominator();
return *this;
}
namespace
{ bool checked_multiply_by(boost::rational<sal_Int32>& i, const boost::rational<sal_Int32>& r)
{ // Protect against self-modification
sal_Int32 num = r.numerator();
sal_Int32 den = r.denominator();
// Fast-path if the number of bits in input is < the number of bits in the output, overflow cannot happen // This is considerably faster than repeated std::gcd() operations if ((impl_NumberOfBits(std::abs(i.numerator())) + impl_NumberOfBits(std::abs(r.numerator()))) < 32 &&
(impl_NumberOfBits(std::abs(i.denominator())) + impl_NumberOfBits(std::abs(r.denominator()))) < 32)
{
i *= r; returnfalse;
}
if ( !mbValid )
{
SAL_WARN( "tools.fraction", "'operator /=' with invalid fraction" ); return *this;
}
boost::rational<sal_Int32> a = toRational(mnNumerator, mnDenominator);
a /= toRational(rVal.mnNumerator, rVal.mnDenominator);
mnNumerator = a.numerator();
mnDenominator = a.denominator();
return *this;
}
/** Inaccurate cancellation for a fraction.
Clip both nominator and denominator to said number of bits. If either of those already have equal or less number of bits used, this method does nothing.
@param nSignificantBits denotes, how many significant binary digits to maintain, in both nominator and denominator.
@example ReduceInaccurate(8) has an error <1% [1/2^(8-1)] - the largest error occurs with the following pair of values:
// If dVal > LONG_MAX or dVal < LONG_MIN, the rational throws a boost::bad_rational. // Otherwise, dVal and denominator are multiplied by 10, until one of them // is larger than (LONG_MAX / 10). // // NOTE: here we use 'sal_Int32' due that only values in sal_Int32 range are valid. static boost::rational<sal_Int32> rational_FromDouble(double dVal)
{ if ( dVal > std::numeric_limits<sal_Int32>::max() ||
dVal < std::numeric_limits<sal_Int32>::min() ||
std::isnan(dVal) ) throw boost::bad_rational();
Clip both nominator and denominator to said number of bits. If either of those already have equal or less number of bits used, this method does nothing.
@param nSignificantBits denotes, how many significant binary digits to maintain, in both nominator and denominator.
@example ReduceInaccurate(8) has an error <1% [1/2^(8-1)] - the largest error occurs with the following pair of values:
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.