Как создать случайный float в c ++ [duplicate]

Вот более простое решение, отлично работает в моем приложении.

  public class MyActivity extends Acitivity {

    TextView myTextView;
    boolean someCondition=true;

     @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.my_activity);

            myTextView = (TextView) findViewById(R.id.refreshing_field);

            //starting our task which update textview every 1000 ms
            new RefreshTask().execute();



        }

    //class which updates our textview every second

    class RefreshTask extends AsyncTask {

            @Override
            protected void onProgressUpdate(Object... values) {
                super.onProgressUpdate(values);
                String text = String.valueOf(System.currentTimeMillis());
                myTextView.setText(text);

            }

            @Override
            protected Object doInBackground(Object... params) {
                while(someCondition) {
                    try {
                        //sleep for 1s in background...
                        Thread.sleep(1000);
                        //and update textview in ui thread
                        publishProgress();
                    } catch (InterruptedException e) {
                        e.printStackTrace(); 

                };
                return null;
            }
        }
    }
225
задан John Dibling 28 June 2013 в 14:00
поделиться

14 ответов

rand() может использоваться для генерации псевдослучайных чисел в C ++. В сочетании с RAND_MAX и небольшой математикой вы можете генерировать случайные числа в любом произвольном интервале, который вы выберете. Этого достаточно для учебных целей и игрушечных программ. Если вам нужны действительно случайные числа с нормальным распределением, вам нужно будет использовать более продвинутый метод.


Это приведет к генерации числа от 0.0 до 1.0 включительно.

float r = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);

Это приведет к генерации числа от 0.0 до некоторого произвольного float, X:

float r2 = static_cast <float> (rand()) / (static_cast <float> (RAND_MAX/X));

. Это приведет к генерации числа от некоторого произвольного LO до некоторые произвольные HI:

float r3 = LO + static_cast <float> (rand()) /( static_cast <float> (RAND_MAX/(HI-LO)));

Обратите внимание, что функция rand() часто бывает недостаточной, если вам нужны действительно случайные числа.


Перед вызовом rand(), вы должны сначала «засеять» генератор случайных чисел, вызвав srand(). Это нужно делать один раз во время запуска вашей программы - не каждый раз, когда вы вызываете rand(). Это часто делается следующим образом:

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

Для вызова rand или srand вы должны #include <cstdlib>.

Чтобы позвонить time, вы должен #include <ctime>.

322
ответ дан Florin Mircea 20 August 2018 в 21:16
поделиться
  • 1
    Не забудьте сначала семена! – Klaim 26 March 2009 в 17:18
  • 2
    Лучше всего отметить, что оба ограничения являются всеобъемлющими. – dmckee 26 March 2009 в 17:52
  • 3
    Этот ответ вводит в заблуждение. На прошлой неделе он был включен в Going Native 2013; rand () Считается вредным, channel9.msdn.com/Events/GoingNative/2013/… для очень подробного объяснения. – Ade Miller 8 September 2013 в 01:13
  • 4
    Я не понимаю, почему так много людей поддержали этот ответ. Это математически неверно. RAND_MAX - очень небольшое число (обычно 2 ^ 16). Это означает, что из 23 бит с плавающей запятой вы делаете только 15 случайных. Остальные будут, вероятно, равны нулю. Вы действительно получите случайные числа в равномерном распределении, но с низкой точностью. Например, ваш случайный генератор может генерировать 0,00001 и 0,00002, но не может генерировать 0,000017. Таким образом, у вас есть равномерное распределение, но с низкой точностью (в 256 раз меньше точности, чем фактическая плавающая точка). – DanielHsH 14 August 2014 в 09:25
  • 5
    @DanielHsH: OP специально спросил, какие механики можно использовать для генерации случайных поплавков с помощью rand(). Этот вопрос и мой ответ были специально сосредоточены на изучении основ и не были связаны с высокой степенью точности. Вы должны научиться ходить, прежде чем научиться бегать. – John Dibling 14 August 2014 в 13:22

В современных c++ вы можете использовать заголовок <random> , который появился с c++11. Чтобы получить случайные float, вы можете использовать std::uniform_real_distribution<>.

Вы можете использовать функцию для генерации чисел, и если вы не хотите, чтобы числа были одинаковыми все время, установите двигатель и распределение будут static. Пример:

float get_random()
{
    static std::default_random_engine e;
    static std::uniform_real_distribution<> dis(0, 1); // rage 0 - 1
    return dis(e);
}

Идеально разместить float в контейнере, таком как std::vector:

int main()
{
    std::vector<float> nums;
    for (int i{}; i != 5; ++i) // Generate 5 random floats
        nums.emplace_back(get_random());

    for (const auto& i : nums) std::cout << i << " ";
}

Пример вывода:

0.0518757 0.969106 0.0985112 0.0895674 0.895542
13
ответ дан Andreas DM 20 August 2018 в 21:16
поделиться

Полностью случайное действительное число с плавающей точкой генерируется следующим образом: случайный знак, случайный показатель и случайная мантисса. Ниже приведен пример генерации случайных чисел из 0..MAXFLOAT с равномерным распределением:

static float frand(){
    float f;
    UINT32 *fi = (UINT32*)&f;
    *fi = 0;
    const int minBitsRandGives  = (1<<15);          //  RAND_MAX is at least (1<<15)    
    UINT32 randExp              = (rand()%254)+1;   //  Exponents are in range of [1..254]
    UINT32 randMantissa         = ((rand() % minBitsRandGives) << 8) | (rand()%256);
    *fi                         = randMantissa | (randExp<<23);                 // Build a float with random exponent and random mantissa
    return f;
}

Важное примечание: RAND_MAX по умолчанию равно 2 ^ 16 (в 32 битовых системах), поэтому rand () может генерировать не более 15 случайных бит. Поскольку с плавающей запятой имеется всего 32 бита, мы должны активировать rand () не менее 3 раз для генерации случайных 32 бит. Я использовал 8 бит rand () для генерации Exponent и еще 2 вызова rand () для генерации 23 бит мантиссы.

Общая ошибка, которой следует избегать: если вы используете (float)rand()/MAX_RAND для получения плавающей запятой в range [0..1], вы все равно получите случайные числа в равномерном распределении, но с низкой точностью. Например, ваш случайный генератор может генерировать 0,00001 и 0,00002, но не может генерировать 0,000017. Такое случайное число в 256 раз меньше, чем фактическое представление с плавающей запятой.

Оптимизация. Моя функция не оптимизирована для скорости. Вы можете улучшить его, заменив разделение «%» на побитовые логические операции. Например, вместо %256 используйте &0xFF

-3
ответ дан DanielHsH 20 August 2018 в 21:16
поделиться
  • 1
    Вы создали единый случайный битовый шаблон, но для float, который не совпадает с равномерным распределением. Сделайте гистограмму и посмотрите. – Mark Ransom 19 March 2015 в 22:28
  • 2
    Марк, ты прав. Но 1. вопрос не указывал на равномерное распределение. Это естественное распределение для целых чисел, но неправильное распределение для поплавков. 2. Невозможно создать равномерное распределение для поплавков. Поскольку точность поплавка составляет примерно 1/10 миллион, он может представлять собой точные фракции только для небольшого числа. Но для чисел более 10 милей он может представлять только целые числа (физически он не может представлять число 10 000 000,25). Для больших чисел он даже не может представлять все целые числа. – DanielHsH 24 March 2015 в 20:05
  • 3
    Например: нет точного представления float для целого числа 100 000,017. По определению диапазон плавающей запятой неравномерен (иначе это была бы фиксированная точка). Фактически его распределение логарифмическое. Поэтому каждый случайный генератор не будет иметь равномерного распределения по действительным числам. Фактически, мой случайный случай является истинным правильным распределением, потому что он «равномерен по представленному диапазону с плавающей запятой». То есть - плавающая точка может представлять 2 ^ 32 разных дробных числа. Мое случайное дает каждому шанс 1/2 ^ 32. Это истинная однородность – DanielHsH 24 March 2015 в 20:11
  • 4
    Что касается вашего предложения о гистограммах - вы не понимаете единообразия диапазона с плавающей запятой. Если вы выполните гистограмму моего rand (), вы увидите экспоненциальную функцию уменьшения. Это точно равномерность для плавающих точек (он может представлять собой множество различных мелких фракций, но только несколько долей больших чисел). – DanielHsH 24 March 2015 в 20:16
  • 5
    Единственное ожидание float для представления равномерного распределения - использовать константный показатель и обрабатывать float как фиксированную точку 23 бит. Это то, что на самом деле делает большинство других ответов в этой теме. Это не случайное float, а скорее случайное целое число между 0..2 ^ 22, деленное на 2 ^ 22, чтобы получить диапазон [0..1]. Для этого вам не нужны плавающие точки вообще – DanielHsH 24 March 2015 в 20:26

До сих пор я не был удовлетворен ни одним из ответов, поэтому написал новую функцию случайного поплавка. Он делает побитовые предположения о типе данных float. Ему по-прежнему нужна функция rand () с не менее 15 случайными битами.

//Returns a random number in the range [0.0f, 1.0f).  Every
//bit of the mantissa is randomized.
float rnd(void){
  //Generate a random number in the range [0.5f, 1.0f).
  unsigned int ret = 0x3F000000 | (0x7FFFFF & ((rand() << 8) ^ rand()));
  unsigned short coinFlips;

  //If the coin is tails, return the number, otherwise
  //divide the random number by two by decrementing the
  //exponent and keep going. The exponent starts at 63.
  //Each loop represents 15 random bits, a.k.a. 'coin flips'.
  #define RND_INNER_LOOP() \
    if( coinFlips & 1 ) break; \
    coinFlips >>= 1; \
    ret -= 0x800000
  for(;;){
    coinFlips = rand();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    //At this point, the exponent is 60, 45, 30, 15, or 0.
    //If the exponent is 0, then the number equals 0.0f.
    if( ! (ret & 0x3F800000) ) return 0.0f;
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
    RND_INNER_LOOP(); RND_INNER_LOOP(); RND_INNER_LOOP();
  }
  return *((float *)(&ret));
}
2
ответ дан iNFiNiTyLoOp 20 August 2018 в 21:16
поделиться
  • 1
    интересный подход, я бы хотел поддержать, но я действительно не понимаю, что происходит – hasen 5 December 2009 в 04:56

drand48(3) является стандартным способом POSIX. GLibC также предоставляет реентерабельную версию, drand48_r(3) .

Функция была объявлена ​​устаревшей в SVID 3, но адекватная альтернатива не была предоставлена, поэтому IEEE Std 1003.1-2013 по-прежнему включает в себя и не имеет никаких заметок о том, что в любом случае это произойдет в ближайшее время.

В Windows стандартным способом является CryptGenRandom () .

4
ответ дан ivan_pozdeev 20 August 2018 в 21:16
поделиться

rand () возвращает int между 0 и RAND_MAX. Чтобы получить случайное число между 0.0 и 1.0, сначала введите int return by rand () в float, а затем разделите на RAND_MAX.

0
ответ дан James Curran 20 August 2018 в 21:16
поделиться

На некоторых системах (в настоящее время Windows с VC наводит на мысль,] RAND_MAX смехотворно мала, i. е. всего 15 бит. При делении на RAND_MAX вы генерируете мантиссону из 15 бит вместо 23 возможных бит. Это может быть или не быть проблемой для вас, но в этом случае вы упускаете некоторые значения.

О, только что заметил, что для этой проблемы уже есть комментарий. В любом случае, вот какой код, который может решить это для вас:

float r = (float)((rand() << 15 + rand()) & ((1 << 24) - 1)) / (1 << 24);

Не проиндексирован, но может работать: -)

5
ответ дан Joey 20 August 2018 в 21:16
поделиться
  • 1
    Что относительно float r = (float) ((rand () & lt; 9) | rand ()) / RAND_MAX? (также непроверенный) – Trap 26 March 2009 в 18:44
  • 2
    Арг, извините, деление на RAND_MAX не приведет вас никуда ... Вся суть этого трюка состояла в том, чтобы иметь что-то большее, чем RAND_MAX ... исправил это и для меня. – Joey 27 March 2009 в 09:07
  • 3
    Будьте осторожны с составлением случайных чисел без теории ... последовательные вызовы rand () могут быть не полностью независимыми. Подсказка: если это линейный конгруэнтный генератор, наблюдайте низкий бит при последовательных вызовах: он чередуется между 0 и 1. – RBerteig 27 March 2009 в 09:14
  • 4
    Я знаю. Однако для некоторых приложений этого может быть достаточно. Но да, вы должны, вероятно, использовать больше, чем просто два вызова в этом случае. В этом случае нет серебряной пули, вы даже не можете полагаться на нее как на LCG. Другие PRNG имеют слабые высокие бит. Решение Boost должно быть лучшим здесь. – Joey 27 March 2009 в 09:46
  • 5
    (nb: младший бит, возвращаемый rand в MSVC, не является самым младшим разрядом состояния RNG. Для 100 вызовов rand () я получаю следующее: 110010000011111110101000010011010111111100100000000010100011011000000100010101010101. Java использует 48-битный LCG и использует только 32 бита, VC кажется сделать это аналогичным образом) – Joey 27 March 2009 в 09:51

Если вы знаете, что ваш формат с плавающей запятой - IEEE 754 (почти все современные процессоры, включая Intel и ARM), то вы можете построить случайное число с плавающей запятой из случайного целого с использованием битовых методов. Это следует учитывать только в том случае, если у вас нет доступа к C ++ 11 random или Boost.Random , которые намного лучше.

float rand_float()
{
    // returns a random value in the range [0.0-1.0)

    // start with a bit pattern equating to 1.0
    uint32_t pattern = 0x3f800000;

    // get 23 bits of random integer
    uint32_t random23 = 0x7fffff & (rand() << 8 ^ rand());

    // replace the mantissa, resulting in a number [1.0-2.0)
    pattern |= random23;

    // convert from int to float without undefined behavior
    assert(sizeof(float) == sizeof(uint32_t));
    char buffer[sizeof(float)];
    memcpy(buffer, &pattern, sizeof(float));
    float f;
    memcpy(&f, buffer, sizeof(float));

    return f - 1.0;
}

Это даст лучшее распределение, чем использование деления.

2
ответ дан Mark Ransom 20 August 2018 в 21:16
поделиться
  • 1
    Я не уверен, почему вы говорите, что это даст «лучшее распределение». Фактически, это даст точно такое же распределение , как только return (float)random23 / (1 << 23). (Да, я просто проверил это , изменив вашу функцию, чтобы принять random32 в качестве параметра и запустить его для всех значений от нуля до (1 << 23)-1. И да, ваш метод действительно дает точно те же результаты, что и деление на 1 << 23.) – Ilmari Karonen 3 January 2016 в 17:19

Если вы используете C ++, а не C, помните, что в техническом отчете 1 (TR1) и в проекте C ++ 0x они добавили возможности для генератора случайных чисел в заголовочном файле, я считаю, что он идентичен библиотека Boost.Random и определенно более гибкая и «современная», чем функция библиотеки C, rand.

Этот синтаксис предлагает возможность выбора генератора (например, mersenne twister mt19937 ), а затем выберите распределение (normal, bernoulli, binomial и т. д.).

Синтаксис выглядит следующим образом (бесстыдно заимствовано из этого сайта ):

  #include <iostream>
  #include <random>

  ...

  std::tr1::mt19937 eng;  // a core engine class 
  std::tr1::normal_distribution<float> dist;     

  for (int i = 0; i < 10; ++i)        
      std::cout << dist(eng) << std::endl;
19
ответ дан Rick 20 August 2018 в 21:16
поделиться
  • 1
    Это теперь в C ++ 11, также dist инициализируется с минимальными и максимальными значениями. – Étienne 6 June 2015 в 16:11

Взгляните на Boost.Random . Вы можете сделать что-то вроде этого:

float gen_random_float(float min, float max)
{
    boost::mt19937 rng;
    boost::uniform_real<float> u(min, max);
    boost::variate_generator<boost::mt19937&, boost::uniform_real<float> > gen(rng, u);
    return gen();
}

Поиграйте, вы можете лучше пройти один и тот же объект mt19937, а не конструировать новый каждый раз, но, надеюсь, вы получите эту идею.

60
ответ дан rlbond 20 August 2018 в 21:16
поделиться
  • 1
    uniform_real использует полуоткрытый интервал [min, max), что означает, что вы получите минимальное значение, но никогда не достигнете максимального значения. Это то, что нужно учитывать, хотя, если вы каким-то образом обходитесь, вы можете преодолеть эту проблему. – Wolf 17 June 2011 в 18:09
  • 2
    Теперь это часть C ++ 11. – Tomas Andrle 26 November 2011 в 22:23
  • 3
    @Wolf в практических приложениях вероятность попадания какого-либо определенного значения с плавающей запятой настолько мала, что не имеет значения, включена ли конечная точка или исключена ли она. Если вам нужно max, но вы можете использовать открытый min, вы можете легко изменить интервал: return min + max - gen();. – Mark Ransom 19 March 2015 в 22:22

Для C ++ он может генерировать реальные числа с плавающей запятой в пределах диапазона, указанного переменной dist

#include <random>  //If it doesnt work then use   #include <tr1/random>
#include <iostream>

using namespace std;

typedef std::tr1::ranlux64_base_01 Myeng; 
typedef std::tr1::normal_distribution<double> Mydist;

int main() { 
       Myeng eng; 
       eng.seed((unsigned int) time(NULL)); //initializing generator to January 1, 1970);
       Mydist dist(1,10); 

       dist.reset(); // discard any cached values 
       for (int i = 0; i < 10; i++)
       {
           std::cout << "a random value == " << (int)dist(eng) << std::endl; 
       }

       return (0);
}
102
ответ дан Shafik Yaghmour 20 August 2018 в 21:16
поделиться
  • 1
    Вы только что скопировали и ввели код из этого ответа? stackoverflow.com/a/1118739/1538531 – Derek 13 November 2013 в 19:39
  • 2
    На самом деле нет. Я немного удивлен, увидев, как они выглядят одинаково! Но я инициализировал генератор-генератор 1 января 1970 года. – Marco167 14 November 2013 в 16:35
  • 3
    Справедливо. Я заметил, что вы инициализировали генератор до эпохи, но чертовски этот код похож! – Derek 14 November 2013 в 17:11
  • 4
    Мне немного странно давать пример TR1, можете ли вы объяснить, в каких случаях кому-то придется использовать TR1, а не C ++ 11? – Shafik Yaghmour 25 August 2014 в 02:46
  • 5
    можете ли вы исправить свои randMToN PLS? либо отметьте, что это [M,N] или добавьте + 1. из выше randZeroToOne. - & GT; подумайте, чтобы называть это следующим образом: randMToN(0.0, 1.0); – BeyelerStudios 1 April 2016 в 07:51
  • 6
    Также будьте осторожны с делением на ноль в (N-M). Хороший способ справиться с этой ошибкой можно найти здесь: stackoverflow.com/questions/33058848/… – Dr Beco 26 May 2018 в 04:42

На мой взгляд, вышеупомянутый ответ действительно дает некоторый «случайный» float, но ни один из них не является поистине случайным поплавком (т. е. они пропускают часть представления float). Прежде чем я буду спешить с моей реализацией, сначала рассмотрим стандартный формат ANSI / IEEE для float:

| sign (1-bit) | e (8 бит) | f (23-бит) |

число, представленное этим словом, равно (-1 * sign) * 2 ^ e * 1.f

отметить, что число «e» равно (с смещением 127), таким образом, варьируя от -127 до 126. Самая простая (и фактически самая случайная) функция состоит в том, чтобы просто записать данные случайного int в поплавок, таким образом

int tmp = rand();
float f = (float)*((float*)&tmp);

обратите внимание, что если вы сделаете float f = (float)rand();, он преобразует целое число в float (таким образом, 10 станет 10.0). Итак, если вы хотите ограничить максимальное значение, вы можете сделать что-то вроде (не уверен, что это работает)

int tmp = rand();
float f = *((float*)&tmp);
tmp = (unsigned int)f       // note float to int conversion!
tmp %= max_number;
f -= tmp;

, но если вы посмотрите на структуру поплавка, вы увидите, что максимальное значение float (приблизительно) 2 ^ 127, который больше, чем максимальное значение int (2 ^ 32), таким образом исключая значительную часть чисел, которые могут быть представлены поплавком. Это моя окончательная реализация:

/**
 * Function generates a random float using the upper_bound float to determine 
 * the upper bound for the exponent and for the fractional part.
 * @param min_exp sets the minimum number (closest to 0) to 1 * e^min_exp (min -127)
 * @param max_exp sets the maximum number to 2 * e^max_exp (max 126)
 * @param sign_flag if sign_flag = 0 the random number is always positive, if 
 *              sign_flag = 1 then the sign bit is random as well
 * @return a random float
 */
float randf(int min_exp, int max_exp, char sign_flag) {
    assert(min_exp <= max_exp);

    int min_exp_mod = min_exp + 126;

    int sign_mod = sign_flag + 1;
    int frac_mod = (1 << 23);

    int s = rand() % sign_mod;  // note x % 1 = 0
    int e = (rand() % max_exp) + min_exp_mod;
    int f = rand() % frac_mod;

    int tmp = (s << 31) | (e << 23) | f;

    float r = (float)*((float*)(&tmp));

    /** uncomment if you want to see the structure of the float. */
//    printf("%x, %x, %x, %x, %f\n", (s << 31), (e << 23), f, tmp, r);

    return r;
}

с использованием этой функции randf(0, 8, 0) вернет случайное число между 0.0 и 255.0

2
ответ дан user2546926 20 August 2018 в 21:16
поделиться
  • 1
    у вас есть ошибка. и ()% frac_mod не будет работать, поскольку MAX_RAND обычно ниже, чем (1 & lt; 23). – DanielHsH 10 July 2013 в 09:45
  • 2
    Я должен признать, что я не знаю точный размер MAX_RAND. Тем не менее, это все равно будет работать, возможно, это бесполезное заявление, но оно все равно будет работать. 8% 10 = 8, так что это нормально, но если MAX_RAND всегда меньше, то (1 & lt; 23) вы действительно можете удалить его. – user2546926 16 July 2013 в 20:34
  • 3
    Нет, ты немного не прав. RandMax обычно составляет ~ 65 000. Это означает, что из 23 бит вы делаете только 15 случайных. Остальные будут, вероятно, равны нулю. Вы действительно получите случайные числа, но с низкой точностью. Например, ваш случайный генератор может генерировать 0.001 и 0.002, но не может генерировать 0.0017. Таким образом, у вас есть равномерное распределение, но с низкой точностью (в 256 раз меньше точности, чем поплавок). – DanielHsH 17 July 2013 в 08:37
  • 4
    В этом ответе есть две ошибки. Фиксация диапазона экспонентов: int e = (rand() % (max_exp - min_exp)) + min_exp_mod; и мантиссы: int f = (int)(frac_mod * (float)rand() / RAND_MAX); заменяют их соответствующие строки выше. Обратите внимание, что ошибка мантиссы важна: для RAND_MAX меньше 1 << 23 вы только рандомизировали младшие значащие биты и получали 0s для самых значительных бит все время! – BeyelerStudios 1 April 2016 в 08:42

Вызвать код с двумя значениями float, код работает в любом диапазоне.

float rand_FloatRange(float a, float b)
{
    return ((b - a) * ((float)rand() / RAND_MAX)) + a;
}
21
ответ дан Ziezi 20 August 2018 в 21:16
поделиться
  • 1
    Возможно, стоит упомянуть, что это потенциальный прецедент для fmaf() (или перегрузка float fma() в C ++) на C99 или C ++ 11, что может сохранить более высокую точность. Как и в fmaf((float)rand() / RAND_MAX, b - a, a). – Tim Čas 9 August 2017 в 01:14
108
ответ дан Shafik Yaghmour 31 October 2018 в 16:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: