@@ -4949,6 +4949,21 @@ DoubleAPFloat &DoubleAPFloat::operator=(const DoubleAPFloat &RHS) {
49494949 return *this ;
49504950}
49514951
4952+ // Returns a result such that:
4953+ // 1. abs(Lo) <= ulp(Hi)/2
4954+ // 2. Hi == RTNE(Hi + Lo)
4955+ // 3. Hi + Lo == X + Y
4956+ //
4957+ // Requires that log2(X) >= log2(Y).
4958+ static std::pair<APFloat, APFloat> fastTwoSum (APFloat X, APFloat Y) {
4959+ if (!X.isFinite ())
4960+ return {X, APFloat::getZero (X.getSemantics (), /* Negative=*/ false )};
4961+ APFloat Hi = X + Y;
4962+ APFloat Delta = Hi - X;
4963+ APFloat Lo = Y - Delta;
4964+ return {Hi, Lo};
4965+ }
4966+
49524967// Implement addition, subtraction, multiplication and division based on:
49534968// "Software for Doubled-Precision Floating-Point Computations",
49544969// by Seppo Linnainmaa, ACM TOMS vol 7 no 3, September 1981, pages 272-283.
@@ -5218,10 +5233,78 @@ DoubleAPFloat::fusedMultiplyAdd(const DoubleAPFloat &Multiplicand,
52185233
52195234APFloat::opStatus DoubleAPFloat::roundToIntegral (APFloat::roundingMode RM) {
52205235 assert (Semantics == &semPPCDoubleDouble && " Unexpected Semantics" );
5221- APFloat Tmp (semPPCDoubleDoubleLegacy, bitcastToAPInt ());
5222- auto Ret = Tmp.roundToIntegral (RM);
5223- *this = DoubleAPFloat (semPPCDoubleDouble, Tmp.bitcastToAPInt ());
5224- return Ret;
5236+ const APFloat &Hi = getFirst ();
5237+ const APFloat &Lo = getSecond ();
5238+
5239+ APFloat RoundedHi = Hi;
5240+ const opStatus HiStatus = RoundedHi.roundToIntegral (RM);
5241+
5242+ // We can reduce the problem to just the high part if the input:
5243+ // 1. Represents a non-finite value.
5244+ // 2. Has a component which is zero.
5245+ if (!Hi.isFiniteNonZero () || Lo.isZero ()) {
5246+ Floats[0 ] = std::move (RoundedHi);
5247+ Floats[1 ].makeZero (/* Neg=*/ false );
5248+ return HiStatus;
5249+ }
5250+
5251+ // Adjust `Rounded` in the direction of `TieBreaker` if `ToRound` was at a
5252+ // halfway point.
5253+ auto RoundToNearestHelper = [](APFloat ToRound, APFloat Rounded,
5254+ APFloat TieBreaker) {
5255+ // RoundingError tells us which direction we rounded:
5256+ // - RoundingError > 0: we rounded up.
5257+ // - RoundingError < 0: we rounded down.
5258+ // Sterbenz' lemma ensures that RoundingError is exact.
5259+ const APFloat RoundingError = Rounded - ToRound;
5260+ if (TieBreaker.isNonZero () &&
5261+ TieBreaker.isNegative () != RoundingError.isNegative () &&
5262+ abs (RoundingError).isExactlyValue (0.5 ))
5263+ Rounded.add (
5264+ APFloat::getOne (Rounded.getSemantics (), TieBreaker.isNegative ()),
5265+ rmNearestTiesToEven);
5266+ return Rounded;
5267+ };
5268+
5269+ // Case 1: Hi is not an integer.
5270+ // Special cases are for rounding modes that are sensitive to ties.
5271+ if (RoundedHi != Hi) {
5272+ // We need to consider the case where Hi was between two integers and the
5273+ // rounding mode broke the tie when, in fact, Lo may have had a different
5274+ // sign than Hi.
5275+ if (RM == rmNearestTiesToAway || RM == rmNearestTiesToEven)
5276+ RoundedHi = RoundToNearestHelper (Hi, RoundedHi, Lo);
5277+
5278+ Floats[0 ] = std::move (RoundedHi);
5279+ Floats[1 ].makeZero (/* Neg=*/ false );
5280+ return HiStatus;
5281+ }
5282+
5283+ // Case 2: Hi is an integer.
5284+ // Special cases are for rounding modes which are rounding towards or away from zero.
5285+ RoundingMode LoRoundingMode;
5286+ if (RM == rmTowardZero)
5287+ // When our input is positive, we want the Lo component rounded toward
5288+ // negative infinity to get the smallest result magnitude. Likewise,
5289+ // negative inputs want the Lo component rounded toward positive infinity.
5290+ LoRoundingMode = isNegative () ? rmTowardPositive : rmTowardNegative;
5291+ else
5292+ LoRoundingMode = RM;
5293+
5294+ APFloat RoundedLo = Lo;
5295+ const opStatus LoStatus = RoundedLo.roundToIntegral (LoRoundingMode);
5296+ if (LoRoundingMode == rmNearestTiesToAway)
5297+ // We need to consider the case where Lo was between two integers and the
5298+ // rounding mode broke the tie when, in fact, Hi may have had a different
5299+ // sign than Lo.
5300+ RoundedLo = RoundToNearestHelper (Lo, RoundedLo, Hi);
5301+
5302+ // We must ensure that the final result has no overlap between the two APFloat values.
5303+ std::tie (RoundedHi, RoundedLo) = fastTwoSum (RoundedHi, RoundedLo);
5304+
5305+ Floats[0 ] = std::move (RoundedHi);
5306+ Floats[1 ] = std::move (RoundedLo);
5307+ return LoStatus;
52255308}
52265309
52275310void DoubleAPFloat::changeSign () {
0 commit comments