From 8fddbce4ab902f855472c30dd1c8bb713854e3c4 Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Wed, 2 Mar 2011 14:57:57 +0000 Subject: [PATCH] re PR libstdc++/47913 ([C++0x] improve ratio_add to overflow less often) 2011-03-02 Marc Glisse PR libstdc++/47913 * include/std/ratio (ratio_add): Avoid denominator overflow. * testsuite/20_util/ratio/operations/47913.cc: New. From-SVN: r170616 --- libstdc++-v3/ChangeLog | 6 +++ libstdc++-v3/include/std/ratio | 16 ++++--- .../20_util/ratio/operations/47913.cc | 42 +++++++++++++++++++ 3 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/ratio/operations/47913.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index a6a290959fb..c2c86d6caea 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,9 @@ +2011-03-02 Marc Glisse + + PR libstdc++/47913 + * include/std/ratio (ratio_add): Avoid denominator overflow. + * testsuite/20_util/ratio/operations/47913.cc: New. + 2011-02-28 Benjamin Kosnik * testsuite/20_util/hash/chi2_quality.cc: Use C++0x mode on simulators. diff --git a/libstdc++-v3/include/std/ratio b/libstdc++-v3/include/std/ratio index 2b10da7c688..30bce162e16 100644 --- a/libstdc++-v3/include/std/ratio +++ b/libstdc++-v3/include/std/ratio @@ -177,15 +177,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct ratio_add { private: - static const intmax_t __gcd = + static constexpr intmax_t __gcd = __static_gcd<_R1::den, _R2::den>::value; + static constexpr intmax_t __n = __safe_add< + __safe_multiply<_R1::num, (_R2::den / __gcd)>::value, + __safe_multiply<_R2::num, (_R1::den / __gcd)>::value>::value; + + // The new numerator may have common factors with the denominator, + // but they have to also be factors of __gcd. + static constexpr intmax_t __gcd2 = __static_gcd<__n, __gcd>::value; public: - typedef ratio< - __safe_add< - __safe_multiply<_R1::num, (_R2::den / __gcd)>::value, - __safe_multiply<_R2::num, (_R1::den / __gcd)>::value>::value, - __safe_multiply<_R1::den, (_R2::den / __gcd)>::value> type; + typedef ratio<__n / __gcd2, + __safe_multiply<_R1::den / __gcd2, _R2::den / __gcd>::value> type; static constexpr intmax_t num = type::num; static constexpr intmax_t den = type::den; diff --git a/libstdc++-v3/testsuite/20_util/ratio/operations/47913.cc b/libstdc++-v3/testsuite/20_util/ratio/operations/47913.cc new file mode 100644 index 00000000000..4105a710d91 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/ratio/operations/47913.cc @@ -0,0 +1,42 @@ +// { dg-options "-std=gnu++0x" } +// { dg-require-cstdint "" } + +// Copyright (C) 2011 Free Software Foundation +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING3. If not see +// . + +#include +#include + +// libstdc++/47913 +void test01() +{ + bool test __attribute__((unused)) = true; + using namespace std; + + const intmax_t m = (intmax_t)1 << (4 * sizeof(intmax_t) - 1); + typedef ratio_add, + ratio<1, (m - 3) * (m - 2)> > ra_type; + + VERIFY( ra_type::num == 2 ); + VERIFY( ra_type::den == (m - 1) * (m - 3) ); +} + +int main() +{ + test01(); + return 0; +} -- 2.30.2