Revision ef18eb33
Added by David Sorber about 4 years ago
| 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;
|
||
|
}
|
||
|
|
||
Correct multiply by integer operator. Also add test cases.