HOWTO · C++

Genera un numero float casuale in C++

In questo articolo viene illustrato come generare un numero float casuale in C++

In questa pagina

Usa la libreria <random> di C++11 per generare un valore a virgola mobile pseudocasuale in un intervallo a scelta. std::uniform_real_distribution accetta i limiti inferiore e superiore, mentre un motore casuale fornisce la sequenza. Scegli float o double in base alla precisione richiesta dall’applicazione; usa rand solo per mantenere codice legacy.

Generare un valore a virgola mobile casuale con C++11

Questo programma completo genera cinque valori nell’intervallo semiaperto [10, 100). Il seed fisso rende ripetibile la sequenza del motore con la stessa implementazione della libreria standard, una caratteristica utile durante il debug. I valori stampati esatti possono variare tra implementazioni, perché l’algoritmo della distribuzione non è specificato in modo da garantire una sequenza portabile.

Esegui questo esempio:

#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

L’argomento template della distribuzione determina il tipo del risultato. Il valore predefinito è double; i tipi supportati dallo standard sono float, double e long double. Scegline uno esplicitamente, così il tipo è chiaro nel punto in cui viene usata la distribuzione: l’esempio usa double, mentre std::uniform_real_distribution<float> richiede valori float. I limiti sono numeri reali e la distribuzione esclude il limite superiore. Questo intervallo semiaperto è utile quando si scalano valori in intervalli in cui includere l’estremo superiore causerebbe una sovrapposizione con la fascia successiva. Per esempio, un intervallo da 0.0 a 1.0 può rappresentare una proporzione normalizzata, mentre uno da 10.0 a 100.0 può rappresentare una misura espressa nelle unità scelte.

Usa float quando la sua precisione è sufficiente e sono importanti lo spazio di archiviazione o la larghezza di banda; scegli double per il consueto equilibrio tra precisione e intervallo di valori. long double è disponibile quando serve una precisione maggiore, anche se l’incremento effettivo dipende dall’implementazione. Quando possibile, mantieni i valori dei limiti coerenti con il tipo della distribuzione, soprattutto se ne cambi l’argomento template: così l’intervallo desiderato è più facile da verificare. Anche con un seed fisso per il motore, la distribuzione non garantisce la stessa sequenza stampata tra diverse implementazioni della libreria standard.

Mantieni attivo il motore e riutilizzalo per generare una sequenza. Creare ogni volta un nuovo motore con un nuovo seed può riavviare o peggiorare la sequenza. Per risultati ripetibili, usa un valore fisso come nell’esempio. Per ottenere una sequenza diversa a ogni esecuzione, std::random_device può fornire materiale per il seed se l’implementazione supporta un output non deterministico; questo comportamento non è garantito su tutti i sistemi. Nessuno dei due approcci rende questo generatore pseudocasuale di uso generale adatto a valori sensibili per la sicurezza. Un seed inizializza il motore una volta: non serve a creare un nuovo motore indipendente per ogni estrazione. Se l’applicazione deve produrre risultati ripetibili tra esecuzioni, registra il seed insieme agli altri input. Per generare token sensibili per la sicurezza, usa una sorgente casuale crittografica anziché questa distribuzione e questo motore.

Usare rand come alternativa legacy limitata

La funzione rand() della libreria C restituisce un intero pseudocasuale compreso tra 0 e RAND_MAX, estremi inclusi; RAND_MAX dipende dall’implementazione. Per convertirlo in un intervallo a virgola mobile, dividi per RAND_MAX usando l’aritmetica in virgola mobile prima di applicare la scala. Questo esempio produce valori nell’intervallo [10, 100], compreso l’estremo superiore quando rand() restituisce 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() offre uno stato e una qualità statistica limitati. Un seed fisso rende questo esempio ripetibile con la stessa implementazione della libreria C, ma non lo rende imprevedibile o sicuro. Per il nuovo codice C++, preferisci <random>: separa il motore dalla distribuzione e consente di scegliere direttamente il tipo del risultato e l’intervallo.