简体   繁体   English

在C或C ++中使用1到10 ^ 10的随机数填充数组

[英]Filling an array with random numbers from 1 to 10^10 in C or C++

a part of an assignment of mine is based on an array (its size is given by the user) which contains random numbers from 1 to 10^10. 我的作业的一部分基于一个数组(其大小由用户指定),该数组包含1到10 ^ 10的随机数。 Then we have to find the k-th smaller number of the array. 然后,我们必须找到数组的第k个较小的数字。 Here's what I tried: 这是我尝试过的:

#include <cstdlib>
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <time.h>

using namespace std;

void swap(int *x,int *y)
{
    int temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

int choose_pivot(int i,int j )
{
    return((i+j) /2);
}

// Print array
void printarr(int arr[],int n)
{
    int i;
    for(i=0;i<n;i++)
        printf("%d\t",arr[i]);
}

// Find algorithm
int find1(int arr[],int left,int right,int k)
{
    int i,j,pivot;
    if (left==right)
        return arr[left];
    else
    {
        i=left;
        j=right+1;
        pivot= arr[left];
        do
        {
            do {
                i=i+1;
            } while (arr[i]>=pivot);
            do {
                j =j-1;
            } while (arr[j]<=pivot);
            if (i<j)
                swap(arr[i],arr[j]);
        } while (j<=i);
    }
    swap(arr[left],arr[j]);
    if (k==j)
        return arr[j];
    else if (k<j)
        find1(arr,left,j-1,k);
    else 
        find1(arr,j+1,right,k-j);
}

int main(int argc, char *argv[])
{
    srand(time(NULL));
    int n,i,fi,k;
    printf("Give array's size:\n");
    scanf("%d",&n);
    int pin[n];
    for (i=0;i<n;i++)
        pin[i]=((rand()*rand()) % 1000000000) +1;
    printf("Give k: \n");
    scanf("%d",&k);
    printf("The array contains the following numbers:\n\n");
    printarr(pin,n);
    fi=find1(pin,0,n-1,k);//find the k-th smallest number in the array
    printf("The k-th smallest number is: %d",fi);

    system("PAUSE");
}

As you can see 10^10 is a very big value, and I did something else to fill the array with the random numbers. 如您所见,10 ^ 10是一个非常大的值,我做了其他一些事情,用随机数填充数组。 Is it correct? 这是正确的吗? Is there something else I could do? 还有什么我可以做的吗? And my second problem is on the find algorithm. 我的第二个问题是查找算法。 It doesn't work. 没用 Could anyone help me with these? 有人可以帮我这些吗? Thank you very much 非常感谢你

long long get_big_rand()
{

    long long result;
    do {
        result = (rand() & 0x3ff);
        result <<= 12;
        result |= (rand() & 0xfff);
        result <<= 12;
        result |= (rand() & 0xfff);
    } while (++result > 10000000000ULL);
    return result;
}

rand()*rand() is a lot different than a single rand() , it decreases the randomness and changes its distribution. rand()*rand()与单个rand()有很大不同,它减少了随机性并更改了其分布。 See this question for a deeper explanation. 有关更多说明,请参见此问题

Also, an integer usually is 4 bytes. 另外,整数通常为4个字节。 It can contain a value as big as 2^31 (2 billions and something) or 2^32 (4 billions and more) if it's unsigned. 如果它是未签名的,则可以包含2^31 (20亿左右)或2^32 (40亿以上)的值。 You can see the max number it can contain checking the INT_MAX macro defined in limits.h . 您可以看到它可以包含的最大数量,它可以检查limits.h定义的INT_MAX宏。 10^10 is 10 billions, it won't fit in an integer, you'll have to use a bigger type ( long long usually is 64 bytes thus more than you need). 10^10是100亿,它不适合整数,您必须使用更大的类型( long long通常是64个字节,因此超出了您的需要)。

rand , also, returns numbers up to RAND_MAX , and since it returns an int , it won't bigger than INT_MAX . rand也返回不超过RAND_MAX数字,并且由于它返回一个int ,因此不会大于INT_MAX You should use some other way to generate a number as big as 10^10 . 您应该使用其他方法来生成最大为10^10

If you don't care about randomness and random number distributions you could sum n random numbers (obtained by rand ) so that n=10^10 / RAND_MAX . 如果您不关心随机性和随机数分布,则可以对n随机数求和(由rand获得),以便n=10^10 / RAND_MAX

If you take a closer look at 10 10 you will notice that it's quite a round limit. 如果您仔细观察10 10,您会发现这是一个相当大的限制。 My take on this would be to generate each number, one digit at a time and ignoring insignificant zeroes. 我的看法是每次生成一个数字,一次生成一个数字,而忽略不重要的零。 At this point you would have a number between 0 and 10 10 -1 inclusive. 此时,您将拥有一个介于0到10 10 -1之间的数字。 All you're left with doing is adding a 1. 您剩下要做的就是添加1。

As for random()*random() , that is the exact topic of this other question . 至于random()*random() ,这是另一个问题确切主题。

Alin 阿林

Problem #1, an int will only hold a number of size 2^31 in size. 问题1,一个int只能容纳大小为2 ^ 31的数字。 You'll need a slightly bigger alternative for your pin array. 您需要引脚阵列更大的替代方案。

Also, multiplying your two random numbers together really doesn't do much - except perhaps make the number less random. 另外,将两个随机数相乘实际上并没有多大作用-只是使数字不那么随机。

Next, you can't create an array on the stack dynamically with the user's input. 接下来,您不能使用用户的输入在堆栈上动态创建一个数组。 That will require a new solution to make alloc an array for you. 这将需要一个新的解决方案来为您分配一个数组。

rand()*rand() isn't going to do anything for you. rand()* rand()不会为您做任何事情。 It doesn't scale the way you think it does, and it does change the distribuon. 它不能像您认为的那样扩展规模,并且确实会改变发行版。 In fact 事实上

double norm_rand(){
    double r=0;
    for(unsigned i=0;i!=12;++i)
        r+=rand()/static_cast<double>(RAND_MAX);
    return (r/12)-6;
}

is a common way to simulate a normal distribution with mean 0 and variance 1; 是模拟均值0和方差1的正态分布的常用方法;

The best way to to get large random numbers is using a random number device, like /dev/urandom or RtlGenRandom. 获取大随机数的最佳方法是使用随机数设备,例如/ dev / urandom或RtlGenRandom。 ie

typedef unsigned long long big_type;
std::vector<double> rnums;
std::vector<big_type> buf(numtoread);
        std::ifstream rnds("/dev/urandom"); 
rnds.read(reinterpret_cast<char*>(&buf[0],buf.size()*sizeof(big_type));
std::transform(buf.begin(),buf.end(),std::back_inserter(rnums),
     [](big_type const& i){
        return (i*100000000000.)/(std::numeric_limits<big_type>::max());
     });

At the risk of doing your homework for you, an entirely different approach is to use the libraries that come with C++. 冒着为您做作业的风险,一种完全不同的方法是使用C ++附带的库。

#include <cassert>
#include <sstream>
#ifndef _MSC_VER  //then assume Linux
#include <tr1/random>
#else
#include <random>
#endif
#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <iterator>
#include <iostream>
int main(int argc, char** argv)
{
    assert(argc==3);
    unsigned const numentries=boost::lexical_cast<unsigned>(argv[1]);
    unsigned const k=boost::lexical_cast<unsigned>(argv[2]);
    std::cout<<" finding "<<k<<"th of "<< numentries<<" entries\n";
    assert(k<=numentries);
    std::vector<double> nums(numentries);
    std::tr1::uniform_real<> rng(0.,10000000000.);
    std::tr1::minstd_rand generator(42u);
    std::tr1::variate_generator<std::tr1::minstd_rand, std::tr1::uniform_real<> >
            uni(generator, rng);
    std::generate_n(nums.begin(),nums.size(),uni);
    std::cout<<" Generated:\t ";
    std::copy(nums.begin(),nums.end(),std::ostream_iterator<double>(std::cout,"\t"));
    std::sort(nums.begin(),nums.end());
    std::cout<<"\n The "<<k<<"th smallest entry is "<<nums[k]<<"\n";
    return 0;
}

(If you are in class at the level of just asking for making an array of rand numbers and you hand that in, they'll probably fail you) What I do in practice is to combine the two approaches. (如果您在课堂上只是要求制作一个兰特数,然后上交,他们可能会使您失败)。我在实践中要做的是将两种方法结合起来。 This is used in place of the linear conguentual rng used above (the minstd_rand): 用它代替上面使用的线性条件rng(minstd_rand):

template<typename bigtype=unsigned>
struct randeng {
    typedef bigtype result_type;
    randeng(unsigned x) :
        m_samplesrequired(x), m_samples(x), m_lastused() {
        std::ifstream rand;
        rand.open("/dev/urandom");
        assert(rand);
        rand.read(reinterpret_cast<char*> (&*(m_samples.begin())),
                m_samplesrequired * sizeof(unsigned));
    }
    result_type operator()() const {
        assert(m_lastused<m_samplesrequired);
        return m_samples[m_lastused++];
    }
    result_type max() const {
        return std::numeric_limits<result_type>::max();
    }
    result_type min() const {
        return 0;
    }
    unsigned m_samplesrequired;
    std::vector<result_type> m_samples;
    mutable unsigned m_lastused;
};

This always seems to give much better results. 这似乎总是能带来更好的结果。

you forgot your return statements. 您忘记了退货单。 at the end of find1 you should be doing: find1的结尾,您应该执行以下操作:

if (k==j)
    return arr[j];
else if (k<j)
    return find1(arr,left,j-1,k);
else 
    return find1(arr,j+1,right,k-j);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM