Я реализовал класс C ++, который ведет себя очень похоже на стандартный тип int
.Разница заключается в том, что он имеет дополнительную концепцию «эпсилон», которая представляет собой какое-то крошечное значение, которое намного меньше 1, но больше 0. Один способ думать об этом - это очень широкое число с фиксированной точкой с 32 старшими битами (целое числочастей), 32 LSB (части эпсилона) и огромное море нулей между ними.(Примечание: большая разница между этим классом и обычными числами с фиксированной точкой состоит в том, что есть два знака, а не один: «значение» и «эпсилон» могут быть отрицательными независимо друг от друга, тогда как для фиксированной точки, есть один знак дляцелое число.)
Следующий класс работает, но вводит ~ 2-кратное снижение скорости в общей программе.(Программа включает в себя код, который не имеет ничего общего с этим классом, поэтому фактическое снижение скорости этого класса, вероятно, намного больше, чем в 2 раза.) Я не могу вставить код, который использует этот класс, но я могу сказать следующее:
+, -, +=, <, >
и >=
являются единственными активно используемыми операторами.Использование setEpsilon()
и getInt()
крайне редко.*
также встречается редко и даже не требует учета значений эпсилона.
Вот класс:
#include <limits>
struct int32Uepsilon {
typedef int32Uepsilon Self;
int32Uepsilon () { _value = 0;
_eps = 0; }
int32Uepsilon (const int &i) { _value = i;
_eps = 0; }
void setEpsilon() { _eps = 1; }
Self operator+(const Self &rhs) const { Self result = *this;
result._value += rhs._value;
result._eps += rhs._eps;
return result; }
Self operator-(const Self &rhs) const { Self result = *this;
result._value -= rhs._value;
result._eps -= rhs._eps;
return result; }
Self operator-( ) const { Self result = *this;
result._value = -result._value;
result._eps = -result._eps;
return result; }
Self operator*(const Self &rhs) const { return this->getInt() * rhs.getInt(); } // XXX: discards epsilon
bool operator<(const Self &rhs) const { return (_value < rhs._value) ||
(_value == rhs._value && _eps < rhs._eps); }
bool operator>(const Self &rhs) const { return (_value > rhs._value) ||
(_value == rhs._value && _eps > rhs._eps); }
bool operator>=(const Self &rhs) const { return (_value >= rhs._value) ||
(_value == rhs._value && _eps >= rhs._eps); }
Self &operator+=(const Self &rhs) { this->_value += rhs._value;
this->_eps += rhs._eps;
return *this; }
Self &operator-=(const Self &rhs) { this->_value -= rhs._value;
this->_eps -= rhs._eps;
return *this; }
int getInt() const { return(_value); }
private:
int _value;
int _eps;
};
namespace std {
template<>
struct numeric_limits<int32Uepsilon> {
static const bool is_signed = true;
static int max() { return 2147483647; }
}
};
Приведенный выше код работает, но он довольно медленный,У кого-нибудь есть идеи как улучшить производительность?Я могу дать несколько советов / подробностей, которые могут быть полезны:
- 32 бита определенно недостаточно для хранения как _value, так и _eps.На практике используется до 24 ~ 28 битов _value и используется до 20 битов _eps.
- Я не мог измерить существенную разницу в производительности между использованием
int32_t
и int64_t
, поэтому нехватка памятиСамо по себе, вероятно, здесь не проблема. - Насыщающее сложение / вычитание на _eps было бы здорово, но на самом деле это не нужно.
- Обратите внимание, что знаки _value и _eps не обязательно совпадают!Это сломало мою первую попытку ускорить этот класс.
- Встроенная сборка не проблема, если она работает с GCC в системе Core i7 под управлением Linux!