Рандомизация вещественных чисел

Доброго времени суток всем!!!

Есть у меня небольшая программка, которая должна заполнять массив случайными вещественными числами и каждое число округлять до точности ближайшего целого, десятых, сотых и тысячных долей после запятой и вывести это все в виде таблицы.

#include <iostream>
#include <cstdlib>
#include <iomanip>
#include <cmath>

using namespace std;

// round to nearest integer
double roundToInteger(double val)
{
    return floor( val + 0.5 );
}   // end roundToInteger

// rount to tenths
double roundToTenths(double val)
{
    return floor( val * 10 + 0.5 ) / 10;
}   // end roundToTenths

// round to hundredths
double roundToHundredths(double val)
{
    return floor( val * 100 + 0.5 ) / 100;
}   // end roundToHundredths

// round to hundredths
double roundToThouthandths(double val)
{
    return floor( val * 1000 + 0.5 ) / 1000;
}   // end roundToThouthandths

const int ARSIZE = 10;

int main()
{
    double min = -2;
    double max = 2;

    double arr[::ARSIZE];

    srand(static_cast<unsigned int>(time(0)));

    cout << setw(10) << right << "Value"
        << setw(10) << right << "Integer"
        << setw(10) << right << "Tenths"
        << setw(10) << right << "Hundred"
        << setw(10) << right << "Thouzand" << "\n\n";

    for (int i = 0; i < ::ARSIZE; i++){
        arr[i] = min + (max - min) / RAND_MAX * rand();

        cout << setw(10) << right << arr[i]
            << setw(10) << right << roundToInteger(arr[i])
            << setw(10) << right << roundToTenths(arr[i])
            << setw(10) << right << roundToHundredths(arr[i])
            << setw(10) << right << roundToThouthandths(arr[i]) << '\n';
    }

    // проверка

/*  double val;
    long long counter = 0;

    do{
        counter++;
        val = min + (max - min) / RAND_MAX * rand();
        cout << setw(10) << val << setw(10) << counter << '\n';
    }while (val != min);
*/
    return 0;
}

Вопрос в следующем, при каждом запуске программы первое число всегда имеет приблизительно одно и тоже значение, в отличие от остальных. В ЧЕМ ЗАКЛЮЧАЕТСЯ ПРОБЛЕМА?

PS Если изменить цикл for так, т.е. первое присвоение сделать в холостую, то работает все нормально.

for (int i = 0; i < ::ARSIZE; i++){

        if (0 == i)
            arr[i] = min + (max - min) / RAND_MAX * rand();

        arr[i] = min + (max - min) / RAND_MAX * rand();

        cout << setw(10) << right << arr[i]
            << setw(10) << right << roundToInteger(arr[i])
            << setw(10) << right << roundToTenths(arr[i])
            << setw(10) << right << roundToHundredths(arr[i])
            << setw(10) << right << roundToThouthandths(arr[i]) << '\n';
}

Ничего удивительного. Ты разгоняешь ГСЧ текущим временем. Если вставить кусочек:

    unsigned int tm = static_cast<unsigned int>(time(NULL));
    srand(tm);
    cout << tm << endl;

то ты увидишь, что «начальное значение» от запуска к запуску изменяется весьма незначительно. Отсюда и «первое число всегда имеет приблизительно одно и тоже значение».

Если для тебя это критично, то после srand() можно дополнительно разогнать ГСЧ в цикле. Или использовать более продвинутый генератор. (Посмотри в STL C++11 там что-то есть на эту тему).

Кстати, меня удивило семейство функций вида

double roundToHundredths(double val)
{
    return floor( val * 100 + 0.5 ) / 100;
}   // end roundToHundredths

По-моему элегантнее будет написать одну функцию:

double roundToPrecision(double val, int prec)
{
    return floor( val * prec + 0.5 ) / prec;
}   // end roundToPrecision

или так:

double roundToPrecision(double val, unsigned int prec)
{
    const double factors[1.0, 10.0, 100.0, 1000.0];
    if (prec > 3)
        prec = 3;
    return floor( val * factors[prec] + 0.5 ) / factors[prec];
}   // end roundToPrecision

Не?

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.