我试图生成一些随机的64位数字时遇到了这个奇怪的问题,并注意到这段代码只能给出低32位<0x8000_0000的数字.
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <cstdlib>
#include <ctime>
using namespace std;
void bin_range(uint64_t addr);
void print_range();
uint64_t GiB = 1024*1024*1024;
#define NUM_TRIES 10000
int range[14] = {0};
int main(){
srand(time(NULL));
for(int i = 0; i < NUM_TRIES; ++i){
uint64_t addr = ((uint64_t) rand() << 32) | rand();
addr &= 0x3FFFFFFFFFull;
if(addr > ((uint64_t) 14*GiB)){
--i;
continue;
}
bin_range(addr);
}
print_range();
return 0;
}
void bin_range(uint64_t addr){
if(addr < GiB)
range[0]++;
else if(addr < 2*GiB)
range[1]++;
else if(addr < 3*GiB)
range[2]++;
else if(addr < 4*GiB)
range[3]++;
else if(addr < 5*GiB)
range[4]++;
else if(addr < 6*GiB)
range[5]++;
else if(addr < 7*GiB)
range[6]++;
else if(addr < 8*GiB)
range[7]++;
else if(addr < 9*GiB)
range[8]++;
else if(addr < 10*GiB)
range[9]++;
else if(addr < 11*GiB)
range[10]++;
else if(addr < 12*GiB)
range[11]++;
else if(addr < 13*GiB)
range[12]++;
else if(addr < 14*GiB)
range[13]++;
}
void print_range(){
for(int i = 0; i < 14; ++i){
cout <<dec<< "range["<<i<<"]\thas "<<((float)range[i]/NUM_TRIES)*100.0<<"%"<<endl;
}
}
Run Code Online (Sandbox Code Playgroud)
当我运行它时,我看到只有地址范围与addr [31:28] <8通过这个if语句!
range[0] has 12.25%
range[1] has 12.17%
range[2] has 0%
range[3] has 0%
range[4] has 13.22%
range[5] has 12.19%
range[6] has 0%
range[7] has 0%
range[8] has 12.53%
range[9] has 11.83%
range[10] has 0%
range[11] has 0%
range[12] has 12.85%
range[13] has 12.96%
Run Code Online (Sandbox Code Playgroud)
这g++ -g -c -fverbose-asm -Wa,-adhln calc.cpp > calc.lst
是使用g ++版本4.4.6 编译时这个if语句的相关反汇编:
32:calc.cpp **** addr &= 0x3FFFFFFFFFull;
407 .loc 2 32 0
408 00ad 48B8FFFF movabsq $274877906943, %rax #, tmp129
408 FFFF3F00
408 0000
409 00b7 482145E0 andq %rax, -32(%rbp) # tmp129, addr
33:calc.cpp **** if(addr > ((uint64_t) 14*GiB)){
410 .loc 2 33 0
411 00bb 488B0500 movq GiB(%rip), %rax # GiB, GiB.59
411 000000
412 00c2 4801C0 addq %rax, %rax # tmp131
413 00c5 488D14C5 leaq 0(,%rax,8), %rdx #, tmp132
413 00000000
414 00cd 4889D1 movq %rdx, %rcx # tmp132,
415 00d0 4829C1 subq %rax, %rcx # tmp130,
416 00d3 4889C8 movq %rcx, %rax #, D.22316
417 00d6 483B45E0 cmpq -32(%rbp), %rax # addr, D.22316
418 00da 7306 jae .L20 #,
34:calc.cpp **** --i;
Run Code Online (Sandbox Code Playgroud)
在我看来,g ++正在使if语句成为32位比较,但从反汇编中我看到它是一个四字比较,所以对我来说这没有意义为什么会发生这种情况.有任何想法吗?
更新:我知道这不是rand()的问题,因为当我将for循环改为这样:
for(int i = 0; i < NUM_TRIES; ++i){
uint64_t addr = ((uint64_t) rand() << 32) | rand();
addr %= 14*GiB;
//addr &= 0x3FFFFFFFFFull;
//if(addr > ((uint64_t) 14*GiB)){
//--i;
//continue;
//}
bin_range(addr);
}
Run Code Online (Sandbox Code Playgroud)
我确实得到了输出的全部数字:
range[0] has 7.09%
range[1] has 6.85%
range[2] has 7.24%
range[3] has 7.75%
range[4] has 7.39%
range[5] has 7.19%
range[6] has 6.92%
range[7] has 6.63%
range[8] has 7.33%
range[9] has 6.95%
range[10] has 7.11%
range[11] has 7.28%
range[12] has 7.08%
range[13] has 7.19%
Run Code Online (Sandbox Code Playgroud)
这一行:
uint64_t addr = ((uint64_t) rand() << 32) | rand();
Run Code Online (Sandbox Code Playgroud)
不会生成正确的64位随机数.如果RAND_MAX是0x7fffffff(这是通常的,并且假设对你的情况是正确的),那么addr它的第31和第63位为零.这就是你体验的原因,数字[2Gi; 4Gi]根本就没有生成.如果您修改32为31,您将获得这些数字.
但请注意,RAND_MAX是实现定义的,最好使用新的随机工具(如果至少使用C++ 11):https://en.cppreference.com/w/cpp/numeric/random