小编Ber*_*ard的帖子

尽快比较形式(a + sqrt(b))的两个值?

作为我编写的程序的一部分,我需要比较形式为a + sqrt(b)where abunsigned 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
}
Run Code Online (Sandbox Code Playgroud)

测试用例is_smaller(900000, 1000000, 900001, 998002)应返回true,但如@wim注释所示,sqrtf()将其返回false。因此将(int)sqrt()截断为整数。

a1+sqrt(b1) = 90100a2+sqrt(b2) = 901000.00050050037512481206。最接近的浮点数就是90100。


由于sqrt()即使在现代的x86-64上作为sqrtsd指令完全内联时,该函数通常也非常昂贵,所以我试图避免sqrt()尽可能地调用。

通过平方运算删除sqrt还可以通过使所有计算都精确来避免舍入错误的任何危险。

如果相反,功能是这样的...

bool is_smaller(unsigned …
Run Code Online (Sandbox Code Playgroud)

c++ optimization algebra micro-optimization sqrt

45
推荐指数
1
解决办法
1737
查看次数

在 x86 汇编中取两个有符号整数的平均值的最快方法?

假设我们有两个寄存器长度为 2有符号1 的整数,例如ab。我们想要计算值(a + b) / 2,向上舍入、向下舍入、向零舍入或远离零舍入,无论哪种方式更容易(即我们不关心舍入方向)。

\n

结果是另一个寄存器长度有符号整数(很明显,平均值必须在寄存器长度有符号整数的范围内)。

\n

执行此计算最快的方法是什么?

\n

您可以选择两个整数最初位于哪个寄存器中,以及平均值最终位于哪个寄存器中。

\n
\n

脚注1:对于无符号整数,我们可以用两条指令来完成。尽管循环进位在 Intel CPU 上超过 1 uop,但这可能是最快的方法。但当计数仅为 1 时,只有一对。 关于无符号均值的问答中的答案讨论了效率。

\n
add rdi, rsi\nrcr rdi, 1\n
Run Code Online (Sandbox Code Playgroud)\n

rdi这两个数字以和开始rsi,平均值以 结束rdi。但对于有符号数,-1 + 3将设置 CF,并将 a 旋转1到符号位。没有给出正确答案+1

\n

脚注 2:我指定了寄存器长度的有符号整数,这样我们就不能简单地用movsxdorcdqe指令对整数进行符号扩展。

\n
\n

我得到的最接近的解决方案使用四个指令,其中一个rcr在 Intel 上为 3 uops,在 AMD …

optimization x86 assembly average micro-optimization

29
推荐指数
2
解决办法
3016
查看次数

删除了所有自动生成的构造函数/运算符的类仍然可以从函数返回?

最近,我遇到了这个答案,它描述了如何初始化一个std::array非默认可构造元素.我并不感到惊讶,因为这个答案显然没有做任何默认构建.

相反,它std::array使用聚合初始化构建临时,然后移动(如果移动构造函数可用)或在函数返回时复制到命名变量.所以我们只需要移动构造函数或复制构造函数即可.

或者我认为......

然后是这段代码让我感到困惑:

struct foo {
    int x;
    foo(int x) : x(x) {}
    foo() = delete;
    foo(const foo&) = delete;
    foo& operator=(const foo&) = delete;
    foo(foo&&) = delete;
    foo& operator=(foo&&) = delete;
};

foo make_foo(int x) {
    return foo(x);
}

int main() {
    foo f = make_foo(1);
    foo g(make_foo(2));
}
Run Code Online (Sandbox Code Playgroud)

所有五个特殊成员构造函数/运算符都被显式删除,所以现在我不能从返回值构造我的对象,对吗?

错误.

令我惊讶的是,这在gcc中编译(使用C++ 17)!

为什么编译?显然foo要从函数返回一个make_foo(),我们必须构造一个foo.这意味着在main()我们foo从返回的函数中分配或构造一个函数foo.怎么可能?!

c++ return-value deleted-functions c++17

19
推荐指数
1
解决办法
1028
查看次数

C++整数类型是给定类型宽度的两倍

在此示例中,coord_squared_t是整数类型的别名,其大小至少是整数类型的两倍coord_t:

typedef int_least32_t coord_t;

coord_squared_t CalculateSquaredHypothenuse(coord_t x, coord_t y){
    coord_squared_t _x=x;
    coord_squared_t _y=y;
    return _x*_x+_y*_y;
}
Run Code Online (Sandbox Code Playgroud)

什么可以用来表现coord_squared_t在以下方面coord_t?标准库中是否有任何东西可以让我做一些像double_width<coord_t>::type获得正确宽度的东西,而不是明确选择类型?

C++ 11或C++ 14很好.

c++ std c++11

15
推荐指数
2
解决办法
1520
查看次数

为什么不赞成使用boost :: optional :: is_initialized()?

我今天注意到boost::optional::is_initialized()Boost 1.64.0参考中被标记为已弃用.我的项目大量洒满,is_initialized()以检查是否boost::optional包含值.

我没有看到任何其他方法来正确测试是否boost::optional初始化,我错过了什么?

boost::optional有一个explicit operator bool(),这意味着我可以做的if(foo){...},如果foo是一个boost::optional.然而,这是否会给出错误的结果foo是一个boost::optional<bool>或一些其他boost::optional<T>地方T可转换为bool.

Boost期望用户做什么?

c++ boost optional

14
推荐指数
1
解决办法
7330
查看次数

必须在C++中用lambda捕获constexpr表达式吗?

这是一段无法在MSVC 2015中编译的代码(忽略未初始化的值访问):

#include <array>
int main() {
    constexpr int x = 5;
    auto func = []() {
        std::array<int, x> arr;
        return arr[0];
    };
    func();
}
Run Code Online (Sandbox Code Playgroud)

它抱怨说:

'x' cannot be implicitly captured because no default capture mode has been specified
Run Code Online (Sandbox Code Playgroud)

但是x是一个constexpr! x在编译时是已知的5.为什么MSVC会对此大做文章?(是不是另一个MSVC的错误?)GCC将愉快地编译它.

c++ lambda visual-c++ constexpr c++14

11
推荐指数
1
解决办法
605
查看次数

仍在评估废弃分支中的嵌套constexpr-if语句?

在我看来,在MSVC(版本15.7.3)中评估另一个constexpr-if语句的废弃分支内的constexpr-if语句.

请考虑以下代码:

#include <tuple>
#include <type_traits>

template <size_t I>
int test() {
    if constexpr(I != 0) {
        return 0;
    }
    else { // This branch is discarded, but it seems that the constexpr-if below is still evaulated?
        if constexpr(std::is_same_v<int, std::tuple_element_t<I, std::tuple<int>>>) { // some constexpr check that is valid only when I == 0
            return 1;
        }
        else {
            return 2;
        }
    }
}

int main() {
    test<1>();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码无法在MSVC中编译,因为std::tuple_element_tI超过元组的边界时,静态断言将失败.这表明,不管怎样,废弃分支中的代码也会被评估,即使它依赖于模板参数I.

根据cppreference …

c++ nested c++17 if-constexpr

11
推荐指数
1
解决办法
521
查看次数

shift_right() 如何在 C++20 中实现?

在 C++20 中,<algorithm>头文件获得了两种新算法:shift_left()shift_right(). 它们都接受任何 LegacyForwardIterator。对于shift_left(),指定“以i?0”开始的递增顺序执行移动;对于shift_right(),指定“如果ForwardIt满足 LegacyBidirectionalIterator 要求,则按照从i开始的递减顺序执行移动last - first - n - 1”。

我可以想到一个相当简单的实现方法shift_left()

template <typename ForwardIt>
constexpr inline ForwardIt shift_left(ForwardIt first, ForwardIt last, typename std::iterator_traits<ForwardIt>::difference_type n) {
    if (n <= 0) return last;
    ForwardIt it = first;
    for (; n > 0; --n, ++it) {
        if (it == last) return first;
    }
    return std::move(it, last, first);
} …
Run Code Online (Sandbox Code Playgroud)

c++ algorithm c++-standard-library c++20

11
推荐指数
1
解决办法
597
查看次数

有负股息的分部,但向负无穷大四舍五入?

请考虑以下代码(在C++ 11中):

int a = -11, b = 3;
int c = a / b;
// now c == -3
Run Code Online (Sandbox Code Playgroud)

C++ 11规范称负股息的除法向零舍入.

对于有一个运算符或函数来进行除向负无穷大的舍入非常有用(例如,为了在迭代范围时与正红利保持一致),那么标准库中是否有一个函数或运算符可以满足我的需要?或者也许是在现代编译器中执行它的编译器定义的函数/内在函数?

我可以编写自己的,例如以下(仅适用于正数除数):

int div_neg(int dividend, int divisor){
    if(dividend >= 0) return dividend / divisor;
    else return (dividend - divisor + 1) / divisor;
}
Run Code Online (Sandbox Code Playgroud)

但它不会像我的意图那样描述,也可能不是标准库函数或编译器内在优化(如果存在).

c++ division c++11

9
推荐指数
1
解决办法
808
查看次数

对于其他类型,是否存在void_t的标准泛化?

在C++ 17中,我们有std::void_t,这使得SFINAE看起来更好:

template <typename T>
std::void_t<decltype(T::prop)> foo() { /* stuff */ }
Run Code Online (Sandbox Code Playgroud)

模板函数仅在T::prop存在时才存在.

如果T::prop存在,模板函数foo()将等效于:

template <typename T>
void foo() { /* stuff */ }
Run Code Online (Sandbox Code Playgroud)

否则,代码相当于根本没有声明foo().

是否std::void_t对标准库中的其他类型进行了泛化,例如:

template<typename T, typename...>
using generic_t = T;
Run Code Online (Sandbox Code Playgroud)

以便下面的代码有效?

template <typename T>
std::generic_t<int, decltype(T::prop)> foo() { /* stuff */ }
Run Code Online (Sandbox Code Playgroud)

这相当于

template <typename T>
int foo() { /* stuff */ }
Run Code Online (Sandbox Code Playgroud)

如果T::prop存在?

c++ sfinae c++17

9
推荐指数
1
解决办法
393
查看次数