试图减少几乎是整数但不是整数的类的速度开销 我实现了一个C++类,它的行为与标准 int >代码>非常类似。不同之处在于它有一个额外的“ε”概念,它表示一些非常小的值,远小于1,但大于0。一种方法是将其视为一个非常宽的不动点数,其中包含32个MSB(整数部分)、32个LSB(ε部分)和大量的零。(注:此类数字与普通固定点数字之间的一大区别是有两个符号,而不是一个:“值”和“ε”可以相互独立地为负,而对于固定点数字,整个数字有一个符号。)
以下课程有效,但在整个课程中引入了~2倍的速度惩罚。(该程序包含与该类无关的代码,因此该类的实际速度损失可能远大于2x。)我无法粘贴使用该类的代码,但我可以说:试图减少几乎是整数但不是整数的类的速度开销 我实现了一个C++类,它的行为与标准 int >代码>非常类似。不同之处在于它有一个额外的“ε”概念,它表示一些非常小的值,远小于1,但大于0。一种方法是将其视为一个非常宽的不动点数,其中包含32个MSB(整数部分)、32个LSB(ε部分)和大量的零。(注:此类数字与普通固定点数字之间的一大区别是有两个符号,而不是一个:“值”和“ε”可以相互独立地为负,而对于固定点数字,整个数字有一个符号。),c++,optimization,numbers,operator-overloading,C++,Optimization,Numbers,Operator Overloading,以下课程有效,但在整个课程中引入了~2倍的速度惩罚。(该程序包含与该类无关的代码,因此该类的实际速度损失可能远大于2x。)我无法粘贴使用该类的代码,但我可以说: +、-、+=、和=是唯一大量使用的运算符。使用setEpsilon()和getInt()是极其罕见的 *也很少见,甚至根本不需要考虑ε值。 下面是课堂: #include <limits> struct int32Uepsilon { typedef int32Uepsilon Self; int32Uepsilon (
+、-、+=、
和=
是唯一大量使用的运算符。使用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; }
}
};
#包括
结构int32Uepsilon{
typedef int32Uepsilon Self;
int32Uepsilon(){u值=0;
_eps=0;}
int32Uepsilon(const int&i){u值=i;
_eps=0;}
void setEpsilon(){u eps=1;}
Self运算符+(const Self&rhs)const{Self result=*this;
结果。_值+=rhs。_值;
结果。_eps+=rhs。_eps;
返回结果;}
自运算符-(const Self&rhs)const{Self result=*this;
结果。_值-=rhs。_值;
结果。_eps-=rhs。_eps;
返回结果;}
自运算符-()const{Self result=*this;
结果。_值=-结果。_值;
结果。_eps=-结果。_eps;
返回结果;}
Self操作符*(const Self&rhs)const{返回this->getInt()*rhs.getInt();}//XXX:discards epsilon
布尔运算符(const Self&rhs)const{return(_值>rhs._值)||
(_值==rhs._值&&u eps>rhs._eps);}
布尔运算符>=(常量Self&rhs)常量{return(_值>=rhs._值)||
(_值==rhs._值&&u eps>=rhs._eps);)
Self&operator+=(const Self&rhs){this->_值+=rhs._值;
此->_eps+=rhs._eps;
返回*this;}
Self&operator-=(const Self&rhs){this->_值-=rhs._值;
此->_eps-=右侧。_eps;
返回*this;}
int getInt()常量{return(_value);}
私人:
int_值;
int_eps;
};
名称空间标准{
模板
结构数值极限{
静态常数布尔值为_signed=true;
静态int max(){return 2147483647;}
}
};
上面的代码可以工作,但速度相当慢。有人对如何提高绩效有什么想法吗?我可以给出一些可能有用的提示/细节:
- 32位绝对不足以同时保存_值和_eps。在实践中,高达24~28位的 _使用值,最多使用20位的_eps
- 我无法衡量使用
和int32\u t
之间的显著性能差异, 因此,内存开销本身可能不是问题所在int64\u t
- 在eps上饱和加法/减法会很酷,但实际上并不必要
- 注意_value和_eps的符号不一定相同!这打破了我的第一次尝试 加快这个班的速度
- 内联汇编是没有问题的,只要它在运行Linux的核心i7系统上与GCC一起工作李>
[32位值][12零][20位eps]
。比较将通过一次操作自动进行,加法和减法需要将eps的结转掩盖为填充零。使用MMX进行加法和减法(然后自动屏蔽)以及使用普通整数比较进行比较没有任何障碍
顺便说一句,您的操作员-=似乎有问题:在
this->\u eps-=rhs.\u eps
中,this->eps
可能会变为负数。难道你不应该同时调整每股收益并降低其值吗?eps的溢出行为是什么?它是否会转化为价值?一件值得尝试的事情是,根据操作符+=
定义例如操作符+
:
Self operator+(const Self &rhs) const { return Self(*this) += rhs; }
这有助于实现,从而消除了按值返回所需的复制构造函数
而且,它减少了代码维护 我的(部分)解决方案使用的是one整数运算,而不是Oli Charlesworth在评论中指出的解决方案中的two
您可以这样做:使用int64\u t
存储\u eps
和\u值
。在我下面的示例中,\u值
由位0到位31
表示,\u eps
由位32到位63
表示
struct int32Uepsilon
{
typedef int32Uepsilon Self;
int64_t value;
int32Uepsilon () { value = 0 }
int32Uepsilon (const int i) { value = i; }
void setEpsilon()
{
//equivent to _eps = 1
value = ((int64_t)1 << 32) + (value & 0xFFFFFFFF);
}
Self operator+(const Self &rhs) const
{
Self result = *this;
//this adds lower 32 bits to lower 32 bits, upper 32 bits to upper 32 bits!
result.value += rhs.value;
return result;
}
//....
int getValue() { return value & 0xFFFFFFFF; }
int getEpsilon() { return value >> 32; }
};
输出:
2, 4
65, 7897
67, 7901
正如所料
Ideone演示:
您可以不使用
x+y
,而使用
2, 4
65, 7897
67, 7901