Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何使用1个非常大的数组快速初始化_C++_Arrays_Performance - Fatal编程技术网

C++ 如何使用1个非常大的数组快速初始化

C++ 如何使用1个非常大的数组快速初始化,c++,arrays,performance,C++,Arrays,Performance,我有一个能量数组: int* arr = new int[BIGNUMBER]; 如何用一个数字快速完成它。通常我会这样做 for(int i = 0; i < BIGNUMBER; i++) arr[i] = 1 for(int i=0;i

我有一个能量数组:

int* arr = new int[BIGNUMBER];
如何用一个数字快速完成它。通常我会这样做

for(int i = 0; i < BIGNUMBER; i++)
    arr[i] = 1
for(int i=0;i
但我认为这需要很长时间


我可以使用
memcpy
或类似功能吗?

您可以尝试使用标准功能:

使用memset或memcpy

memset(arr, 0, BIGNUMER); 
尝试使用memset

memset(arr, 1, BIGNUMBER);

安迪·普劳尔的
std::uninitialized_fill_n()
解决方案的一些可能替代方案,仅供子孙后代使用:

  • 如果你很幸运,并且你的值是由所有相同的字节组成的,那么我会这样做
  • 有些实现提供了16位版本的memsetw,但这并不普遍
  • GCC有一个扩展,可以填充范围
  • 我曾经使用过一些ARM系统,这些系统的库加速了CPU和DMA的word fill变体,并在汇编中手工编码——如果您不太关心可移植性的话,您可以看看您的平台是否提供了这些功能
  • 根据处理器的不同,即使是查看SIMD内部函数的循环也可能会带来提升;一些SIMD单元具有加载/存储管道,这些管道针对这样的数据移动进行了优化。另一方面,在寄存器类型之间移动可能会受到严厉的惩罚
最后但绝对不是最不重要的一点,回应一些评论:您应该测试并查看。编译器往往非常擅长识别和优化这样的模式——您可能只是在用简单循环或
未初始化的填充
以外的任何东西来权衡可移植性或可读性

您可能对前面的问题感兴趣:


动态数组的替代方法是使用构造函数,该构造函数接受每个元素的初始值:

std::vector<int> v(BIGNUMBER, 1); // 'BIGNUMBER' elements, all with value 1.
std::向量v(BIGNUMBER,1);/'BIGNUMBER'元素,所有元素的值均为1。

如前所述,绩效需要衡量。这种方法提供了自动释放内存的额外好处。

在启用优化的Linux/x86 gcc下,您的代码将编译为以下内容:

rax = arr
rdi = BIGNUMBER

400690: c7 04 90 01 00 00 00    movl   $0x1,(%rax,%rdx,4)
将立即
int(1)
移动到rax+rdx

400697: 48 83 c2 01             add    $0x1,%rdx
增量寄存器

40069b: 48 39 fa                cmp    %rdi,%rdx
Cmp-rdi到rdx

40069e: 75 f0                   jne    400690 <main+0xa0>
40069e:75 f0 jne 400690
如果已达到BIGNUMBER,请跳回开始


在我的机器上,每GB大约需要1秒,但我打赌大部分时间都是在物理内存中分页以支持未初始化的分配。

只需将循环展开8或16次即可。像
memcpy
这样的函数速度很快,但它们确实是为了方便,而不是为了比您可能编写的任何函数都快:

for (i = 0; i < BIGNUMBER-8; i += 8){
  a[i+0] = 1; // this gets rid of the test against BIGNUMBER, and the increment, on 7 out of 8 items.
  a[i+1] = 1; // the compiler should be able to see that a[i] is being calculated repeatedly here
  ...
  a[i+7] = 1;
}
for (; i < BIGNUMBER; i++) a[i] = 1;
(i=0;i{ a[i+0]=1;//这将消除针对BIGNUMBER的测试,以及8项中7项的增量。 a[i+1]=1;//编译器应该能够看到此处重复计算a[i] ... a[i+7]=1; } 对于(;i

编译器可能可以为您展开循环,但为什么要冒险呢?

memset(arr,1,sizeof(int)*BIGNUMBER)

尽量避免假设某件事需要多长时间才能完成。你真的试过这样做吗?需要多长时间?通常情况下,
bigname
是什么?如果这是您的瓶颈,那么您的代码结构错误。我猜你填充数组是有原因的,所以你必须有另一个(可能更慢的)循环。无论如何,
memcpy
可能会慢一些,因为它需要进行内存查找,而不是使用寄存器/常量。仅供参考:我尝试了基于memcpy的算法,但没有得到任何有意义的速度差异。@RobertKilar:以前尝试使用
std::uninitialized\u fill\n()
函数,并检查它是否适合您。最有可能的是,该函数最终调用了
memcpy()
,用于普通类型,所有内容都被内联。在这种情况下,
uninitialized\u fill\n
比更明显的
fill\n
提供了什么,不适用于普通类型-只是名称更清楚地表明将填充未初始化的内存区域。我使用
BIGNUMBER=1测试了OP解决方案和
std::uninitialized_fill
,但对于非普通类型,这将是未定义的行为,因为内存已经用有效对象初始化。您必须使用
fill\n
。这是我的(小)反对意见,它对所有类型都更加一致。但我也理解你的推理。
memset
不适用于非零数字,因为它在字节级别上工作
memcpy
可能会比手动循环慢,因为它需要同时引用其他内存writing@Dave:您是指非字节值
memset
肯定可以处理任意无符号字符。@Dave还说,memcpy的速度会慢一些,因为您必须从某个地方复制,这意味着您必须用1填充数组,然后在该数组上使用memcpy。如果仅仅用1来填充数组,那似乎很愚蠢。@user268396不,我的意思是
memset(arr,1,BIGNUMBER)
将用16843009而不是1来填充数组。@Dave:这在读取时是一个微妙的类型问题,因为
int
的字节数比
无符号字符的字节数多。然而,实际上,您的评论似乎暗示
memset(arr,0xA,BIGNUMBER)
将无法用
AAAA
填充数组(假设为32位整数)。哪一个最有效
memset
不适用于非零数字,因为它在字节级别工作。那么您必须在
char
数组上使用过它。在
int
数组上(如问题中所述),它将产生错误的结果。e、 g.
memset(arr,1,…)
将数字设置为16843009(假设为32位

40069e: 75 f0                   jne    400690 <main+0xa0>
for (i = 0; i < BIGNUMBER-8; i += 8){
  a[i+0] = 1; // this gets rid of the test against BIGNUMBER, and the increment, on 7 out of 8 items.
  a[i+1] = 1; // the compiler should be able to see that a[i] is being calculated repeatedly here
  ...
  a[i+7] = 1;
}
for (; i < BIGNUMBER; i++) a[i] = 1;