数组读取出现异常值求助:随机数数组偶尔出现超大值或连续0
问题描述
尝试生成范围(-1 < x < 1)的随机数存入数组,使用代码p[i] = (double)2*rand()/RAND_MAX-1;,随机数生成阶段无异常,但读取数组时p[j]偶尔出现连续0或极大值(如28040310013302517619982145582267442588916597218393832117220025500645045329090733358176461602261387426622486260295380601312859137588835453228348262580224.000000),已确认索引i、j在数组范围内,附上C语言代码:
#include <stdio.h> #include <stdlib.h> int main(){ FILE *file; file = fopen("result.txt","w"); int N = 10000; double p[N]={0}; for(int i=0;i<N;i++){ p[i] = (double)2*rand()/RAND_MAX-1; //range[-1, 1] } int j; double x,y; for(int n=-100; n<=100; n++){ double q = 0; for(int i=0; i<N; i++){ j = (i+n)%N; q += p[i]*p[j]; } fprintf(file,"%d\t%f\n",n,q); } fclose(file); }
错误原因
负数取模导致数组越界
C语言中,负数取模的结果为负数。例如当i=0、n=-1时,(i+n)%N = (-1)%10000 = -1,此时访问p[-1]属于数组越界行为,会读取到内存中未初始化的垃圾数据,表现为极大值或随机0值。你误以为索引在范围内,但实际负数索引已经越界。随机数计算存在整数溢出风险
(double)2*rand()的执行顺序是先将2转为double,再与rand()的整数结果相乘。如果RAND_MAX是较大的整数(比如32位系统中的2^31-1),2*rand()可能超出int类型的取值范围,导致整数溢出,进而生成错误的随机数。
修复方案
1. 修正索引计算
将j = (i+n)%N;改为:
j = (i + n + N) % N;
通过额外加N确保i+n+N始终为正数,取模后得到的索引范围始终是0~N-1,避免越界访问。
2. 修正随机数生成代码
将随机数生成行改为:
p[i] = (double)rand() * 2.0 / RAND_MAX - 1.0;
先将rand()的结果转为double,再进行浮点运算,彻底避免整数溢出问题,同时保证随机数范围正确(若要严格的(-1,1),可改为(double)rand() * 2.0 / (RAND_MAX + 1.0) - 1.0)。
可选:初始化随机数种子
当前代码未设置随机数种子,每次运行会生成相同的随机数序列。可在main开头添加:
srand(time(NULL));
记得包含头文件#include <time.h>,这样每次运行的随机数序列都会不同。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <time.h> int main(){ FILE *file; file = fopen("result.txt","w"); int N = 10000; double p[N]={0}; srand(time(NULL)); // 初始化随机数种子 for(int i=0;i<N;i++){ p[i] = (double)rand() * 2.0 / RAND_MAX - 1.0; // 范围[-1, 1] } int j; for(int n=-100; n<=100; n++){ double q = 0; for(int i=0; i<N; i++){ j = (i + n + N) % N; // 修正索引计算 q += p[i]*p[j]; } fprintf(file,"%d\t%f\n",n,q); } fclose(file); return 0; }
内容的提问来源于stack exchange,提问作者Titanium

