【问题标题】:fastest way to modify part of array修改部分数组的最快方法
【发布时间】:2012-09-08 01:33:56
【问题描述】:

我想对 bool 数组的连续元素块执行 not 操作,然后读回完整的数组。我正在使用以下代码来执行操作。

bool arr[100000]={0};
cin>>x>>y;
for(i=x; i<=y; i++)
 arr[i]=!arr[i];

//Some other operations on the array

for(i=0; i<=100000; i++)
 arr+=arr[i];

这很好,但我正在尝试提高程序的速度。有没有更好的方法来执行相同的操作?

【问题讨论】:

  • 您是否尝试展开?您是否尝试过使用 structs 作为 32 位部件来使 32 位不使用单个操作进行操作?
  • cin &gt;&gt; i 然后for(i = x... 如果你只是要替换它,为什么还要麻烦输入呢?
  • 这段代码没有意义。为什么要从std::cin 填充i,然后立即用x 覆盖它? arr+=arr[i]; 应该是什么意思?
  • 我认为他正在更改数组相对于其他元素的地址,并且数组地址开始在那里晃来晃去
  • 将 32 位打包到一个 int 中(假设它在您的机器上是 32 位),然后在 int 上使用按位“非”。您甚至可以使用 SIMD 命令同时使用 4 个整数。你试过编译器优化吗?

标签: c++ performance processing-efficiency


【解决方案1】:

考虑使用 bitset。比较性能-也许会更好。

std::bitset<100000> arr;
cin>>x>>y;
for(i=x; i<=y; i++)
 arr.flip(i);

//Some other operations on the array
unsigned int carr = arr.count();

为了更优化(请测量并且不要相信),您可以使用自己的 bitset 版本,这不是测试代码:

const size_t arr_bitlen = 100000;
typedef unsigned int arr_type;
const size_t arr_type_size = sizeof(arr_type);
const size_T arr_len = (arr_bitlen + arr_type_size - 1) / arr_type_size;
arr_type arr[arr_len] = { 0 };
cin>>x>>y;
unsigned int x_addr = x / arr_type_size;
unsigned int y_addr = y / arr_type_size;
unsigned int x_bit = x % arr_type_size;
unsigned int y_bit = y % arr_type_size;

if (0 == x_bit)
    for (i=x_addr; i<=y_addr; i++)
       arr[i] = ~arr[i]; // revert all bits (bools)
else {
  // deal with first element in range ( ....xxxx - change only x-s
  arr_type x_mask = ((1 << x_bit) - 1) << (arr_type_len - x_bit);
  arr[x_addr] ^= x_mask; 
  for (i = x_bit + 1; i < arr_type_size; ++i)
      arr[i] = ~arr[i]; // revert all bits (bools)
}
if (y_bit > 0) // try to invert 0..y_bit in arr[y_addr + 1] by yourself

//Some other operations on the array
see implementation of std::bitset<N>::count() - it is very clever - just copy it

【讨论】:

  • 这并没有提高性能。我希望删除循环并通过单个操作执行翻转,这将对整体性能产生巨大影响
  • 您可以制作自己的结构,如 bitset - 直接操作内部数据。然后您可以将否定次数减少 32。
  • 如何直接操作数据?你能举个小例子吗?我是 C++ 新手,所以我在这件事上遇到了一些麻烦。
  • 在互联网上搜索“C 位操作”。我给出了第二个例子——但这只是一个例子——没有以任何方式进行测试。使用前对其进行单元测试。或者也许你可以在 BOOST 库中找到有用的东西。我建议保留您的第一个解决方案或仅使用 bitset。最后一个提案将很难实施/理解。
  • 查看我的问题stackoverflow.com/questions/12433154/… - cmets 中有一些提示。不要忘记旧的 memcpy memset 函数
【解决方案2】:

既然我发表了关于使用 int(或者实际上是 int64)的评论,我不妨把它写下来,你可以评估它是否值得。会是这样的。请原谅任何错误,因为我只是在我的孩子们正在观看可笑的垃圾星期六早上的卡通片时将其放入浏览器中。

// I'm gonna assume 32-bit ints here.  Makes the other maths clearer.
// Sorry about all the '4' and '32' constants =P
const size_t arrLen = 100000 / 4 + 1;
int arr[arrLen];

//This gets filled with your data...
memset((void*)arr, 0, arrLen*4);

cin >> x >> y;
int leftMask = 0xffffffff >> (x % 32);      // "(x & 0x1f)" faster?
int rightMask = ~(0x7fffffff >> (y % 32));  // "(y & 0x1f)" faster?
x /= 32;                                    // "x >>= 5" faster?
y /= 32;                                    // "y >>= 5" faster?

if( x == y )
{
    // Intersect the masks
    leftMask &= rightMask;
    arr[x] = (arr[x] & ~leftMask) | (~arr[x] & leftMask);
}
else if( x < y )
{
    // Flip the left and right ends
    arr[x] = (arr[x] & ~leftMask) | (~arr[x] & leftMask);
    arr[y] = (arr[y] & ~rightMask) | (~arr[y] & rightMask);

    // Flip everything in between
    for( int i = x+1; i < y; i++ ) {
        arr[i] ^= 0xffffffff;  // Or arr[i] = ~arr[i] -- whichever is faster
    }
}

上述循环的替代方案,如果有什么不同的话......

// Flip everything in between
for( int *a = arr+x+1, *b = arr+y; a < b; a++ ) {
    *a = ~*a;
}

练习是尝试使用 64 位整数。就个人而言,我认为这种方法会比其他任何方法都快,除非您只翻转几位。

我的右侧掩码中可能有一个偏移一位错误。如果有人发现它,请发表评论。脑袋空空的。 =)

【讨论】:

  • 啊,将右侧位掩码更正为 0x7fffffff 以包含 y。我怀疑存在一个错误。
猜你喜欢
  • 1970-01-01
  • 2018-04-26
  • 2014-03-12
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-23
相关资源
最近更新 更多