Project

General

Profile

« Previous | Next » 

Revision ef18eb33

Added by David Sorber about 4 years ago

Correct multiply by integer operator. Also add test cases.

View differences:

software/fixed/fixed.h
constexpr inline fixed<I, F, STI, STF> operator*(
const fixed<I, F, STI, STF>& x, const int64_t& y)
{
fixed<I, F, STI, STF> newVal;
//~ bool negativeDivisorFlag = (y < 0);
//~ bool negativeDividendFlag = (x.m_integer < 0) ||
//~ (x.m_integer == fixed<I, F, STI, STF>::NEGATIVE_ZERO);
//~ bool negativeZeroFlag = false;
//~ I integerX = x.m_integer;
//~ if (__unlikely((integerX == fixed<I, F, STI, STF>::NEGATIVE_ZERO)))
//~ {
//~ integerX = 0;
//~ negativeZeroFlag = true;
//~ }
// Straight multiply for integer portion
newVal.m_integer = x.m_integer * y;
// Set flag to indicate if result should be negative
bool negativeResultFlag = false;
I integerX = x.m_integer;
if (__unlikely((integerX == fixed<I, F, STI, STF>::NEGATIVE_ZERO)))
{
integerX = 0;
negativeResultFlag = true;
}
else if (integerX < 0)
{
integerX *= -1;
negativeResultFlag = true;
}
std::cout << "INTEGER: " << newVal.m_integer << std::endl;
int64_t multiplier = y;
if (multiplier < 0)
{
// Ensure that multiplier is positive to avoid issues with
// signed/unsigned operations
multiplier *= -1;
// Toggle negative results flag
negativeResultFlag = !negativeResultFlag;
}
std::cout << "Frac digits: " << fixed<I, F, STI, STF>::fractional_decimal_digits << std::endl;
std::cout << "Half Frac digits: " << (fixed<I, F, STI, STF>::fractional_decimal_digits / 2) << std::endl;
// Multiply integer portion first
fixed<I, F, STI, STF> newVal;
newVal.m_integer = integerX * multiplier;
uint32_t index = (fixed<I, F, STI, STF>::fractional_decimal_digits / 2);
uint32_t indexUpper = (fixed<I, F, STI, STF>::fractional_decimal_digits / 2);
uint32_t indexLower = (fixed<I, F, STI, STF>::fractional_decimal_digits - indexUpper);
#if SUPPORT_128_INTS
uint128_t scaler = fixed<I, F, STI, STF>::SCALE_VALUES[index];
uint128_t scalerUpper = fixed<I, F, STI, STF>::SCALE_VALUES[indexUpper];
uint128_t scalerLower = fixed<I, F, STI, STF>::SCALE_VALUES[indexLower];
#else
uint64_t scaler = fixed<I, F, STI, STF>::SCALE_VALUES[index];
uint64_t scalerUpper = fixed<I, F, STI, STF>::SCALE_VALUES[indexUpper];
uint64_t scalerLower = fixed<I, F, STI, STF>::SCALE_VALUES[indexLower];
#endif
// Compute the lower portion
F fracLower = (x.m_fractional % scalerLower) * multiplier;
// Handle upper and lower portions of fractional value separarely so that
// the integer carry can be handled
std::cout << "[1] FRAC upper: " << (x.m_fractional / scaler) << std::endl;
F fracUpper = (x.m_fractional / scaler) * y;
std::cout << "[2] FRAC upper: " << fracUpper << std::endl;
newVal.m_fractional = (fracUpper % (scaler * 10)) * scaler;
std::cout << "NEW FRAC upper: " << newVal.m_fractional << std::endl;
// Compute lower carry explicitly as it may trigger an additional carry,
// then rescale lower portion to remove carry
F carryLower = fracLower / scalerLower;
fracLower %= scalerLower;
F carry = (fracUpper / (scaler * 10));
std::cout << "Carry: " << carry << std::endl;
newVal.m_integer += carry;
// Compute upper portion
F fracUpper = ((x.m_fractional / scalerLower) * multiplier) + carryLower;
newVal.m_fractional = (fracUpper % scalerUpper) * scalerLower;
F fracLower = (x.m_fractional % scaler) * y;
std::cout << "FRAC lower: " << fracLower << std::endl;
// Computer integer carry then add it to integer portion
newVal.m_integer += (fracUpper / scalerUpper);
// Finally add the lower fractional portion, which at this point will not
// trigger a carry
newVal.m_fractional += fracLower;
// If negative result flag was set ensure that final result is negative
if (negativeResultFlag)
{
if (newVal.m_integer == 0 && newVal.m_fractional > 0)
{
newVal.m_integer = fixed<I, F, STI, STF>::NEGATIVE_ZERO;
}
else if (newVal.m_integer > 0)
{
newVal.m_integer *= -1;
}
}
return newVal;
}

Also available in: Unified diff