C 我可以避免在数组的连续子集中写入相同值的循环吗?
我有一个程序,我重复一系列的方法来重现时间的演变。我必须做的一件事是为一个非常大的数组的元素的长连续子集写入相同的值。知道哪些元素是我想要的,哪些值是我想要的,除了逐个循环设置这些值,还有其他方法吗 编辑:为了清楚起见,我想避免以下情况:C 我可以避免在数组的连续子集中写入相同值的循环吗?,c,arrays,loops,C,Arrays,Loops,我有一个程序,我重复一系列的方法来重现时间的演变。我必须做的一件事是为一个非常大的数组的元素的长连续子集写入相同的值。知道哪些元素是我想要的,哪些值是我想要的,除了逐个循环设置这些值,还有其他方法吗 编辑:为了清楚起见,我想避免以下情况: double arr[10000000]; int i; for (i=0; i<100000; ++i) arr[i] = 1; double arr[10000000]; int i; 对于(i=0;i<p>),我
double arr[10000000];
int i;
for (i=0; i<100000; ++i)
arr[i] = 1;
double arr[10000000];
int i;
对于(i=0;i<p>),我有一点脸颊和不可移植的可能性供您考虑。如果您将缓冲区调整为2的大小,则可以用一个加倍来缓冲该缓冲区,然后使用<代码> MeMCPY 复制缓冲区的较大的块,直到缓冲区满。
首先,在接下来的8个字节上复制前8个字节…(现在有2个双字节)
…然后在接下来的16个字节上复制前16个字节…(现在有4个双字节)
…然后在接下来的32个字节上复制前32个字节…(现在有8个双字节)
……等等
很明显,我们实际上不会多次调用memcpy
,如果memcpy
的实现比简单的循环快得多,我们将看到一个好处
试着构建和运行这个,告诉我它在你的机器上是如何运行的。这是一个非常零碎的概念证明
#include <string.h>
#include <time.h>
#include <stdio.h>
void loop_buffer_init(double* buffer, int buflen, double val)
{
for (int i = 0; i < buflen; i++)
{
buffer[i] = val;
}
}
void memcpy_buffer_init(double* buffer, int buflen, double val)
{
buffer[0] = val;
int half_buf_size = buflen * sizeof(double) / 2;
for (int i = sizeof(double); i <= half_buf_size; i += i)
{
memcpy((unsigned char *)buffer + i, buffer, i);
}
}
void check_success(double* buffer, int buflen, double expected_val)
{
for (int i = 0; i < buflen; i++)
{
if (buffer[i] != expected_val)
{
printf("But your whacky loop failed horribly.\n");
break;
}
}
}
int main()
{
const int TEST_REPS = 500;
const int BUFFER_SIZE = 16777216;
static double buffer[BUFFER_SIZE]; // 2**24 doubles, 128MB
time_t start_time;
time(&start_time);
printf("Normal loop starting...\n");
for (int reps = 0; reps < TEST_REPS; reps++)
{
loop_buffer_init(buffer, BUFFER_SIZE, 1.0);
}
time_t end_time;
time(&end_time);
printf("Normal loop finishing after %.f seconds\n",
difftime(end_time, start_time));
time(&start_time);
printf("Whacky loop starting...\n");
for (int reps = 0; reps < TEST_REPS; reps++)
{
memcpy_buffer_init(buffer, BUFFER_SIZE, 2.5);
}
time(&end_time);
printf("Whacky loop finishing after %.f seconds\n",
difftime(end_time, start_time));
check_success(buffer, BUFFER_SIZE, 2.5);
}
要使用小于2的完美幂次的缓冲区,只需尽可能使用2的递增幂次,然后在最后一个memcpy
中填写剩余部分
(编辑:在任何人提到它之前,使用静态double(也可以在编译时初始化它)当然毫无意义,但在运行时请求一段新的内存时,它也可以工作。)
看起来这个解决方案对缓存大小或其他硬件优化非常敏感。在我的旧(大约2009年)笔记本电脑上,memcpy
解决方案比简单循环慢或慢,直到缓冲区大小下降到1MB以下。低于1MB左右,memcpy
解决方案恢复到两倍的速度
我有一个程序,我重复一系列的方法来复制
时间进化。我要做的事情之一就是写同样的东西
非常大数组的元素的长连续子集的值。
知道哪些元素是我想要的,哪些值,还有其他的吗
而不是通过循环来逐个设置这些值
原则上,您可以随意初始化数组,而无需使用循环。如果该数组具有静态持续时间,那么该初始化实际上可能非常有效,因为初始值以某种方式存储在可执行映像中
否则,您有几个选项:
- 如果数组元素是字符类型,则可以使用
memset()
。这很可能涉及内部循环,但您自己的代码中不会有循环
- 如果要设置的值的表示形式的所有字节都相等,例如任何算术类型中0的典型表示形式,则
memset()
也是一种可能
- 正如您所建议的,如果您有另一个具有适当内容的数组,则可以将其部分或全部复制到目标数组中。为此,您可以使用
memcpy()
,除非源和目标可能重叠,在这种情况下,您需要memmove()
- 更一般地说,您可以从一些外部源(例如文件)读入数据(例如,通过
fread()
)。但是,不要指望任何基于I/O的解决方案能够发挥作用
- 您可以编写特定于数组数据类型的
memset()
模拟函数。这样的函数可能需要在内部使用某种形式的循环,但您可以避免在调用方中使用这种循环
- 您可以编写扩展到所需循环的宏。这可以是泛型类型,因此不同的数据类型不需要不同的版本。它使用循环,但循环在使用时不会出现在源代码中
- 如果您事先知道要设置多少元素,那么原则上,您可以在不循环的情况下编写那么多赋值语句。但是我无法想象为什么您会如此希望避免循环,以至于您会对大量元素使用此方法
但是,除了最后一个“实际执行”循环之外,所有这些循环都只是为了避免在您要设置数组元素的位置使用循环结构将代码弄乱。其中一些循环结构可能更清晰,更容易被人类读者理解。需要查看一些代码以了解发生了什么。只有当该值为单个值时,才可以使用循环结构然而,e字节(当然,这实际上也是一个循环,只是不是你自己键入的循环。)根据你给我们的粗略信息,循环听起来完全正确。你有什么理由不想使用循环吗?你如何避免“浪费时间”,如果您必须实际设置此内存的值?嗯,这听起来确实是一个XY问题使用与上面的memset
解决方案类似的解决方案,您可以将第一个双精度写入数组的开头,然后memcpy
将8个字节写入数组开头的位置+8个字节。现在memcpy
两个双精度写入下一个位置,因此您有4个双精度。现在memcpy
all四个双打到下一个位置,所以你有8个双打…等等。(这看起来很奇怪,可能不会比一个简单的循环快)我在我的机器上试过,得到了大约相同的时间(23和11秒)。我建议更改
和
Normal loop starting...
Normal loop finishing after 21 seconds
Whacky loop starting...
Whacky loop finishing after 9 seconds