C나 C++에서는 float 타입의 난수를 직접 생성할 수 없습니다. 대신 약간의 트릭을 사용해야 하는데, 가장 일반적인 방법은 두 개의 난수 정수값을 만든 후 이를 나누어 부동 소수점 값을 얻는 것입니다.
이때 나눗셈 결과가 정수(몫)가 되는 경우가 간혹 발생할 수 있습니다. 이러한 가능성을 줄이기 위해 결과에 0.5 같은 부동 소수점 상수를 곱해 주기도 합니다.
기본 구현 예제
아래 예제는 rand() 함수가 반환하는 최대값인 RAND_MAX로 나누어 0.0 ~ 1.0 사이의 실수를 만들고, 여기에 원하는 범위의 최대값(5.0)을 곱하는 방식입니다.
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main() {
srand((unsigned int)time(NULL));
float a = 5.0;
for (int i = 0; i < 20; i++)
cout << (float(rand()) / float(RAND_MAX)) * a << endl;
}실행 결과
2.07648 4.3115 1.31092 2.22465 2.17292 1.48381 1.91137 0.56505 2.24326 4.44517 3.1695 2.39067 1.89062 4.35881 4.17524 0.189673 1.87521 1.76916 2.3217 2.20481
C++11 이상에서 권장되는 방식
rand() 함수는 난수의 품질과 범위 면에서 한계가 있으므로, C++11부터 도입된 <random> 헤더를 사용하는 것이 더 좋습니다. 아래처럼 작성하면 더 균일하게 분포된 실수 난수를 얻을 수 있습니다.
#include <iostream>
#include <random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_real_distribution<float> dist(0.0f, 5.0f);
for (int i = 0; i < 20; i++)
std::cout << dist(gen) << '\n';
}정리하면, 전통적인 방식은 rand()를 RAND_MAX로 나누어 정규화한 뒤 원하는 범위를 곱하는 것이며, 현대 C++에서는 std::uniform_real_distribution을 활용하는 것이 안전하고 권장되는 방법입니다.