tạo số kép ngẫu nhiên trong c ++


83

Cách tạo các số ngẫu nhiên giữa hai số đôi trong c ++, những số này phải giống như xxxxx, yyyyy.


6
"những số này phải giống như xxxxx, yyyyy". Cách tạo số nhân đôi ngẫu nhiên và cách định dạng số nhân đôi dưới dạng chuỗi, là những vấn đề hoàn toàn riêng biệt.
Steve Jessop

Và hãy suy nghĩ về nó theo cách khác: tạo các nhân đôi phân bố đều và tạo các số thập phân phân bố đều có phần khác nhau, mặc dù có liên quan đến các nhiệm vụ.
Steve Jessop

Việc tạo ra các số nguyên phân bố đều có liên quan chặt chẽ hơn đến vấn đề số thập phân.
Potatoswatter

Câu trả lời:


116

Đây là cách

double fRand(double fMin, double fMax)
{
    double f = (double)rand() / RAND_MAX;
    return fMin + f * (fMax - fMin);
}

Hãy nhớ gọi srand () với một hạt giống thích hợp mỗi khi chương trình của bạn bắt đầu.

[Chỉnh sửa] Câu trả lời này đã lỗi thời vì C ++ có thư viện ngẫu nhiên không dựa trên C riêng (xem câu trả lời của Alessandro Jacopsons) Nhưng, điều này vẫn áp dụng cho C


10
Nếu bạn thêm 1 vào RAND_MAX, hãy thực hiện cẩn thận vì nó có thể bằng INT_MAX. double f = rand() / (RAND_MAX + 1.0);
Steve Jessop

8
Lưu ý rằng tính ngẫu nhiên của điều này có thể bị hạn chế. Phạm vi xxxxx, yyyyy đề xuất 10 chữ số thập phân. Có rất nhiều hệ thống trong đó RAND_MAX nhỏ hơn 10 ^ 10. Điều này có nghĩa rằng một số con số trong phạm vi đó cóp(xxxxx,yyyyy)==0.0
MSalters

7
Bạn nên tránh hàm rand () nếu có thể. Xem câu trả lời khác cho giải pháp C ++ 11 hoặc TR1.
jfritz42

Không phải ai cũng sử dụng C ++ 0x, tr1 hoặc C ++ 11 Có tài liệu tham khảo nào cho thấy nên tránh sử dụng hàm rand () không? Đó là cách duy nhất để lấy số ngẫu nhiên trong nhiều thập kỷ.
rep_movsd

1
@ChamilaWijayarathna, Bạn cần bao gồm cstdlib
Veridian

101

Giải pháp này yêu cầu C ++ 11 (hoặc TR1).

#include <random>

int main()
{
   double lower_bound = 0;
   double upper_bound = 10000;
   std::uniform_real_distribution<double> unif(lower_bound,upper_bound);
   std::default_random_engine re;
   double a_random_double = unif(re);

   return 0;
}

Để biết thêm chi tiết, hãy xem "Tạo số ngẫu nhiên bằng C ++ TR1" của John D. Cook .

Xem thêm "Tạo số ngẫu nhiên" của Stroustrup .


7
Bạn có thể muốn cập nhật điều này bằng một tài liệu cppreference mới hơn , điều này khá tốt.
Shafik Yaghmour

10

Điều này phải hiệu quả, an toàn và đủ linh hoạt cho nhiều mục đích sử dụng:

#include <random>
#include <iostream>

template<typename Numeric, typename Generator = std::mt19937>
Numeric random(Numeric from, Numeric to)
{
    thread_local static Generator gen(std::random_device{}());

    using dist_type = typename std::conditional
    <
        std::is_integral<Numeric>::value
        , std::uniform_int_distribution<Numeric>
        , std::uniform_real_distribution<Numeric>
    >::type;

    thread_local static dist_type dist;

    return dist(gen, typename dist_type::param_type{from, to});
}

int main(int, char*[])
{
    for(auto i = 0U; i < 20; ++i)
        std::cout << random<double>(0.0, 0.3) << '\n';
}

7

Nếu độ chính xác là một vấn đề ở đây, bạn có thể tạo các số ngẫu nhiên với độ phân chia tốt hơn bằng cách ngẫu nhiên hóa các bit quan trọng. Giả sử chúng ta muốn có một nhân đôi giữa 0,0 và 1000,0.

Ví dụ trên MSVC (12 / Win32) RAND_MAX là 32767.

Nếu bạn sử dụng rand()/RAND_MAXsơ đồ chung, khoảng trống của bạn sẽ lớn bằng

1.0 / 32767.0 * ( 1000.0 - 0.0) = 0.0305 ...

Trong trường hợp IEE 754 biến kép (53 bit quan trọng) và ngẫu nhiên hóa 53 bit, khoảng cách ngẫu nhiên nhỏ nhất có thể có cho bài toán 0 đến 1000 sẽ là

2^-53 * (1000.0 - 0.0) = 1.110e-13

và do đó thấp hơn đáng kể.

Nhược điểm là cần 4 lệnh gọi rand () để nhận số tích phân ngẫu nhiên (giả sử RNG 15 bit).

double random_range (double const range_min, double const range_max)
{
  static unsigned long long const mant_mask53(9007199254740991);
  static double const i_to_d53(1.0/9007199254740992.0);
  unsigned long long const r( (unsigned long long(rand()) | (unsigned long long(rand()) << 15) | (unsigned long long(rand()) << 30) | (unsigned long long(rand()) << 45)) & mant_mask53 );
  return range_min + i_to_d53*double(r)*(range_max-range_min);
}

Nếu số bit cho phần định trị hoặc RNG là không xác định, các giá trị tương ứng cần được lấy trong hàm.

#include <limits>
using namespace std;
double random_range_p (double const range_min, double const range_max)
{
  static unsigned long long const num_mant_bits(numeric_limits<double>::digits), ll_one(1), 
    mant_limit(ll_one << num_mant_bits);
  static double const i_to_d(1.0/double(mant_limit));
  static size_t num_rand_calls, rng_bits;
  if (num_rand_calls == 0 || rng_bits == 0)
  {
    size_t const rand_max(RAND_MAX), one(1);
    while (rand_max > (one << rng_bits))
    {
      ++rng_bits;
    }
    num_rand_calls = size_t(ceil(double(num_mant_bits)/double(rng_bits)));
  }
  unsigned long long r(0);
  for (size_t i=0; i<num_rand_calls; ++i)
  {
    r |= (unsigned long long(rand()) << (i*rng_bits));
  }
  r = r & (mant_limit-ll_one);
  return range_min + i_to_d*double(r)*(range_max-range_min);
}

Lưu ý: Tôi không biết liệu số lượng bit cho dài dài không dấu (64 bit) có lớn hơn số bit định trị kép (53 bit cho IEE 754) trên tất cả các nền tảng hay không. Có lẽ sẽ là "thông minh" nếu bao gồm một chi phiếu như thế if (sizeof(unsigned long long)*8 > num_mant_bits) ...này nếu không phải như vậy.


3

Đoạn mã này là trực tiếp từ Ngôn ngữ lập trình C ++ của Stroustrup (Phiên bản thứ 4) , §40.7; nó yêu cầu C ++ 11:

#include <functional>
#include <random>

class Rand_double
{
public:
    Rand_double(double low, double high)
    :r(std::bind(std::uniform_real_distribution<>(low,high),std::default_random_engine())){}

    double operator()(){ return r(); }

private:
    std::function<double()> r;
};

#include <iostream>    
int main() {
    // create the random number generator:
    Rand_double rd{0,0.5};

    // print 10 random number between 0 and 0.5
    for (int i=0;i<10;++i){
        std::cout << rd() << ' ';
    }
    return 0;
}

0

một cái gì đó như thế này:

#include <iostream>
#include <time.h>

using namespace std;

int main()
{
    const long max_rand = 1000000L;
    double x1 = 12.33, x2 = 34.123, x;

    srandom(time(NULL));

    x = x1 + ( x2 - x1) * (random() % max_rand) / max_rand;

    cout << x1 << " <= " << x << " <= " << x2 << endl;

    return 0;
}

2
"(random ()% max_rand)" = "random ()" (tức là 3% 7 = 3). Đây sẽ là một bước xử lý lãng phí.
Zak
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.