squareRoot method
- FloatingPointValue value, {
- FloatingPointRoundingMode roundingMode = FloatingPointRoundingMode.roundNearestEven,
Computes square root exactly and rounds once into this format.
Implementation
FpvType squareRoot(FloatingPointValue value,
{FloatingPointRoundingMode roundingMode =
FloatingPointRoundingMode.roundNearestEven}) {
if (value.isNaN) {
return _quietNaNFrom(value);
}
if (value.isAZero) {
return _zero(value.sign.toBool());
}
if (value.sign.toBool()) {
return nan;
}
if (value.isAnInfinity) {
return _infinityOrLargestFinite(
negative: false, roundingMode: roundingMode);
}
final exact = _decodeFinite(value);
final floorLog2 = exact.significand.bitLength - 1 + exact.exponent;
var resultExponent =
floorLog2 >= 0 ? floorLog2 ~/ 2 : -((-floorLog2 + 1) ~/ 2);
final isSubnormal = resultExponent < minExponent;
if (isSubnormal) {
resultExponent = minExponent;
}
final fractionWidth = mantissaWidth - (explicitJBit ? 1 : 0);
final scaleExponent = exact.exponent + 2 * (fractionWidth - resultExponent);
final BigInt truncated;
final bool exactResult;
final int midpointComparison;
if (scaleExponent >= 0) {
final scaledRadicand = exact.significand << scaleExponent;
truncated = _integerSquareRoot(scaledRadicand);
exactResult = truncated * truncated == scaledRadicand;
final midpoint = (truncated << 1) + BigInt.one;
midpointComparison = (scaledRadicand << 2).compareTo(midpoint * midpoint);
} else {
final denominatorShift = -scaleExponent;
truncated = _integerSquareRoot(exact.significand >> denominatorShift);
exactResult =
(truncated * truncated) << denominatorShift == exact.significand;
final midpoint = (truncated << 1) + BigInt.one;
midpointComparison = (exact.significand << 2)
.compareTo((midpoint * midpoint) << denominatorShift);
}
final increment = !exactResult &&
switch (roundingMode) {
FloatingPointRoundingMode.truncate ||
FloatingPointRoundingMode.roundTowardsZero ||
FloatingPointRoundingMode.roundTowardsNegativeInfinity =>
false,
FloatingPointRoundingMode.roundTowardsInfinity => true,
FloatingPointRoundingMode.roundNearestTiesAway =>
midpointComparison >= 0,
FloatingPointRoundingMode.roundNearestEven =>
midpointComparison > 0 ||
(midpointComparison == 0 && truncated.isOdd),
};
final significand = increment ? truncated + BigInt.one : truncated;
return _packRounded(significand, resultExponent,
negative: false, wasSubnormal: isSubnormal, roundingMode: roundingMode);
}