为什么这个64位比较被视为32位?

Mel*_*are -1 c++ random

我试图生成一些随机的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)

gez*_*eza 5

这一行:

    uint64_t addr = ((uint64_t) rand() << 32) | rand();
Run Code Online (Sandbox Code Playgroud)

不会生成正确的64位随机数.如果RAND_MAX0x7fffffff(这是通常的,并且假设对你的情况是正确的),那么addr它的第31和第63位为零.这就是你体验的原因,数字[2Gi; 4Gi]根本就没有生成.如果您修改3231,您将获得这些数字.

但请注意,RAND_MAX是实现定义的,最好使用新的随机工具(如果至少使用C++ 11):https://en.cppreference.com/w/cpp/numeric/random