speed up Fraction::operator*= a little

for my test spreadsheet this reduced the time spent
in Fraction by 30%

Change-Id: Ib14a93284dbd6c6ea2349c1754979135463ca61b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/125878
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
This commit is contained in:
Noel Grandin 2021-11-26 13:55:03 +02:00 committed by Noel Grandin
parent 26643b50a2
commit 05766922e7

View file

@ -35,8 +35,8 @@
#endif
static boost::rational<sal_Int32> rational_FromDouble(double dVal);
static void rational_ReduceInaccurate(boost::rational<sal_Int32>& rRational, unsigned nSignificantBits);
static int impl_NumberOfBits( sal_uInt32 nNum );
static boost::rational<sal_Int32> toRational(sal_Int32 n, sal_Int32 d)
{
@ -163,15 +163,24 @@ Fraction& Fraction::operator -= ( const Fraction& rVal )
namespace
{
template<typename T> bool checked_multiply_by(boost::rational<T>& i, const boost::rational<T>& r)
bool checked_multiply_by(boost::rational<sal_Int32>& i, const boost::rational<sal_Int32>& r)
{
// Protect against self-modification
T num = r.numerator();
T den = r.denominator();
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;
return false;
}
// Avoid overflow and preserve normalization
T gcd1 = std::gcd(i.numerator(), den);
T gcd2 = std::gcd(num, i.denominator());
sal_Int32 gcd1 = std::gcd(i.numerator(), den);
sal_Int32 gcd2 = std::gcd(num, i.denominator());
bool fail = false;
fail |= o3tl::checked_multiply(i.numerator() / gcd1, num / gcd2, num);