mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-13 05:40:42 +01:00
Extend DivideRoundToNearest to support negative numbers and use for UnitBase
UnitBase own function to divide with rounding overflows when dividend is close to the max int64_t Bug: b/262999013 Change-Id: I5b0c3f4408165a0f03690cab80bd098e506fc984 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/288521 Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org> Commit-Queue: Danil Chapovalov <danilchap@webrtc.org> Cr-Commit-Position: refs/heads/main@{#38943}
This commit is contained in:
parent
e04c397099
commit
f4b21da965
4 changed files with 38 additions and 22 deletions
|
@ -34,13 +34,25 @@ template <typename Dividend, typename Divisor>
|
|||
inline auto constexpr DivideRoundToNearest(Dividend dividend, Divisor divisor) {
|
||||
static_assert(std::is_integral<Dividend>(), "");
|
||||
static_assert(std::is_integral<Divisor>(), "");
|
||||
RTC_DCHECK_GE(dividend, 0);
|
||||
RTC_DCHECK_GT(divisor, 0);
|
||||
|
||||
if (dividend < Dividend{0}) {
|
||||
auto half_of_divisor = divisor / 2;
|
||||
auto quotient = dividend / divisor;
|
||||
auto remainder = dividend % divisor;
|
||||
if (rtc::SafeGt(-remainder, half_of_divisor)) {
|
||||
--quotient;
|
||||
}
|
||||
return quotient;
|
||||
}
|
||||
|
||||
auto half_of_divisor = (divisor - 1) / 2;
|
||||
auto quotient = dividend / divisor;
|
||||
auto remainder = dividend % divisor;
|
||||
return quotient + (rtc::SafeGt(remainder, half_of_divisor) ? 1 : 0);
|
||||
if (rtc::SafeGt(remainder, half_of_divisor)) {
|
||||
++quotient;
|
||||
}
|
||||
return quotient;
|
||||
}
|
||||
|
||||
} // namespace webrtc
|
||||
|
|
|
@ -39,11 +39,18 @@ TEST(DivideRoundUpTest, WorksForMaxDividend) {
|
|||
TEST(DivideRoundToNearestTest, CanBeUsedAsConstexpr) {
|
||||
static constexpr int kOne = DivideRoundToNearest(5, 4);
|
||||
static constexpr int kTwo = DivideRoundToNearest(7, 4);
|
||||
static_assert(kOne == 1, "");
|
||||
static_assert(kTwo == 2, "");
|
||||
static_assert(kOne == 1);
|
||||
static_assert(kTwo == 2);
|
||||
static_assert(DivideRoundToNearest(-5, 4) == -1);
|
||||
static_assert(DivideRoundToNearest(-7, 4) == -2);
|
||||
}
|
||||
|
||||
TEST(DivideRoundToNearestTest, DivideByOddNumber) {
|
||||
EXPECT_EQ(DivideRoundToNearest(-5, 3), -2);
|
||||
EXPECT_EQ(DivideRoundToNearest(-4, 3), -1);
|
||||
EXPECT_EQ(DivideRoundToNearest(-3, 3), -1);
|
||||
EXPECT_EQ(DivideRoundToNearest(-2, 3), -1);
|
||||
EXPECT_EQ(DivideRoundToNearest(-1, 3), 0);
|
||||
EXPECT_EQ(DivideRoundToNearest(0, 3), 0);
|
||||
EXPECT_EQ(DivideRoundToNearest(1, 3), 0);
|
||||
EXPECT_EQ(DivideRoundToNearest(2, 3), 1);
|
||||
|
@ -54,6 +61,13 @@ TEST(DivideRoundToNearestTest, DivideByOddNumber) {
|
|||
}
|
||||
|
||||
TEST(DivideRoundToNearestTest, DivideByEvenNumberTieRoundsUp) {
|
||||
EXPECT_EQ(DivideRoundToNearest(-7, 4), -2);
|
||||
EXPECT_EQ(DivideRoundToNearest(-6, 4), -1);
|
||||
EXPECT_EQ(DivideRoundToNearest(-5, 4), -1);
|
||||
EXPECT_EQ(DivideRoundToNearest(-4, 4), -1);
|
||||
EXPECT_EQ(DivideRoundToNearest(-3, 4), -1);
|
||||
EXPECT_EQ(DivideRoundToNearest(-2, 4), 0);
|
||||
EXPECT_EQ(DivideRoundToNearest(-1, 4), 0);
|
||||
EXPECT_EQ(DivideRoundToNearest(0, 4), 0);
|
||||
EXPECT_EQ(DivideRoundToNearest(1, 4), 0);
|
||||
EXPECT_EQ(DivideRoundToNearest(2, 4), 1);
|
||||
|
@ -68,6 +82,9 @@ TEST(DivideRoundToNearestTest, LargeDivisor) {
|
|||
EXPECT_EQ(DivideRoundToNearest(std::numeric_limits<int>::max() - 1,
|
||||
std::numeric_limits<int>::max()),
|
||||
1);
|
||||
EXPECT_EQ(DivideRoundToNearest(std::numeric_limits<int>::min(),
|
||||
std::numeric_limits<int>::max()),
|
||||
-1);
|
||||
}
|
||||
|
||||
TEST(DivideRoundToNearestTest, DivideSmallTypeByLargeType) {
|
||||
|
|
|
@ -10,13 +10,14 @@ import("../../webrtc.gni")
|
|||
|
||||
rtc_source_set("unit_base") {
|
||||
visibility = [
|
||||
"../../api/units:*",
|
||||
":*",
|
||||
"../../api/units:*",
|
||||
]
|
||||
sources = [ "unit_base.h" ]
|
||||
|
||||
deps = [
|
||||
"../../rtc_base:checks",
|
||||
"../../rtc_base:divide_round",
|
||||
"../../rtc_base:safe_conversions",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <type_traits>
|
||||
|
||||
#include "rtc_base/checks.h"
|
||||
#include "rtc_base/numerics/divide_round.h"
|
||||
#include "rtc_base/numerics/safe_conversions.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
@ -154,12 +155,7 @@ class UnitBase {
|
|||
constexpr typename std::enable_if<std::is_integral<T>::value, T>::type
|
||||
ToFraction() const {
|
||||
RTC_DCHECK(IsFinite());
|
||||
if (Unit_T::one_sided) {
|
||||
return rtc::dchecked_cast<T>(
|
||||
DivRoundPositiveToNearest(value_, Denominator));
|
||||
} else {
|
||||
return rtc::dchecked_cast<T>(DivRoundToNearest(value_, Denominator));
|
||||
}
|
||||
return rtc::dchecked_cast<T>(DivideRoundToNearest(value_, Denominator));
|
||||
}
|
||||
template <int64_t Denominator, typename T>
|
||||
constexpr typename std::enable_if<std::is_floating_point<T>::value, T>::type
|
||||
|
@ -169,9 +165,7 @@ class UnitBase {
|
|||
|
||||
template <int64_t Denominator>
|
||||
constexpr int64_t ToFractionOr(int64_t fallback_value) const {
|
||||
return IsFinite() ? Unit_T::one_sided
|
||||
? DivRoundPositiveToNearest(value_, Denominator)
|
||||
: DivRoundToNearest(value_, Denominator)
|
||||
return IsFinite() ? DivideRoundToNearest(value_, Denominator)
|
||||
: fallback_value;
|
||||
}
|
||||
|
||||
|
@ -205,14 +199,6 @@ class UnitBase {
|
|||
constexpr const Unit_T& AsSubClassRef() const {
|
||||
return static_cast<const Unit_T&>(*this);
|
||||
}
|
||||
// Assumes that n >= 0 and d > 0.
|
||||
static constexpr int64_t DivRoundPositiveToNearest(int64_t n, int64_t d) {
|
||||
return (n + d / 2) / d;
|
||||
}
|
||||
// Assumes that d > 0.
|
||||
static constexpr int64_t DivRoundToNearest(int64_t n, int64_t d) {
|
||||
return (n + (n >= 0 ? d / 2 : -d / 2)) / d;
|
||||
}
|
||||
|
||||
int64_t value_;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue