diff --git a/AK/Time.cpp b/AK/Time.cpp index 8120dea9d8..876fa383d5 100644 --- a/AK/Time.cpp +++ b/AK/Time.cpp @@ -73,18 +73,19 @@ Duration Duration::from_time_units(i64 time_units, u32 numerator, u32 denominato VERIFY(numerator != 0); VERIFY(denominator != 0); - auto seconds_checked = Checked(time_units); - seconds_checked.mul(numerator); - seconds_checked.div(denominator); - if (time_units < 0) - seconds_checked.sub(1); - - if (seconds_checked.has_overflow()) + if (Checked::multiplication_would_overflow(time_units, numerator)) return Duration(time_units >= 0 ? NumericLimits::max() : NumericLimits::min(), 0); - auto seconds = seconds_checked.value_unchecked(); - auto seconds_in_time_units = seconds * denominator / numerator; - auto remainder_in_time_units = time_units - seconds_in_time_units; - auto nanoseconds = ((remainder_in_time_units * 1'000'000'000 * numerator) + (denominator / 2)) / denominator; + auto time_units_product = time_units * numerator; + auto seconds = time_units_product / denominator; + auto time_units_remainder = time_units_product % denominator; + if (time_units_remainder < 0) { + if (seconds == NumericLimits::min()) + return Duration(NumericLimits::min(), 0); + seconds--; + time_units_remainder += denominator; + } + + auto nanoseconds = ((time_units_remainder * 1'000'000'000) + (denominator / 2)) / denominator; if (nanoseconds == 1'000'000'000) { seconds++; nanoseconds = 0; diff --git a/Tests/AK/TestTime.cpp b/Tests/AK/TestTime.cpp index ff265f769c..055d2762a1 100644 --- a/Tests/AK/TestTime.cpp +++ b/Tests/AK/TestTime.cpp @@ -961,6 +961,13 @@ TEST_CASE(time_units) EXPECT_EQ(Duration::from_time_units(-43776, 1, 14592), Duration::from_seconds(-3)); + EXPECT_EQ(Duration::from_time_units(NumericLimits::min(), 1, 2), Duration::from_seconds(NumericLimits::min() / 2)); + EXPECT_EQ(Duration::from_time_units(NumericLimits::min() + 1, 1, 2), Duration::from_seconds(NumericLimits::min() / 2) + Duration::from_milliseconds(500)); + EXPECT_EQ(Duration::from_time_units(NumericLimits::min(), 1, 3), Duration::from_seconds(NumericLimits::min() / 3) - Duration::from_nanoseconds(666'666'667)); + + EXPECT_EQ(Duration::from_time_units(-1, 1, 2'000'000'000), Duration::zero()); + EXPECT_EQ(Duration::from_time_units(-2, 1, 2'000'000'000), Duration::from_nanoseconds(-1)); + EXPECT_EQ(Duration::from_milliseconds(999).to_time_units(1, 48'000), 47'952); EXPECT_EQ(Duration::from_milliseconds(-12'500).to_time_units(1, 1'000), -12'500); EXPECT_EQ(Duration::from_milliseconds(-12'500).to_time_units(1, 1'000), -12'500);