HOWTO · C++

如何在 C++ 中生成一個隨機浮點數

本文演示瞭如何在 C++ 中生成一個隨機的浮點數。

本頁內容

使用 C++11 的 <random> 程式庫,在指定範圍內產生偽隨機浮點數。std::uniform_real_distribution 接受上下界,隨機引擎則提供數值序列。請依應用程式所需的精度選用 float 或 double;只有在維護舊程式碼時才使用 rand。

使用 C++11 產生隨機浮點數

這個完整程式會在半開區間 [10, 100) 內產生五個值。固定種子會讓引擎在相同標準程式庫實作下產生可重複的序列,方便除錯。由於標準並未規定分佈演算法必須產生跨實作可攜的序列,因此不同實作列印出的確切數值可能不同。

執行此範例。輸出區塊只包含數值,沒有英文標籤;程式碼和輸出區塊維持與原文逐位元組相同。

#include <iomanip>
#include <iostream>
#include <random>

int main() {
  std::mt19937 engine(2026);
  std::uniform_real_distribution<double> distribution(10.0, 100.0);

  for (int i = 0; i < 5; ++i) {
    std::cout << std::setprecision(10) << distribution(engine) << '\n';
  }
}
78.99481399
96.50696843
96.65823206
73.63312607
11.77415091

分佈的樣板引數會決定結果型別。預設型別是 double;標準支援的選項有 float、double 和 long double。請明確指定型別,讓呼叫位置一目了然;此範例使用 double,而 std::uniform_real_distribution<float> 則會要求產生 float 值。上下界是實數,且分佈不會包含上界。半開區間適合用來縮放數值,避免剛好等於上界的值落入下一個區間。例如,0.0 到 1.0 的範圍可表示正規化比例,而 10.0 到 100.0 的範圍可表示以指定單位表示的測量值。

若 float 的精度已足夠,且儲存空間或頻寬很重要,就使用 float;一般情況下,double 在精度與範圍之間較為均衡。若需要更高精度,也可以使用 long double,但額外精度的多寡取決於實作。實際可行時,請讓界限值與分佈型別一致;尤其是更改樣板引數時,這樣更容易檢查預期範圍。即使引擎種子固定,分佈也不保證不同標準程式庫實作會產生相同的列印序列。

產生一連串數值時,請讓引擎保持存活並重複使用。每次產生數值都重新建立並設定種子的引擎,可能會重啟或降低序列品質。若要重複取得相同結果,請像範例一樣使用固定值作為種子。若希望每次執行都得到不同序列,當實作支援非決定性輸出時,std::random_device 可提供種子材料;但並非每個系統都保證具有這項行為。這兩種方式都無法讓這種通用偽隨機產生器適用於安全敏感的值。種子只會初始化引擎一次,並不代表每次抽取都要建立新的獨立引擎。若應用程式需要在不同執行之間重現結果,請連同其他輸入一起記錄種子。若需要安全敏感的權杖,請改用密碼學隨機來源,而非此分佈與引擎。

將 rand 用作有限的舊式替代方案

C 標準程式庫的 rand() 會回傳介於 0 與實作所決定的 RAND_MAX 之間的偽隨機整數,且包含兩端。若要將它映射到浮點數範圍,請先使用浮點數運算除以 RAND_MAX,再進行縮放。此範例映射至 [10, 100];當 rand() 回傳 RAND_MAX 時,也會包含上界:

#include <cstdlib>
#include <iostream>

int main() {
  const double lower = 10.0;
  const double upper = 100.0;
  std::srand(2026);

  for (int i = 0; i < 5; ++i) {
    const double value = lower + (upper - lower) *
        (static_cast<double>(std::rand()) / RAND_MAX);
    std::cout << value << '\n';
  }
}
60.2772
88.4741
67.8989
11.5099
83.7273

rand() 的狀態有限,統計品質也有限;固定種子會讓此範例在相同 C 程式庫實作下產生可重複的結果,但不會讓結果變得不可預測或安全。撰寫新的 C++ 程式碼時,請優先使用 <random>,因為它將引擎與分佈分開,並可直接選擇結果型別和範圍。