已知f(x) 传入的值 等概率 输出0 or 1,如果写一个f1(x)实现等概率输出0-9?

如题
怎么实现一个方法,实现传入值后,等概率输出0或1,(0和1每个概率都是50%)
怎么根据f(x)实现一个f1(x) ,要求f1(x)满足,传入参数后,等概率输出0-9,(0-9每个概率都是10%)
附上灵魂图片
image.png

阅读 8.3k
9 个回答

这题是个数学题啊,看到各位都在吵架,首先,数学上的定义是:
两个事件发生的概率相乘 = 两件事同时发生的概率

所以,从数学上来说,如果A事件发生的概率是50%,B事件发生的概率也是50%,那么A和B同时发生的概率为:
50%*50%=25%
从题目这里来看,有个已知条件,或者叫做已知函数f(x),在已知条件上写一个新的函数f1(x),而题目的条件是等概率输出0~9,所以相当于基于50%概率发生器创建一个10%的概率发生器。

怎么创建一个10%的事件发生器呢,我们从公式可知,f(x)产生事件概率P(1)=50%,P(0)=50%,那么P(1)两次执行,也就是两次结果都是1的概率为25%,三次结果都是1的概率为12.5%,四次执行都为1的概率为6.25%,相当于四次产生的1111组合的概率为6.25%,也就是1/16.
这个数据是不是很熟悉?我们用程序生成一下四次0和1产生的组合数:

0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111

这个数据是不是很熟悉?相当熟悉,就是个二进制数,转换成十进制之后,就是0~15,相当于16个数每个数发生的概率都是1/16;从另外一个角度来说,从0到16发生的概率都相等,那么也就是说,从0~9数据产生的概率都相等。那么这个f1(x)应该就是在其中调用4次f(x),生成4位的二进制数,然后再转换成10进制数,如果这个数大于9,再重新生成即可。

自然也就实现了等概率生成0~9的数据。
以下是PHP语言的实现,其他语言实现我就懒得写了:

// 模拟fx()
function f($x)
{
    return mt_rand(0, 1);
}

function f1($x)
{
    $j = '0x';
    for ($i = 0; $i < 4; $i++) {
        $j .= f($x);
    }
    // 二进制字符串转二进制
    $j = base_convert($j, 2, 2);
    // 二进制转10进制
    $j = bindec($j);
    if ($j > 9) {
        return f1($x);
    } else {
        return $j;
    }
}

参考资料
https://www.geeksforgeeks.org...
https://leetcode-cn.com/probl...
程序员面试金典第六版16.23

const uniform = (a: number, b: number): number => {
  return a + Math.floor((b - a) * Math.random())
}

const rand2 = () => {
  return uniform(0, 2)
}

const rand4 = () => {
  return 2 * rand2() + rand2()
}

const rand10 = () => {
  const ans = 4 * rand4() + rand4()

  if (ans < 10) return ans

  return rand10()
}

const map = {
  0: 0,
  1: 0,
  2: 0,
  3: 0,
  4: 0,
  5: 0,
  6: 0,
  7: 0,
  8: 0,
  9: 0,
  10: 0,
}
for (let i = 0; i < 1e6; ++i) {
  ++map[rand10()]
}

console.log(map)

由于题主未指明传参的用途,以下仅回答2个随机取数部分

Math.floor(Math.random()*2); // 获取 0 到 1 的随机整数。
Math.floor(Math.random()*10); // 获取 0 到 9 的随机整数。
这里使用round与toFixed其实是不符合等概率的。

从楼主后面的回复,如果需要满足限定次数下必随机到,可以通过随机后移除已随机到的部分继续随机以满足

需要额外指出的是函数的定义与注释需要表达语义,代码误用或理解错误很多就是语义不清晰造成的,好比楼主的等概率与大家的回答。
-------------分割线-------------------------------------------
另单指小天的答案,
f(min,max),使用的人大概率会认为该函数是随机[min, max],我说的错就是这个,其他的什么round,等分概率全是他自己捏出来的靶子在那攻击,满嘴喷那啥,一口一个上等人阴阳怪气,还在那摆什么资历,笑死个人,素质高下一眼立见。指出他错误,估计是被别人踩了答案以为是我,结果乱骂一通!建议大家举报一下

等下 人家题意应该是要用50%的概率搞出个10%吧 类似

function pten() {
   return f() * f() * f();
}

function random() {
  for(let i = 0; i <= 9; i++) {
     if (pten()) {
        return i;
     }
  }
  return 9
}

这样吧?
只是这个10%不知道怎么搞出来?

从你描述来看,其实与传入的参数没有任何关系~应该是一个有固定规则输出的纯函数。
这是一个常见简易转盘抽奖概率设计。
按照你的问题,假设有如下靶子:
image.png
由你投掷飞镖,对于左边的靶子,0区域与1区域平分靶子面积,那么你每次投掷命中 0 ,1区域的概率都是50%;
抽象成纯函数:

function f() {
    return Math.floor(Math.random()*2)
}

对于右边的靶子,0-9 10个区域平分靶子面积,那么你每次投掷,命中其中一个区域的概率都是10%。
抽象成纯函数:

function f() {
    return Math.floor(Math.random()*10)
}

因为[0-0.1)*10 =0 (取最小整数)
因为[0.1-0.2)*10 =1 (取最小整数)
以此类推,每个区域恰好命中同样的数值区间。
当然,因为Math.random()返回一个浮点伪随机数在范围[0,1),(包括0,但是不包括1)导致命中最大值的概率(第一个是1,第二个是9)会稍微有误差,但也会无限接近50% 或10%.

希望能解答你的问题。


------------- 我是分割线 -------
仅仅是传参然后依次输出0-9的话,更简单了:

(
    function (window){
        window.result = -1 
        function f(anyVal) {
            if (window.result === 9) {
                window.result = -1
            }
            window.result +=1
            return window.result
            
        }
        window.f=f
    }
)(window)

结果如图:
image.png
随便怎么输入,就考察一个值的存储,为了显得基础扎实点,你可以将window.result换成闭包。
这样还不行的话。。。你可以反问面试官了

------- 分割线2 -----
有一部分审题没严谨,做出了不严谨的回答,给题主道歉。题中有提到需要利用f(x),我重新补充下:

(
    function (window){
        window.result = -1 
        function f1(x) {
            if(f(x)){ //只有f(x)等概率输出1时才允许 f1(x)返回有意义的值,这样保证每个f1(x)计算出来的值都是基于f(x)等概率输出一次1的概率
              if (window.result === 9) {
                window.result = -1
              }
              window.result +=1
              return window.result
            }
        }
        window.f1=f1
    }
)(window)

根据已采纳的层主解释,将php转化为js,自己写了一个,感谢层主@kumfo

function f(x:number):number{
        return mt_rand(0, 1)
}
function f1(x:number):number {
    let n = 0
    n += 0x1*fx(x)
    n += 0x10*fx(x)
    n += 0x100*fx(x)
    n += 0x1000*fx(x)

    if (n > 9) {
        return f1(x)
    }else{
        return n
    }
}

简单说下结论
如果要求数学上f1概率完全相同,那最坏情况下f1运行时间无限长
如果是从工程角度考虑,可以让f1的每个值的概率近似10%而非绝对的10%,就可以避免上面那种情况

(可以设定传值,但没必要)

// f() 等概率返回 0 或 1
int f();

// f1() 等概率返回 0 - 9 中任意数字
int f1() {
    int t = f() | f() << 1 | f() << 2 | f() << 3;
    return t <= 9 ? t : f1();
}

image.png
测试下就知道了,没必要争吵。
这个只是随机,不是题主说的等分
@dodopy
@小天

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏