【问题标题】:C++ How I can get random value from 1 to 12? [duplicate]C++ 如何获得从 1 到 12 的随机值? [复制]
【发布时间】:2011-01-16 07:19:08
【问题描述】:

如何获得从 1 到 12 的 C++ 随机值?

所以我会有 3 个、6 个还是 11 个?

【问题讨论】:

  • 有没有其他人认为int Random(){ return 4; /*Guaranteed random -- Determined by dice roll */ }
  • 我确实认为解释性说明既多余又增加了歧义;在 1 到 12 之间还有其他值(实际上是无限数)
  • 我需要在 3 之前有一个零,或者在某些应用程序中自动填写 4,所以我需要输入 day: 01 而不是 1,并且在月份 - 08 而不是 8
  • 啊,所以你只需要将这些生成的数字转换成2位固定宽度的数字(作为字符串)?
  • 哎呀。值的格式与值无关。生成它们后,您可以以任何您想要的方式格式化它们。

标签: c++ random


【解决方案1】:

在这种情况下,前导零有什么意义吗?您是否打算将其设为八进制,所以 12 真的是 10(以 10 为底)?

获取指定范围内的随机数相当简单:

int rand_lim(int limit) {
/* return a random number between 0 and limit inclusive.
 */

    int divisor = RAND_MAX/(limit+1);
    int retval;

    do { 
        retval = rand() / divisor;
    } while (retval > limit);

    return retval;
}

(while 循环是为了防止结果出现偏差——某些输出比其他输出更频繁地发生)。当/如果您直接使用除法(或其余数)时,倾斜的结果几乎是不可避免的。

如果您想打印出来,即使是一位数字也显示两位数(即前导 0),您可以执行以下操作:

std::cout << std::setw(2) << std::setprecision(2) << std::setfill('0') << number;

编辑:至于为什么这样做,以及为什么需要一个 while 循环(或类似的东西),请考虑一个非常有限的生成器版本,它只生成从 0 到 9 的数字。进一步假设我们想要数字在0到2的范围内。我们基本上可以将数字排列在一个表格中:

0 1 2
3 4 5 
6 7 8 
9

根据我们的偏好,我们可以将数字排列在列中:

0 3 6  
1 4 7
2 5 8
    9

但是,无论哪种方式,我们最终都会得到其中一列的数字比其他列多一个。 10 除以 3 的余数始终为 1,因此无论我们如何将数字除以,我们总会得到一个余数,这使得其中一个输出比其他输出更常见。

上面代码的基本思想非常简单:在得到一个数字并计算出像上面那个数字这样的“表格”会落在哪里之后,它会检查我们得到的数字是否是“奇数”。如果是,则执行循环的另一次迭代以获得另一个数字。

还有其他方法可以做到这一点。例如,您可以首先计算仍在随机数生成器范围内的范围大小的最大倍数,然后重复生成数字,直到得到比它小的一个,然后将收到的数字相除以使其正确范围。从理论上讲,这甚至可以稍微更有效(它避免将随机数划分到正确的范围内,直到它获得将要使用的随机数)。实际上,绝大多数情况下,循环只会执行一次迭代,因此我们在循环内部或外部执行的内容几乎没有区别。

【讨论】:

  • 这对我来说似乎是正确的,但并不是很明显。请您详细说明为什么它是正确的?
【解决方案2】:
#include <iomanip>
#include <iostream>
#include <stdlib.h>
#include <time.h>

// initialize random seed
srand( time(NULL) );

// generate random number
int randomNumber = rand() % 12 + 1;

// output, as you seem to wan a '0'
cout << setfill ('0') << setw (2) << randomNumber;

直接解决问题可能会更好?

// generate random number
int randomNumber = rand()>>4; // get rid of the first 4 bits

// get the value
randomNumer = randomNumer % 12 + 1;

编辑在 mre 和 dirkgently 的 cmets 之后

【讨论】:

  • 糟糕的方法,因为许多随机数生成器的低位是非随机的。阅读我在答案中发布的常见问题解答。
  • @dirkgently 我敢打赌这只是家庭作业,所以他不在乎这些数字是否真的随机。
  • +1 你太快了 ;) 也许换成 std​​::cout
  • @Earlz:家庭作业是关于正确学习的。不是复制粘贴。因此,我的答案没有完整的解决方案。只是一个提示。一个非常非常重要的提示要牢记。
  • 缺少 #include 并且它是 std::setfill 和 std::setw
【解决方案3】:

使用以下公式:

M + rand() / (RAND_MAX / (N - M + 1) + 1), M = 1, N = 12

并阅读此FAQ

编辑:关于这个问题的大多数答案都没有考虑到较差的 PRN 生成器(通常与库函数 rand() 一起提供)在低位中不是很随机的事实。因此:

rand() % 12 + 1

不够好。

【讨论】:

  • 使用除法本身只会带来微小的改进——结果可能更加随机,但它们通常仍然存在偏差。假设rand() 以相等的概率产生直到 RAND_MAX 的所有数字,这将不会以相等的概率产生从 1 到 12 的数字,除非 RAND_MAX 恰好是 12 的倍数(非常罕见)。
  • +1 用于提高使用天真的 % 方法的统计偏差问题。
  • @Jerry:公平地说,链接的常见问题解答提供了其他解决方案。
  • @Clifford:我没有检查链接,但你是对的。再说一次,如果没记错的话,我对常见问题解答中的内容负有部分责任......
  • 其实,重新检查,看起来我可能不是。对于任何关心我在说什么的人,请参阅:groups.google.com/group/comp.lang.c/browse_frm/thread/…
【解决方案4】:

你可以这样做,例如:

#include <cstdlib>
#include <cstdio>
#include <time.h>

int main(int argc, char **argv)
{
    srand(time(0));

    printf("Random number between 1 and 12: %d", (rand() % 12) + 1);
}

srand 函数将使用当前时间(以秒为单位)为随机数生成器播种 - 通常是这样做的,但也有更安全的解决方案。

rand() % 12 会给你一个介于 0 和 11 之间的数字(% 是模运算符),所以我们在这里加 1 以达到你想要的 1 到 12 的范围。

为了打印 01 02 03 等而不是 1 2 3,您可以格式化输出:

printf("Random number between 01 and 12: %02d", (rand() % 12) + 1);

【讨论】:

    【解决方案5】:

    (rand() % 12 + 1).ToString("D2")

    【讨论】:

    • 问题标记为 C++,而不是 C# 或任何代码。
    • 如果有人不知道如何将其转换为 c++,那么我质疑进行任何编程的能力。
    • @tim:但在这一点上,它基本上并没有做更多的事情,只是回应了这个问题。小数点后两位如何打印?用两位小数进行转换!哦,除此之外,就如何缩小范围给出了与至少六个其他人一样的(坏的)建议......
    猜你喜欢
    • 2014-02-25
    • 1970-01-01
    • 1970-01-01
    • 2015-06-05
    • 2018-09-09
    • 1970-01-01
    • 2013-11-12
    • 2010-12-19
    • 2012-06-22
    相关资源
    最近更新 更多