【问题标题】:3 ways to toggle a bit represented as a char3 种方法来切换表示为 char 的位
【发布时间】:2016-11-26 13:20:38
【问题描述】:

这是我写的:

#include <iostream>
#include <vector>

int main()
{
    std::vector<char> v = {0, 0, 0};
    v[0] = v[0] == 0 ? 1 : 0;
    v[1] = !v[1];
    v[2] ^= 1;
    std::cout << (int)v[0] << (int)v[1] << (int)v[2] << "\n";
    return 0;
}

切换所有位,但我实际上只关心更改第 i 位。

我感兴趣的是在 项目中应该使用哪一种方式,而您唯一关心的是速度(而不是内存和可读性)?


使用std::vector&lt;char&gt;作为bitset的原因是in my timings I found that it's faster than a vector of ints or chars, and std::bitset。

【问题讨论】:

  • 您所说的“我应该使用哪一个”是什么意思——显然这四个操作中只有 一个 会产生正确的结果?!
  • Kerrek 更新了! @Raindrop7 没经验,能解释一下吗?
  • xor 和前两个具有不同的语义(对于不同于 0 或 1 的初始值)。
  • 你的意思是:v[2] ^= 1; 而不是v[3]
  • @Raindrop7 好吧,他将它们用作位集。至于实际的 std::bitset,有时在无法静态证明索引在范围内时会产生开销,但通常没问题。虽然它不是很灵活,所以你经常会在它上面调用to_ulong,做一些操作,然后转换回来..

标签: c++ c++ algorithm vector bit-manipulation toggle


【解决方案1】:

您可以改用std::bitset,只要您对位感兴趣或直接使用布尔向量而不是字符:

#include <iostream>
#include <vector>

int main()
{
    std::vector<bool> v = { 0, 0, 0 };

    for (int i(0); i < v.size(); i++)
        v[i] = !v[i];

    for (int i(0); i < v.size(); i++)
        std::cout << (int)v[i];

    std::cout << std::endl;

    std::cin.get();
    return 0;
} 
  • 推荐使用bitwise not !,因为它速度快且干净。

【讨论】:

  • std::vector&lt;bool&gt; 据说很慢,my timings over vectors of ints, chars and bools, as well as std::bitset 同意。 std::bitset 似乎是一个选择,当内存很重要时,时间驱使我使用std::vector&lt;char&gt;,因为我关心速度。那么对于chars的向量,你还觉得!更快吗?暂时忘记可读性。
  • 我发了一个answer 有一些时间,请看一下,你可能会发现任何错误,如果有一个! :) 感谢您的宝贵时间!
  • @gsamaras:对不起,我的意思是 logical not 不是按位否定运算符 ~
【解决方案2】:

根据 Raindrop7 的回答,我决定基于 How-to-store-binary-data-when-you-only-care-about-speed? 并使用以下代码进行时间测量:

#include <ctime>
#include <ratio>
#include <chrono>
#include <iostream>
#include <vector>
#include <random>

#define T int

std::uniform_int_distribution<int> uni_bit_distribution(0, 1);
std::default_random_engine generator(std::chrono::system_clock::now().time_since_epoch().count());

// g++ -Wall -std=c++0x -O3 toggle_all_bits_one_by_one.cpp
int main()
{
    const int N = 1000000;
    const int D = 100;

    using namespace std::chrono;
    high_resolution_clock::time_point t1 = high_resolution_clock::now();


    std::vector<T> v;
    v.resize(N * D);
    for(int i = 0; i < N; ++i)
        for(int j = 0; j < D; ++j)
            v[j + i * D] = uni_bit_distribution(generator);


    high_resolution_clock::time_point t2 = high_resolution_clock::now();

    duration<double> time_span = duration_cast<duration<double> >(t2 - t1);

    std::cout << "Build " << time_span.count() << " seconds.\n";

    t1 = high_resolution_clock::now();

    for(int i = 0; i < N; ++i)
        for(int j = 0; j < D; ++j)
            //v[j + i * D] = v[j + i * D] == 0 ? 1 : 0;
            // Build 3.95191 seconds. Time to toggle all bits one by one 0.0490182 seconds.
            //v[j + i * D] = !v[j + i * D];
            // Build 3.82705 seconds. Time to toggle all bits one by one 0.0477722 seconds.
            v[j + i * D] ^= 1;
            // Build 3.74881 seconds. Time to toggle all bits one by one 0.046955 seconds.

    t2 = high_resolution_clock::now();
    time_span = duration_cast<duration<double> >(t2 - t1);
    std::cout << "Time to toggle all bits one by one " << time_span.count() << " seconds.\n";

    return 0;
}

这在我的机器上证明了方法选择所产生的影响很小,正如预期的那样。因此,总的来说,请关注可读性。


对于#define T char,我得到:

v[j + i * D] = v[j + i * D] == 0 ? 1 : 0;
// Build 3.65369 seconds. Time to toggle all bits one by one 0.0580222 seconds.
//v[j + i * D] = !v[j + i * D];
// Build 3.65898 seconds. Time to toggle all bits one by one 0.0573292 seconds.
//v[j + i * D] ^= 1;
// Build 3.95643 seconds. Time to toggle all bits one by one 0.0570291 seconds.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-12-20
    • 2011-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-14
    相关资源
    最近更新 更多