private static SqlDecimal Round(SqlDecimal n, int lPosition, bool fTruncate)
{
if (n.IsNull)
return SqlDecimal.Null;
if (lPosition >= 0)
{
//If round to the right of decimal number
lPosition = Math.Min(s_NUMERIC_MAX_PRECISION, lPosition);
if (lPosition >= n.m_bScale)
return n; //No need to round
}
else
{
//If round to the left of the decimal point
lPosition = Math.Max(-s_NUMERIC_MAX_PRECISION, lPosition);
//Return +0.00 if truncation of integer part
if (lPosition < n.m_bScale - n.m_bPrec)
{
n.SetToZero();
return n;
}
}
uint ulRem = 0; // Remainder: the highest significant digit to be truncated
int lAdjust = Math.Abs(lPosition - (int)n.m_bScale); // Precision adjustment
uint ulLastDivBase = 1; //
//Compute the integral part of the numeric
while (lAdjust > 0)
{
if (lAdjust >= 9)
{
ulRem = n.DivByULong(s_rgulShiftBase[8]);
ulLastDivBase = s_rgulShiftBase[8];
lAdjust -= 9;
}
else
{
ulRem = n.DivByULong(s_rgulShiftBase[lAdjust - 1]);
ulLastDivBase = s_rgulShiftBase[lAdjust - 1];
lAdjust = 0;
}
}
// The rounding only depends on the first digit after the rounding position
if (ulLastDivBase > 1)
{
ulRem /= (ulLastDivBase / 10);
}
//If result is zero, return
if (n.FZero() && (fTruncate || ulRem < 5))
{
n.SetPositive();
n.AssertValid();
return n;
}
// Adjust by adding 1 if remainder is larger than 5
if (ulRem >= 5 && !fTruncate)
n.AddULong(1);
// Convert back to original scale
lAdjust = Math.Abs(lPosition - n.m_bScale);
while (lAdjust-- > 0)
{
n.MultByULong(s_ulBase10);
}
n.AssertValid();
return n;
}