// Following trick can reduce the range check by one
if ((uint) index >= (uint)_size) {
  ThrowHelper.ThrowArgumentOutOfRangeException();
}
显然这比(?)更有效 if (index < 0 || index >= _size)
我很好奇这个技巧背后的理由.单个分支指令真的比两个转换要贵uint吗?或者是否还有一些其他优化会使这个代码比另外的数字比较更快?
为了解决房间里的大象:是的,这是微优化,不,我不打算在我的代码中到处使用它 - 我只是好奇;)
c# performance micro-optimization numeric-conversion range-checking
为了说清楚,我不打算在这里使用任何类型的便携性,所以任何将我绑定到某个盒子的解决方案都可以.
基本上,我有一个if语句将99%的时间评估为true,并且我试图剔除每个性能的最后一个时钟,我可以发出某种编译器命令(使用GCC 4.1.2和x86 ISA,如果告诉分支预测器它应该缓存该分支吗?
通过编码是否有任何(非微优化)性能增益
float f1 = 200f / 2
在比较中
float f2 = 200f * 0.5
几年前我的一位教授告诉我,浮点除法比浮点乘法慢,但没有详细说明原因.
这句话适用于现代PC架构吗?
UPDATE1
关于评论,请同时考虑这个案例:
float f1;
float f2 = 2
float f3 = 3;
for( i =0 ; i < 1e8; i++)
{
  f1 = (i * f2 + i / f3) * 0.5; //or divide by 2.0f, respectively
}
更新2 从评论中引用:
[我想]知道什么是算法/架构要求导致>除法在硬件上比复制要复杂得多
在我正在研究的其中一个项目中,我看到了这段代码
struct Base {
  virtual ~Base() { }
};
struct ClassX {
  bool isHoldingDerivedObj() const {
    return typeid(1 ? *m_basePtr : *m_basePtr) == typeid(Derived);
  }
  Base *m_basePtr;
};
我从来没有见过这样的typeid用法.为什么它会做那种奇怪的舞蹈?:,而不仅仅是做typeid(*m_basePtr)?有什么理由吗?Base是一个多态类(带有虚拟析构函数).
编辑:在这个代码的另一个地方,我看到这个,它似乎是等价的"多余的"
template<typename T> T &nonnull(T &t) { return t; }
struct ClassY {
  bool isHoldingDerivedObj() const {
    return typeid(nonnull(*m_basePtr)) == typeid(Derived);
  }
  Base *m_basePtr;
};
在某些情况下,您知道某个浮点表达式将始终为非负数。例如,计算一个矢量的长度时,一个做sqrt(a[0]*a[0] + ... + a[N-1]*a[N-1])(NB:我是知道的std::hypot,这是不相关的问题),并且平方根下表达显然是非负的。但是,GCC 为以下输出以下程序集sqrt(x*x):
        mulss   xmm0, xmm0
        pxor    xmm1, xmm1
        ucomiss xmm1, xmm0
        ja      .L10
        sqrtss  xmm0, xmm0
        ret
.L10:
        jmp     sqrtf
也就是说,它将结果x*x与零进行比较,如果结果为非负数,则执行sqrtss指令,否则调用sqrtf。
因此,我的问题是:如何强制GCC假定该x*x值始终为非负值,从而跳过比较和sqrtf调用,而无需编写内联汇编?
我想强调的是,我对本地解决方案感兴趣,而不是像-ffast-math,-fno-math-errno或那样做-ffinite-math-only(尽管确实可以解决问题,这要归功于ks1322,harold和Eric Postpischil的评论)。
此外,“强制将GCC假定x*x为非负数”应解释为assert(x*x >= 0.f),因此这也排除了x*xNaN 的情况。
我可以使用特定于编译器,特定于平台,特定于CPU等的解决方案。
我偶然发现了这篇Reddit 帖子,它是对以下代码片段的一个玩笑,
void f(int& x) {
    if (x != 1) {
        x = 1;
    }
}
void g(int& x) {
    x = 1;
}
说这两个函数不等同于“编译器”。我确信任何主要的 C++ 编译器都会将条件赋值优化为无条件存储,从而为f和发出相同的汇编代码g。
谁能向我解释为什么会这样?
我的想法是:无条件存储很可能会更快,因为无论如何我们都必须访问内存来读取比较值,并且分支代码会给分支预测器带来压力。此外,编译器不应将存储视为副作用(AFAIK),即使后续内存访问可能会更快或更慢,具体取决于是否f由于缓存局部性而采用分支。
那么编译器就无法弄清楚这一点吗?虽然证明f和 的等价性g可能并不容易,但我觉得这些编译器能够解决更困难的问题。那么我可能错了,这些功能毕竟不相等,或者这里发生了什么?
在x86上有两种众所周知的方法可以将整数寄存器设置为零值.
或
mov reg, 0
要么
xor reg, reg
有一种观点认为第二种变体更好,因为值0没有存储在代码中并且节省了几个字节的生成的机器代码.这绝对是好的 - 使用较少的指令缓存,这有时可以实现更快的代码执行.许多编译器生成这样的代码.
然而,在xor指令和改变相同寄存器的早期指令之间正式存在指令间依赖性.由于存在依赖性,后一条指令需要等到前者完成,这可能会减少处理器单元的负载并损害性能.
add reg, 17
;do something else with reg here
xor reg, reg
很明显,无论初始寄存器值如何,xor的结果都将完全相同.但是处理器能够识别出这个吗?
我在VC++ 7中尝试了以下测试:
const int Count = 10 * 1000 * 1000 * 1000;
int _tmain(int argc, _TCHAR* argv[])
{
    int i;
    DWORD start = GetTickCount();
    for( i = 0; i < Count ; i++ ) {
        __asm {
            mov eax, 10
            xor eax, eax
        };
    }
    DWORD diff = GetTickCount() - start;
    start = …作为我编写的程序的一部分,我需要比较形式为a + sqrt(b)where a和bunsigned integer的两个值。由于这是紧密循环的一部分,因此我希望此比较尽可能快地运行。(如果重要的话,我正在x86-64机器上运行代码,并且无符号整数不大于10 ^ 6。此外,我知道这样的事实a1<a2。)
作为独立功能,这就是我要优化的功能。我的数字是足够小的整数,可以double(或什至float)精确地表示它们,但是sqrt结果中的舍入误差不能改变结果。
// known pre-condition: a1 < a2  in case that helps
bool is_smaller(unsigned a1, unsigned b1, unsigned a2, unsigned b2) {
    return a1+sqrt(b1) < a2+sqrt(b2);  // computed mathematically exactly
}
测试用例:is_smaller(900000, 1000000, 900001, 998002)应返回true,但如@wim注释所示,sqrtf()将其返回false。因此将(int)sqrt()截断为整数。
a1+sqrt(b1) = 90100和a2+sqrt(b2) = 901000.00050050037512481206。最接近的浮点数就是90100。
由于sqrt()即使在现代的x86-64上作为sqrtsd指令完全内联时,该函数通常也非常昂贵,所以我试图避免sqrt()尽可能地调用。
通过平方运算删除sqrt还可以通过使所有计算都精确来避免舍入错误的任何危险。
如果相反,功能是这样的...
bool is_smaller(unsigned …我浏览了最近发布的Doom 3 BFG源代码,当时我遇到了一些似乎没有任何意义的东西.Doom 3在idMath类中包含数学函数.一些函数只是向相应的函数提供math.h,但有些是重新实现(例如idMath :: exp16()),我认为它具有比它们的math.h对应物更高的性能(可能以牺牲精度为代价).
然而,令我感到困惑的是他们实现这一float idMath::Sqrt(float x)功能的方式:
ID_INLINE float idMath::InvSqrt( float x ) {
     return ( x > FLT_SMALLEST_NON_DENORMAL ) ? sqrtf( 1.0f / x ) : INFINITY;
}
ID_INLINE float idMath::Sqrt( float x ) {
     return ( x >= 0.0f ) ? x * InvSqrt( x ) : 0.0f;
}
这似乎执行两个不必要的浮点运算:首先是除法然后是乘法.
值得注意的是,原始的Doom 3源代码也以这种方式实现了平方根函数,但是反平方根使用了快速平方根算法.
ID_INLINE float idMath::InvSqrt( float x ) {
    dword …