From 93125d3a05acd0a4e3b5f898fd30e4fe0a561d9e Mon Sep 17 00:00:00 2001 From: Edward Welbourne Date: Tue, 3 May 2022 15:59:48 +0200 Subject: [PATCH] Refine QRoundingDown::qDiv() to avoid underflow Subtracting denominator - 1 from the numerator ran into trouble if the numerator was close to its type's minimum representable value. Adding 1 before division, then subtracting it after, avoids that underflow while getting the same answer. Change-Id: I0bb85deaa2ad36f8744ed6dbfdb4817442dddebe Reviewed-by: Thiago Macieira --- src/corelib/time/qcalendarmath_p.h | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/corelib/time/qcalendarmath_p.h b/src/corelib/time/qcalendarmath_p.h index 61c2c5d2b5c..cc8e725c3f8 100644 --- a/src/corelib/time/qcalendarmath_p.h +++ b/src/corelib/time/qcalendarmath_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtCore module of the Qt Toolkit. @@ -62,10 +62,17 @@ namespace QRoundingDown { From C++11 onwards, integer division is defined to round towards zero, so we can rely on that when implementing this. This is only used with denominator b > 0, so we only have to treat negative numerator, a, specially. + + If a is a multiple of b, adding 1 before and subtracting it after dividing by + b gets us to where we should be (albeit by an eccentric path), since the + adding caused rounding up, undone by the subtracting. Otherwise, adding 1 + doesn't change the result of dividing by b; and we want one less than that + result. This is equivalent to subtracting b - 1 and simply dividing, except + when that subtraction would underflow. */ template constexpr Int qDiv(Int a, unsigned b) -{ return (a - (a < 0 ? int(b - 1) : 0)) / int(b); } +{ return a < 0 ? (a + 1) / int(b) - 1 : a / int(b); } template constexpr Int qMod(Int a, unsigned b) { return a - qDiv(a, b) * b; }