Revision b9f341b6
Added by David Sorber over 4 years ago
| software/fixed/fixed.h | ||
|---|---|---|
|
#define __likely(cond) (cond)
|
||
|
#endif
|
||
|
|
||
|
// Defaults for compile time options
|
||
|
#ifndef BEHAVIOR_PARSE_TRUNCATE
|
||
|
#define BEHAVIOR_PARSE_TRUNCATE 0 // Default: disable
|
||
|
#endif
|
||
|
|
||
|
#ifndef SUPPORT_PARSE_EXPONENT
|
||
|
#define SUPPORT_PARSE_EXPONENT 1 // Default: enable
|
||
|
#endif
|
||
|
|
||
|
template<typename T>
|
||
|
constexpr T calculateMax(size_t decimal_digits)
|
||
|
{
|
||
| ... | ... | |
|
std::floor(std::log10(std::numeric_limits<IntegerType>::max()));
|
||
|
static constexpr size_t fractional_decimal_digits =
|
||
|
std::floor(std::log10(std::numeric_limits<FractionalType>::max()));
|
||
|
static constexpr size_t total_decimal_digits = integer_decimal_digits +
|
||
|
fractional_decimal_digits;
|
||
|
|
||
|
static constexpr IntegerType MAX_INTEGER_VALUE =
|
||
|
(calculateMax<IntegerType>(integer_decimal_digits));
|
||
| ... | ... | |
|
(calculateMax<FractionalType>(fractional_decimal_digits));
|
||
|
static constexpr FractionalType MIN_FRACTIONAL_VALUE = 0;
|
||
|
|
||
|
static constexpr IntegerType NEGATIVE_ZERO = MAX_INTEGER_VALUE + 2;
|
||
|
|
||
|
static const uint64_t SCALE_VALUES[20];
|
||
|
static const std::map<uint64_t, uint32_t> DIGIT_LOOKUP_TABLE;
|
||
|
|
||
|
// Constructors
|
||
|
fixed()
|
||
|
explicit fixed()
|
||
|
: m_integer(0),
|
||
|
m_fractional(0)
|
||
|
{}
|
||
|
|
||
|
fixed(IntegerType integerVal)
|
||
|
explicit fixed(IntegerType integerVal)
|
||
|
: m_integer(__checkIntOverflow(integerVal)),
|
||
|
m_fractional(0)
|
||
|
{}
|
||
|
|
||
|
fixed(IntegerType integerVal, FractionalType fractionalVal)
|
||
|
explicit fixed(IntegerType integerVal, FractionalType fractionalVal)
|
||
|
: m_integer(__checkIntOverflow(integerVal)),
|
||
|
m_fractional(__checkFracOverflow(fractionalVal))
|
||
|
{
|
||
| ... | ... | |
|
getFracScaleValue(m_fractional));
|
||
|
}
|
||
|
|
||
|
fixed(IntegerType integerVal, FractionalType fractionalVal, uint32_t leadingZeros)
|
||
|
explicit fixed(IntegerType integerVal, FractionalType fractionalVal, uint32_t leadingZeros)
|
||
|
: m_integer(__checkIntOverflow(integerVal)),
|
||
|
m_fractional(__checkFracOverflow(fractionalVal))
|
||
|
{
|
||
| ... | ... | |
|
char* endPtr = nullptr;
|
||
|
m_integer = __checkIntOverflow(strto_inttype(input, &endPtr, 10));
|
||
|
m_fractional = 0;
|
||
|
bool negativeZeroFlag = false;
|
||
|
|
||
|
if (std::isdigit(*endPtr))
|
||
|
{
|
||
|
throw std::out_of_range("Integer value is out of range.");
|
||
|
}
|
||
|
|
||
|
// Check for negative zero corner case with leading zero digit
|
||
|
if (__unlikely(m_integer == 0 && endPtr - input >= 2 && *(endPtr - 2) == '-'))
|
||
|
{
|
||
|
negativeZeroFlag = true;
|
||
|
}
|
||
|
|
||
|
// If the ending char is a period we can now parse the fractional part
|
||
|
if (*endPtr == '.')
|
||
|
uint32_t fracLen = 0;
|
||
|
if (*endPtr == '.'|| (endPtr[0] == '-' && endPtr[1] == '.'))
|
||
|
{
|
||
|
// Check for negative zero corner case without leading zero digit
|
||
|
if (__unlikely(endPtr[0] == '-'))
|
||
|
{
|
||
|
++endPtr;
|
||
|
negativeZeroFlag = true;
|
||
|
}
|
||
|
|
||
|
char* fracEndPtr = nullptr;
|
||
|
FractionalType fracTemp =
|
||
|
__checkFracOverflow(strto_fractype(endPtr + 1, &fracEndPtr, 10));
|
||
|
|
||
|
uint32_t fracLen = (fracEndPtr - endPtr) - 1;
|
||
|
fracLen = fractional_decimal_digits - fracLen;
|
||
|
|
||
|
m_fractional = __checkFracOverflow(fracTemp * SCALE_VALUES[fracLen]);
|
||
|
fracLen = (fracEndPtr - endPtr) - 1;
|
||
|
if (__unlikely(fracLen > fractional_decimal_digits))
|
||
|
{
|
||
|
#if BEHAVIOR_PARSE_TRUNCATE
|
||
|
// Fractional length exceeds supported number of fractional
|
||
|
// decimal digits, downscale value to only include supported
|
||
|
// number of digits
|
||
|
uint32_t idx = fracLen - fractional_decimal_digits;
|
||
|
m_fractional = fracTemp / SCALE_VALUES[idx];
|
||
|
#else
|
||
|
throw std::out_of_range("Fractional length exceeds supported "
|
||
|
"number of fractional decimal digits.");
|
||
|
#endif
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uint32_t idx = fractional_decimal_digits - fracLen;
|
||
|
m_fractional = __checkFracOverflow(fracTemp * SCALE_VALUES[idx]);
|
||
|
}
|
||
|
endPtr = fracEndPtr;
|
||
|
}
|
||
|
|
||
|
#if SUPPORT_PARSE_EXPONENT
|
||
|
// Attempt to parse exponent
|
||
|
if (*endPtr == 'e' || *endPtr == 'E')
|
||
|
{
|
||
|
// Set negative zero flag here if integer part is negative then
|
||
|
// clear below if final integer part after exponent adjustment is
|
||
|
// not zero
|
||
|
if (m_integer < 0)
|
||
|
{
|
||
|
negativeZeroFlag = true;
|
||
|
}
|
||
|
|
||
|
char* expEndPtr = nullptr;
|
||
|
long exponent = strtol(++endPtr, &expEndPtr, 10);
|
||
|
uint32_t integerLen = 0;
|
||
|
if (m_integer != 0)
|
||
|
{
|
||
|
integerLen = DIGIT_LOOKUP_TABLE.upper_bound(std::abs(m_integer))->second;
|
||
|
}
|
||
|
uint32_t scaledFracLen =
|
||
|
DIGIT_LOOKUP_TABLE.upper_bound(m_fractional)->second;
|
||
|
|
||
|
if (exponent >= 0)
|
||
|
{
|
||
|
// Detect potential overflow based on the exponent
|
||
|
if ((m_integer != 0) &&
|
||
|
(integerLen + static_cast<size_t>(exponent)) >
|
||
|
integer_decimal_digits)
|
||
|
{
|
||
|
throw std::out_of_range("Positive exponent exceeds maximum"
|
||
|
" decimal digit range.");
|
||
|
}
|
||
|
else if (scaledFracLen + static_cast<size_t>(exponent)
|
||
|
> total_decimal_digits)
|
||
|
{
|
||
|
throw std::out_of_range("Positive exponent exceeds maximum"
|
||
|
" decimal digit range (2).");
|
||
|
}
|
||
|
|
||
|
long fracExponent = exponent;
|
||
|
if (static_cast<size_t>(fracExponent) > fractional_decimal_digits)
|
||
|
{
|
||
|
fracExponent = fractional_decimal_digits;
|
||
|
}
|
||
|
|
||
|
bool intZeroFlag = true;
|
||
|
if (m_integer != 0)
|
||
|
{
|
||
|
// Rescale integer value if it is greater than zero
|
||
|
intZeroFlag = false;
|
||
|
m_integer *= static_cast<IntegerType>(SCALE_VALUES[exponent]);
|
||
|
}
|
||
|
|
||
|
uint64_t scaler = SCALE_VALUES[fractional_decimal_digits -
|
||
|
fracExponent];
|
||
|
IntegerType temp = m_fractional / scaler;
|
||
|
m_integer += temp;
|
||
|
m_fractional -= (temp * scaler);
|
||
|
m_fractional *= SCALE_VALUES[fracExponent];
|
||
|
|
||
|
if (intZeroFlag)
|
||
|
{
|
||
|
// Rescale integer value if it was zero
|
||
|
m_integer *= SCALE_VALUES[exponent - fracExponent];
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// Handle negative exponent
|
||
|
// Detect potential overflow based on the exponent
|
||
|
if (m_fractional != 0 &&
|
||
|
(static_cast<size_t>(-exponent) >
|
||
|
(fractional_decimal_digits - fracLen)))
|
||
|
{
|
||
|
throw std::out_of_range("Negative exponent exceeds maximum"
|
||
|
" decimal digit range.");
|
||
|
}
|
||
|
else if (static_cast<size_t>(-exponent) >=
|
||
|
(integerLen + fractional_decimal_digits))
|
||
|
{
|
||
|
throw std::out_of_range("Negative exponent exceeds maximum"
|
||
|
" decimal digit range.");
|
||
|
}
|
||
|
|
||
|
FractionalType temp = 0;
|
||
|
if (m_fractional != 0)
|
||
|
{
|
||
|
// CASE 1: fractional non-zero
|
||
|
m_fractional /= SCALE_VALUES[-exponent];
|
||
|
temp = std::abs(m_integer) % SCALE_VALUES[-exponent];
|
||
|
temp *= SCALE_VALUES[fractional_decimal_digits + exponent];
|
||
|
m_integer /= static_cast<IntegerType>(SCALE_VALUES[-exponent]);
|
||
|
m_fractional += temp;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// CASE 2: fractional zero
|
||
|
long intExponent = std::abs(exponent);
|
||
|
if (static_cast<size_t>(intExponent) > integer_decimal_digits)
|
||
|
{
|
||
|
intExponent = integer_decimal_digits;
|
||
|
}
|
||
|
|
||
|
temp = std::abs(m_integer) % SCALE_VALUES[intExponent];
|
||
|
temp *= SCALE_VALUES[fractional_decimal_digits - intExponent];
|
||
|
m_integer /= SCALE_VALUES[intExponent];
|
||
|
m_fractional += temp;
|
||
|
|
||
|
if (std::abs(exponent) > intExponent)
|
||
|
{
|
||
|
long fracExponent = std::abs(exponent) - intExponent;
|
||
|
m_fractional /= SCALE_VALUES[fracExponent];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Clear negative zero flag if final adjusted integer part is not
|
||
|
// zero. Flag will remain set iff initial integer part was negative
|
||
|
// and integer part after exponent adjustment is zero.
|
||
|
if (__likely(m_integer != 0))
|
||
|
{
|
||
|
negativeZeroFlag = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
if (__unlikely(negativeZeroFlag))
|
||
|
{
|
||
|
m_integer = NEGATIVE_ZERO;
|
||
|
}
|
||
|
|
||
|
// Calculate and return overall length
|
||
|
return (endPtr - input);
|
||
|
}
|
||
|
|
||
|
void absval()
|
||
|
constexpr inline void absval()
|
||
|
{
|
||
|
m_integer = abs(m_integer);
|
||
|
if (__unlikely(m_integer == NEGATIVE_ZERO))
|
||
|
{
|
||
|
m_integer = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_integer = std::abs(m_integer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// This is modeled after std::signbit() for floating point types
|
||
|
constexpr inline bool signbit() const
|
||
|
{
|
||
|
return (m_integer < 0 || m_integer == NEGATIVE_ZERO);
|
||
|
}
|
||
|
|
||
|
constexpr inline void negate()
|
||
|
{
|
||
|
if (__unlikely(m_integer == 0))
|
||
|
{
|
||
|
m_integer = NEGATIVE_ZERO;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_integer *= -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Disallow conversion operators (for now)
|
||
|
explicit operator int() = delete;
|
||
|
explicit operator float() = delete;
|
||
|
explicit operator double() = delete;
|
||
|
|
||
|
constexpr inline fixed operator-() const noexcept = delete;
|
||
|
constexpr inline fixed operator!() const noexcept = delete;
|
||
| ... | ... | |
|
// Divide by unsigned int
|
||
|
template<typename I, typename F, typename STI, typename STF>
|
||
|
friend constexpr inline fixed<I, F, STI, STF> operator/(
|
||
|
const fixed<I, F, STI, STF>& x, const uint64_t& y);
|
||
|
const fixed<I, F, STI, STF>& x, const int64_t& y);
|
||
|
|
||
|
// Output stream operator
|
||
|
template<typename I, typename F, typename STI, typename STF>
|
||
| ... | ... | |
|
return fractionalVal;
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
// Helper function to get the approprate scale value for an unscaled input
|
||
|
// value of the fractional type
|
||
|
static inline FractionalType getFracScaleValue(
|
||
| ... | ... | |
|
return SCALE_VALUES[index];
|
||
|
}
|
||
|
|
||
|
public:
|
||
|
IntegerType m_integer;
|
||
|
FractionalType m_fractional;
|
||
|
};
|
||
| ... | ... | |
|
constexpr inline bool operator<(
|
||
|
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
|
||
|
{
|
||
|
if (x.m_integer == y.m_integer)
|
||
|
if (x.signbit() && (! y.signbit()))
|
||
|
{
|
||
|
return (x.m_fractional < y.m_fractional);
|
||
|
return true;
|
||
|
}
|
||
|
else if ((! x.signbit()) && y.signbit())
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (x.m_integer < y.m_integer);
|
||
|
I integerX = x.m_integer;
|
||
|
if (__unlikely((x.m_integer == fixed<I, F, STI, STF>::NEGATIVE_ZERO)))
|
||
|
{
|
||
|
integerX = 0;
|
||
|
}
|
||
|
|
||
|
I integerY = y.m_integer;
|
||
|
if (__unlikely((y.m_integer == fixed<I, F, STI, STF>::NEGATIVE_ZERO)))
|
||
|
{
|
||
|
integerY = 0;
|
||
|
}
|
||
|
|
||
|
if (integerX == integerY)
|
||
|
{
|
||
|
return (x.m_fractional < y.m_fractional);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (integerX < integerY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
| ... | ... | |
|
constexpr inline bool operator>(
|
||
|
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
|
||
|
{
|
||
|
if (x.m_integer == y.m_integer)
|
||
|
if (x.signbit() && (! y.signbit()))
|
||
|
{
|
||
|
return false;
|
||
|
}
|
||
|
else if ((! x.signbit()) && y.signbit())
|
||
|
{
|
||
|
return (x.m_fractional > y.m_fractional);
|
||
|
return true;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (x.m_integer > y.m_integer);
|
||
|
I integerX = x.m_integer;
|
||
|
if (__unlikely((x.m_integer == fixed<I, F, STI, STF>::NEGATIVE_ZERO)))
|
||
|
{
|
||
|
integerX = 0;
|
||
|
}
|
||
|
|
||
|
I integerY = y.m_integer;
|
||
|
if (__unlikely((y.m_integer == fixed<I, F, STI, STF>::NEGATIVE_ZERO)))
|
||
|
{
|
||
|
integerY = 0;
|
||
|
}
|
||
|
|
||
|
if (integerX == integerY)
|
||
|
{
|
||
|
return (x.m_fractional > y.m_fractional);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (integerX > integerY);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
| ... | ... | |
|
constexpr inline bool operator<=(
|
||
|
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
|
||
|
{
|
||
|
if (x.m_integer == y.m_integer)
|
||
|
{
|
||
|
return (x.m_fractional <= y.m_fractional);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (x.m_integer < y.m_integer);
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
return (x == y || x < y);
|
||
|
}
|
||
|
|
||
|
template<typename I, typename F, typename STI, typename STF>
|
||
|
constexpr inline bool operator>=(
|
||
|
const fixed<I, F, STI, STF>& x, const fixed<I, F, STI, STF>& y) noexcept
|
||
|
{
|
||
|
if (x.m_integer == y.m_integer)
|
||
|
{
|
||
|
return (x.m_fractional >= y.m_fractional);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (x.m_integer > y.m_integer);
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
return (x == y || x > y);
|
||
|
}
|
||
|
|
||
|
// Addition -- not yet supported
|
||
| ... | ... | |
|
// Division by unsigned int
|
||
|
template<typename I, typename F, typename STI, typename STF>
|
||
|
constexpr inline fixed<I, F, STI, STF> operator/(
|
||
|
const fixed<I, F, STI, STF>& x, const uint64_t& y)
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
newVal.m_integer = integerX / y;
|
||
|
newVal.m_fractional = std::abs(integerX) % y;
|
||
|
newVal.m_fractional *= x.getFracScaleValue(newVal.m_fractional);
|
||
|
newVal.m_fractional += x.m_fractional / std::abs(y);
|
||
|
|
||
|
// Ensure quotient has correct sign value
|
||
|
if (newVal.m_integer == 0 && negativeDividendFlag && negativeDivisorFlag)
|
||
|
{
|
||
|
newVal.m_integer = 0;
|
||
|
}
|
||
|
else if ((newVal.m_integer == 0 && (negativeDividendFlag || negativeDivisorFlag))
|
||
|
|| __unlikely(negativeZeroFlag))
|
||
|
{
|
||
|
fixed<I, F, STI, STF> newVal;
|
||
|
newVal.m_integer = x.m_integer / y;
|
||
|
newVal.m_fractional = x.m_integer % y;
|
||
|
newVal.m_fractional *= x.getFracScaleValue(newVal.m_fractional);
|
||
|
newVal.m_fractional += x.m_fractional / y;
|
||
|
return newVal;
|
||
|
newVal.m_integer = fixed<I, F, STI, STF>::NEGATIVE_ZERO;
|
||
|
}
|
||
|
|
||
|
return newVal;
|
||
|
}
|
||
|
|
||
|
// Stream output
|
||
|
template<typename I, typename F, typename STI, typename STF>
|
||
| ... | ... | |
|
break;
|
||
|
}
|
||
|
}
|
||
|
if (found)
|
||
|
if (found || idx == -1)
|
||
|
{
|
||
|
buffer[idx + 1] = '\0';
|
||
|
}
|
||
|
|
||
|
uint32_t leadingZeros =
|
||
|
uint32_t leadingZeros = (rhs.m_fractional == 0) ? 1 :
|
||
|
fixed<I, F, STI, STF>::fractional_decimal_digits -
|
||
|
fixed<I, F, STI, STF>::DIGIT_LOOKUP_TABLE.upper_bound(rhs.m_fractional)->second;
|
||
|
|
||
|
// Handle special case of negative zero
|
||
|
os << std::fixed;
|
||
|
if (__unlikely((rhs.m_integer == fixed<I, F, STI, STF>::NEGATIVE_ZERO)))
|
||
|
{
|
||
|
os << "-0.";
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
os << rhs.m_integer << ".";
|
||
|
}
|
||
|
|
||
|
// Output any leading zeros
|
||
|
os << std::fixed << rhs.m_integer << ".";
|
||
|
// Output any fractional leading zeros
|
||
|
for (uint32_t idx = 0; idx < leadingZeros; ++idx)
|
||
|
{
|
||
|
os << "0";
|
||
| software/fixed/fixed_test.cc | ||
|---|---|---|
|
#include <cstdint>
|
||
|
#include <limits>
|
||
|
#include <random>
|
||
|
#include <stdexcept>
|
||
|
#include <sstream>
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
| ... | ... | |
|
|
||
|
#include "fixed.h"
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t0)
|
||
|
// Helper macros
|
||
|
#define VALUE_CHECK(val) \
|
||
|
output.str(""); \
|
||
|
output << value; \
|
||
|
BOOST_CHECK(output.str() == val);
|
||
|
|
||
|
#define PARSE_VALUE_CHECK(val) \
|
||
|
value.parse(input); \
|
||
|
output.str(""); \
|
||
|
output << value; \
|
||
|
BOOST_CHECK(output.str() == val);
|
||
|
|
||
|
|
||
|
#define PARSE_EXCEPTION_CHECK \
|
||
|
exception = false; \
|
||
|
try \
|
||
|
{ \
|
||
|
value.parse(input); \
|
||
|
} \
|
||
|
catch (const std::out_of_range& exp) \
|
||
|
{ \
|
||
|
exception = true; \
|
||
|
} \
|
||
|
BOOST_CHECK(exception);
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t000)
|
||
|
{
|
||
|
/* TEST CASE 0: Check storage sizes (in bytes) of all predefined fixed
|
||
|
* point types.
|
||
| ... | ... | |
|
BOOST_CHECK(sizeof(f_64_64) == 16);
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t1)
|
||
|
BOOST_AUTO_TEST_CASE(t001)
|
||
|
{
|
||
|
/* TEST CASE 1: Test basic comparisons
|
||
|
*/
|
||
| ... | ... | |
|
BOOST_CHECK(! (val1 <= val2));
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t2)
|
||
|
BOOST_AUTO_TEST_CASE(t002)
|
||
|
{
|
||
|
/* TEST CASE 2: Test parsing with leading zeros.
|
||
|
*/
|
||
| ... | ... | |
|
BOOST_CHECK(val1 == val2);
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t3)
|
||
|
BOOST_AUTO_TEST_CASE(t003)
|
||
|
{
|
||
|
/* TEST CASE 3: Test parsing and printing randomly generated values
|
||
|
*/
|
||
| ... | ... | |
|
std::mt19937 rng;
|
||
|
rng.seed(SEED);
|
||
|
|
||
|
std::uniform_int_distribution<std::mt19937::result_type> negative(0, 1);
|
||
|
std::uniform_int_distribution<std::mt19937::result_type> intDigits(1, theType::integer_decimal_digits);
|
||
|
std::uniform_int_distribution<std::mt19937::result_type> fracDigits(1, theType::fractional_decimal_digits);
|
||
|
std::uniform_int_distribution<std::mt19937::result_type> digits(0, 9);
|
||
| ... | ... | |
|
for (uint32_t idx = 0; idx < NUMBER; ++idx)
|
||
|
{
|
||
|
std::ostringstream output;
|
||
|
|
||
|
// Decide if the number should be negative
|
||
|
if (negative(rng) == 1)
|
||
|
{
|
||
|
output << "-";
|
||
|
}
|
||
|
|
||
|
// Generate random integer number digits
|
||
|
for (uint32_t integerIdx = 0; integerIdx < intDigits(rng); ++integerIdx)
|
||
|
{
|
||
| ... | ... | |
|
output << ".";
|
||
|
|
||
|
// Generate random fractional number digits
|
||
|
int numFracDigits = fracDigits(rng);
|
||
|
uint32_t numFracDigits = fracDigits(rng);
|
||
|
for (uint32_t fracIdx = 0; fracIdx < numFracDigits; ++fracIdx)
|
||
|
{
|
||
|
int digit = digits(rng);
|
||
| ... | ... | |
|
}
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t4)
|
||
|
BOOST_AUTO_TEST_CASE(t004)
|
||
|
{
|
||
|
/* TEST CASE 4: Basic test division by unsigned integer
|
||
|
*/
|
||
| ... | ... | |
|
BOOST_CHECK(answer == val2);
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t005)
|
||
|
{
|
||
|
/* TEST CASE 5: Test parsing a decimal number with a larger than supported
|
||
|
* fractional part.
|
||
|
*/
|
||
|
|
||
|
const char* input = ".00010102030508132134";
|
||
|
|
||
|
fixed_64_64 value;
|
||
|
#if 0
|
||
|
value.parse(input);
|
||
|
|
||
|
std::ostringstream output;
|
||
|
output << value;
|
||
|
|
||
|
BOOST_CHECK(output.str() == "0.0001010203050813213");
|
||
|
#else
|
||
|
bool exception = false;
|
||
|
try
|
||
|
{
|
||
|
value.parse(input);
|
||
|
}
|
||
|
catch (const std::out_of_range& exp)
|
||
|
{
|
||
|
exception = true;
|
||
|
}
|
||
|
BOOST_CHECK(exception);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t006)
|
||
|
{
|
||
|
/* TEST CASE 6: zero integer, positive exponent, walking one positive test
|
||
|
* cases
|
||
|
*/
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
|
const char* input = "0.0000000000000000001e36";
|
||
|
PARSE_VALUE_CHECK("100000000000000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e35";
|
||
|
PARSE_VALUE_CHECK("10000000000000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e34";
|
||
|
PARSE_VALUE_CHECK("1000000000000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e33";
|
||
|
PARSE_VALUE_CHECK("100000000000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e32";
|
||
|
PARSE_VALUE_CHECK("10000000000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e31";
|
||
|
PARSE_VALUE_CHECK("1000000000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e30";
|
||
|
PARSE_VALUE_CHECK("100000000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e29";
|
||
|
PARSE_VALUE_CHECK("10000000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e28";
|
||
|
PARSE_VALUE_CHECK("1000000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e27";
|
||
|
PARSE_VALUE_CHECK("100000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e26";
|
||
|
PARSE_VALUE_CHECK("10000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e25";
|
||
|
PARSE_VALUE_CHECK("1000000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e24";
|
||
|
PARSE_VALUE_CHECK("100000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e23";
|
||
|
PARSE_VALUE_CHECK("10000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e22";
|
||
|
PARSE_VALUE_CHECK("1000.0");
|
||
|
|
||
|
input = "0.0000000000000000001e21";
|
||
|
PARSE_VALUE_CHECK("100.0");
|
||
|
|
||
|
input = "0.0000000000000000001e20";
|
||
|
PARSE_VALUE_CHECK("10.0");
|
||
|
|
||
|
input = "0.0000000000000000001e19";
|
||
|
PARSE_VALUE_CHECK("1.0");
|
||
|
|
||
|
// Cross over
|
||
|
input = "0.0000000000000000001e18";
|
||
|
PARSE_VALUE_CHECK("0.1");
|
||
|
|
||
|
input = "0.0000000000000000001e17";
|
||
|
PARSE_VALUE_CHECK("0.01");
|
||
|
|
||
|
input = "0.0000000000000000001e16";
|
||
|
PARSE_VALUE_CHECK("0.001");
|
||
|
|
||
|
input = "0.0000000000000000001e15";
|
||
|
PARSE_VALUE_CHECK("0.0001");
|
||
|
|
||
|
input = "0.0000000000000000001e14";
|
||
|
PARSE_VALUE_CHECK("0.00001");
|
||
|
|
||
|
input = "0.0000000000000000001e13";
|
||
|
PARSE_VALUE_CHECK("0.000001");
|
||
|
|
||
|
input = "0.0000000000000000001e12";
|
||
|
PARSE_VALUE_CHECK("0.0000001");
|
||
|
|
||
|
input = "0.0000000000000000001e11";
|
||
|
PARSE_VALUE_CHECK("0.00000001");
|
||
|
|
||
|
input = "0.0000000000000000001e10";
|
||
|
PARSE_VALUE_CHECK("0.000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e9";
|
||
|
PARSE_VALUE_CHECK("0.0000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e8";
|
||
|
PARSE_VALUE_CHECK("0.00000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e7";
|
||
|
PARSE_VALUE_CHECK("0.000000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e6";
|
||
|
PARSE_VALUE_CHECK("0.0000000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e5";
|
||
|
PARSE_VALUE_CHECK("0.00000000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e4";
|
||
|
PARSE_VALUE_CHECK("0.000000000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e3";
|
||
|
PARSE_VALUE_CHECK("0.0000000000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e2";
|
||
|
PARSE_VALUE_CHECK("0.00000000000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e1";
|
||
|
PARSE_VALUE_CHECK("0.000000000000000001");
|
||
|
|
||
|
input = "0.0000000000000000001e0";
|
||
|
PARSE_VALUE_CHECK("0.0000000000000000001");
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t007)
|
||
|
{
|
||
|
/* TEST CASE 7: non-zero integer, positive exponent, walking value
|
||
|
* positive+negative test cases
|
||
|
*/
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
|
const char* input = "1.0000000000000000001e1";
|
||
|
PARSE_VALUE_CHECK("10.000000000000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e2";
|
||
|
PARSE_VALUE_CHECK("100.00000000000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e3";
|
||
|
PARSE_VALUE_CHECK("1000.0000000000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e4";
|
||
|
PARSE_VALUE_CHECK("10000.000000000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e5";
|
||
|
PARSE_VALUE_CHECK("100000.00000000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e6";
|
||
|
PARSE_VALUE_CHECK("1000000.0000000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e7";
|
||
|
PARSE_VALUE_CHECK("10000000.000000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e8";
|
||
|
PARSE_VALUE_CHECK("100000000.00000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e9";
|
||
|
PARSE_VALUE_CHECK("1000000000.0000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e10";
|
||
|
PARSE_VALUE_CHECK("10000000000.000000001");
|
||
|
|
||
|
input = "1.0000000000000000001e11";
|
||
|
PARSE_VALUE_CHECK("100000000000.00000001");
|
||
|
|
||
|
input = "1.0000000000000000001e12";
|
||
|
PARSE_VALUE_CHECK("1000000000000.0000001");
|
||
|
|
||
|
input = "1.0000000000000000001e13";
|
||
|
PARSE_VALUE_CHECK("10000000000000.000001");
|
||
|
|
||
|
input = "1.0000000000000000001e14";
|
||
|
PARSE_VALUE_CHECK("100000000000000.00001");
|
||
|
|
||
|
input = "1.0000000000000000001e15";
|
||
|
PARSE_VALUE_CHECK("1000000000000000.0001");
|
||
|
|
||
|
input = "1.0000000000000000001e16";
|
||
|
PARSE_VALUE_CHECK("10000000000000000.001");
|
||
|
|
||
|
input = "1.0000000000000000001e17";
|
||
|
PARSE_VALUE_CHECK("100000000000000000.01");
|
||
|
|
||
|
input = "1.0000000000000000001e18";
|
||
|
bool exception = false;
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t008)
|
||
|
{
|
||
|
/* TEST CASE 8: zero integer, positive exponent, walking one negative test
|
||
|
* cases
|
||
|
*/
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
|
const char* input = "0.0000000000000000001e37";
|
||
|
bool exception = false;
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000000000000000001e38";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00000000000000001e37";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000000000000001e36";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000000000000001e35";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000000000000001e34";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00000000000001e32";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000000000001e31";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000000000001e30";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00000000001e29";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000000001e28";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000000001e27";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00000001e26";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000001e25";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000001e24";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00001e23";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0001e22";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.001e21";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.01e20";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.1e19";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
// Cross over
|
||
|
input = "1.0e18";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10.0e17";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100.0e16";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000.0e15";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000.0e14";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100000.0e13";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000000.0e12";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000000.0e11";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100000000.0e10";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000000000.0e9";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000000000.0e8";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100000000000.0e7";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000000000000.0e6";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000000000000.0e5";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100000000000000.0e4";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000000000000000.0e3";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000000000000000.0e2";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100000000000000000.0e1";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000000000000000000.0e0";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t009)
|
||
|
{
|
||
|
/* TEST CASE 9: zero factional, negative exponent, walking one positive test
|
||
|
* cases
|
||
|
*/
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
|
const char* input = "100000000000000000.0e-1";
|
||
|
PARSE_VALUE_CHECK("10000000000000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-2";
|
||
|
PARSE_VALUE_CHECK("1000000000000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-3";
|
||
|
PARSE_VALUE_CHECK("100000000000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-4";
|
||
|
PARSE_VALUE_CHECK("10000000000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-5";
|
||
|
PARSE_VALUE_CHECK("1000000000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-6";
|
||
|
PARSE_VALUE_CHECK("100000000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-7";
|
||
|
PARSE_VALUE_CHECK("10000000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-8";
|
||
|
PARSE_VALUE_CHECK("1000000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-9";
|
||
|
PARSE_VALUE_CHECK("100000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-10";
|
||
|
PARSE_VALUE_CHECK("10000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-11";
|
||
|
PARSE_VALUE_CHECK("1000000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-12";
|
||
|
PARSE_VALUE_CHECK("100000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-13";
|
||
|
PARSE_VALUE_CHECK("10000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-14";
|
||
|
PARSE_VALUE_CHECK("1000.0");
|
||
|
|
||
|
input = "100000000000000000.0e-15";
|
||
|
PARSE_VALUE_CHECK("100.0");
|
||
|
|
||
|
input = "100000000000000000.0e-16";
|
||
|
PARSE_VALUE_CHECK("10.0");
|
||
|
|
||
|
input = "100000000000000000.0e-17";
|
||
|
PARSE_VALUE_CHECK("1.0");
|
||
|
|
||
|
// Cross over
|
||
|
input = "100000000000000000.0e-18";
|
||
|
PARSE_VALUE_CHECK("0.1");
|
||
|
|
||
|
input = "100000000000000000.0e-19";
|
||
|
PARSE_VALUE_CHECK("0.01");
|
||
|
|
||
|
input = "100000000000000000.0e-20";
|
||
|
PARSE_VALUE_CHECK("0.001");
|
||
|
|
||
|
input = "100000000000000000.0e-21";
|
||
|
PARSE_VALUE_CHECK("0.0001");
|
||
|
|
||
|
input = "100000000000000000.0e-22";
|
||
|
PARSE_VALUE_CHECK("0.00001");
|
||
|
|
||
|
input = "100000000000000000.0e-23";
|
||
|
PARSE_VALUE_CHECK("0.000001");
|
||
|
|
||
|
input = "100000000000000000.0e-24";
|
||
|
PARSE_VALUE_CHECK("0.0000001");
|
||
|
|
||
|
input = "100000000000000000.0e-25";
|
||
|
PARSE_VALUE_CHECK("0.00000001");
|
||
|
|
||
|
input = "100000000000000000.0e-26";
|
||
|
PARSE_VALUE_CHECK("0.000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-27";
|
||
|
PARSE_VALUE_CHECK("0.0000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-28";
|
||
|
PARSE_VALUE_CHECK("0.00000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-29";
|
||
|
PARSE_VALUE_CHECK("0.000000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-30";
|
||
|
PARSE_VALUE_CHECK("0.0000000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-31";
|
||
|
PARSE_VALUE_CHECK("0.00000000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-32";
|
||
|
PARSE_VALUE_CHECK("0.000000000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-33";
|
||
|
PARSE_VALUE_CHECK("0.0000000000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-34";
|
||
|
PARSE_VALUE_CHECK("0.00000000000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-35";
|
||
|
PARSE_VALUE_CHECK("0.000000000000000001");
|
||
|
|
||
|
input = "100000000000000000.0e-36";
|
||
|
PARSE_VALUE_CHECK("0.0000000000000000001");
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t010)
|
||
|
{
|
||
|
/* TEST CASE 10: non-zero factional, negative exponent, walking value
|
||
|
* positive+negative test cases
|
||
|
*/
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
|
const char* input = "100000000000000000.1e-1";
|
||
|
PARSE_VALUE_CHECK("10000000000000000.01");
|
||
|
|
||
|
input = "100000000000000000.1e-2";
|
||
|
PARSE_VALUE_CHECK("1000000000000000.001");
|
||
|
|
||
|
input = "100000000000000000.1e-3";
|
||
|
PARSE_VALUE_CHECK("100000000000000.0001");
|
||
|
|
||
|
input = "100000000000000000.1e-4";
|
||
|
PARSE_VALUE_CHECK("10000000000000.00001");
|
||
|
|
||
|
input = "100000000000000000.1e-5";
|
||
|
PARSE_VALUE_CHECK("1000000000000.000001");
|
||
|
|
||
|
input = "100000000000000000.1e-6";
|
||
|
PARSE_VALUE_CHECK("100000000000.0000001");
|
||
|
|
||
|
input = "100000000000000000.1e-7";
|
||
|
PARSE_VALUE_CHECK("10000000000.00000001");
|
||
|
|
||
|
input = "100000000000000000.1e-8";
|
||
|
PARSE_VALUE_CHECK("1000000000.000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-9";
|
||
|
PARSE_VALUE_CHECK("100000000.0000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-10";
|
||
|
PARSE_VALUE_CHECK("10000000.00000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-11";
|
||
|
PARSE_VALUE_CHECK("1000000.000000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-12";
|
||
|
PARSE_VALUE_CHECK("100000.0000000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-13";
|
||
|
PARSE_VALUE_CHECK("10000.00000000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-14";
|
||
|
PARSE_VALUE_CHECK("1000.000000000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-15";
|
||
|
PARSE_VALUE_CHECK("100.0000000000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-16";
|
||
|
PARSE_VALUE_CHECK("10.00000000000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-17";
|
||
|
PARSE_VALUE_CHECK("1.000000000000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-18";
|
||
|
PARSE_VALUE_CHECK("0.1000000000000000001");
|
||
|
|
||
|
input = "100000000000000000.1e-19";
|
||
|
bool exception = false;
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t011)
|
||
|
{
|
||
|
/* TEST CASE 11: zero factional, negative exponent, walking one negative test
|
||
|
* cases
|
||
|
*/
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
|
const char* input = "100000000000000000.0e-37";
|
||
|
bool exception = false;
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000000000000000.0e-36";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000000000000000.0e-35";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100000000000000.0e-34";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000000000000.0e-33";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000000000000.0e-32";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100000000000.0e-31";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000000000.0e-30";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000000000.0e-29";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100000000.0e-28";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000000.0e-27";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000000.0e-26";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100000.0e-25";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10000.0e-24";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1000.0e-23";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "100.0e-22";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "10.0e-21";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "1.0e-20";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
// Cross over
|
||
|
input = "0.1e-19";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.01e-18";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.001e-17";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0001e-16";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00001e-15";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000001e-14";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000001e-13";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00000001e-12";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000000001e-11";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000000001e-10";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00000000001e-9";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000000000001e-8";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000000000001e-7";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00000000000001e-6";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000000000000001e-5";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000000000000001e-4";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.00000000000000001e-3";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.000000000000000001e-2";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
|
||
|
input = "0.0000000000000000001e-1";
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t012)
|
||
|
{
|
||
|
/* TEST CASE 12: non-zero negative integer, positive exponent, walking value
|
||
|
* positive+negative test cases
|
||
|
*/
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
|
const char* input = "-1.0000000000000000001e1";
|
||
|
PARSE_VALUE_CHECK("-10.000000000000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e2";
|
||
|
PARSE_VALUE_CHECK("-100.00000000000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e3";
|
||
|
PARSE_VALUE_CHECK("-1000.0000000000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e4";
|
||
|
PARSE_VALUE_CHECK("-10000.000000000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e5";
|
||
|
PARSE_VALUE_CHECK("-100000.00000000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e6";
|
||
|
PARSE_VALUE_CHECK("-1000000.0000000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e7";
|
||
|
PARSE_VALUE_CHECK("-10000000.000000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e8";
|
||
|
PARSE_VALUE_CHECK("-100000000.00000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e9";
|
||
|
PARSE_VALUE_CHECK("-1000000000.0000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e10";
|
||
|
PARSE_VALUE_CHECK("-10000000000.000000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e11";
|
||
|
PARSE_VALUE_CHECK("-100000000000.00000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e12";
|
||
|
PARSE_VALUE_CHECK("-1000000000000.0000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e13";
|
||
|
PARSE_VALUE_CHECK("-10000000000000.000001");
|
||
|
|
||
|
input = "-1.0000000000000000001e14";
|
||
|
PARSE_VALUE_CHECK("-100000000000000.00001");
|
||
|
|
||
|
input = "-1.0000000000000000001e15";
|
||
|
PARSE_VALUE_CHECK("-1000000000000000.0001");
|
||
|
|
||
|
input = "-1.0000000000000000001e16";
|
||
|
PARSE_VALUE_CHECK("-10000000000000000.001");
|
||
|
|
||
|
input = "-1.0000000000000000001e17";
|
||
|
PARSE_VALUE_CHECK("-100000000000000000.01");
|
||
|
|
||
|
input = "-1.0000000000000000001e18";
|
||
|
bool exception = false;
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t013)
|
||
|
{
|
||
|
/* TEST CASE 13: non-zero negative factional, negative exponent, walking
|
||
|
* value positive+negative test cases
|
||
|
*/
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
|
const char* input = "-100000000000000000.1e-1";
|
||
|
PARSE_VALUE_CHECK("-10000000000000000.01");
|
||
|
|
||
|
input = "-100000000000000000.1e-2";
|
||
|
PARSE_VALUE_CHECK("-1000000000000000.001");
|
||
|
|
||
|
input = "-100000000000000000.1e-3";
|
||
|
PARSE_VALUE_CHECK("-100000000000000.0001");
|
||
|
|
||
|
input = "-100000000000000000.1e-4";
|
||
|
PARSE_VALUE_CHECK("-10000000000000.00001");
|
||
|
|
||
|
input = "-100000000000000000.1e-5";
|
||
|
PARSE_VALUE_CHECK("-1000000000000.000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-6";
|
||
|
PARSE_VALUE_CHECK("-100000000000.0000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-7";
|
||
|
PARSE_VALUE_CHECK("-10000000000.00000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-8";
|
||
|
PARSE_VALUE_CHECK("-1000000000.000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-9";
|
||
|
PARSE_VALUE_CHECK("-100000000.0000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-10";
|
||
|
PARSE_VALUE_CHECK("-10000000.00000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-11";
|
||
|
PARSE_VALUE_CHECK("-1000000.000000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-12";
|
||
|
PARSE_VALUE_CHECK("-100000.0000000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-13";
|
||
|
PARSE_VALUE_CHECK("-10000.00000000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-14";
|
||
|
PARSE_VALUE_CHECK("-1000.000000000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-15";
|
||
|
PARSE_VALUE_CHECK("-100.0000000000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-16";
|
||
|
PARSE_VALUE_CHECK("-10.00000000000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-17";
|
||
|
PARSE_VALUE_CHECK("-1.000000000000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-18";
|
||
|
PARSE_VALUE_CHECK("-0.1000000000000000001");
|
||
|
|
||
|
input = "-100000000000000000.1e-19";
|
||
|
bool exception = false;
|
||
|
PARSE_EXCEPTION_CHECK
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t014)
|
||
|
{
|
||
|
/* TEST CASE 14: LEADING_ZERO=true; negative zero parse
|
||
|
*/
|
||
|
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
|
const char* input = "-0.9";
|
||
|
PARSE_VALUE_CHECK("-0.9");
|
||
|
|
||
|
input = "-0.99";
|
||
|
PARSE_VALUE_CHECK("-0.99");
|
||
|
|
||
|
input = "-0.999";
|
||
|
PARSE_VALUE_CHECK("-0.999");
|
||
|
|
||
|
input = "-0.9999";
|
||
|
PARSE_VALUE_CHECK("-0.9999");
|
||
|
|
||
|
input = "-0.99999";
|
||
|
PARSE_VALUE_CHECK("-0.99999");
|
||
|
|
||
|
input = "-0.999999";
|
||
|
PARSE_VALUE_CHECK("-0.999999");
|
||
|
|
||
|
input = "-0.9999999";
|
||
|
PARSE_VALUE_CHECK("-0.9999999");
|
||
|
|
||
|
input = "-0.99999999";
|
||
|
PARSE_VALUE_CHECK("-0.99999999");
|
||
|
|
||
|
input = "-0.999999999";
|
||
|
PARSE_VALUE_CHECK("-0.999999999");
|
||
|
|
||
|
input = "-0.9999999999";
|
||
|
PARSE_VALUE_CHECK("-0.9999999999");
|
||
|
|
||
|
input = "-0.99999999999";
|
||
|
PARSE_VALUE_CHECK("-0.99999999999");
|
||
|
|
||
|
input = "-0.999999999999";
|
||
|
PARSE_VALUE_CHECK("-0.999999999999");
|
||
|
|
||
|
input = "-0.9999999999999";
|
||
|
PARSE_VALUE_CHECK("-0.9999999999999");
|
||
|
|
||
|
input = "-0.99999999999999";
|
||
|
PARSE_VALUE_CHECK("-0.99999999999999");
|
||
|
|
||
|
input = "-0.999999999999999";
|
||
|
PARSE_VALUE_CHECK("-0.999999999999999");
|
||
|
|
||
|
input = "-0.9999999999999999";
|
||
|
PARSE_VALUE_CHECK("-0.9999999999999999");
|
||
|
|
||
|
input = "-0.99999999999999999";
|
||
|
PARSE_VALUE_CHECK("-0.99999999999999999");
|
||
|
|
||
|
input = "-0.999999999999999999";
|
||
|
PARSE_VALUE_CHECK("-0.999999999999999999");
|
||
|
|
||
|
input = "-0.9999999999999999999";
|
||
|
PARSE_VALUE_CHECK("-0.9999999999999999999");
|
||
|
}
|
||
|
|
||
|
BOOST_AUTO_TEST_CASE(t015)
|
||
|
{
|
||
|
/* TEST CASE 15: LEADING_ZERO=false; negative zero parse
|
||
|
*/
|
||
|
|
||
|
fixed_64_64 value;
|
||
|
std::ostringstream output;
|
||
|
|
||
Adding fixed point type changes from a few weeks ago. This includes
significantly expanded tests.