计算结果总和的概率的算法

| 我正在使用的算法允许您用x个项目展示它,每个项目的范围从a到b,结果为y。我希望有一种算法,当该算法提供所描述的值时,将输出发生这种情况的可能性。 例如对于两个模具。由于我已经知道它们(由于可能的结果太低了)。它可以告诉您每种可能性。 该设置将是类似的。 x = 2 a = 1 b = 6。如果您想知道它产生2的机会,则只需吐出1/36(或它的float值)即可。如果您将7作为总和,它会告诉您6。 所以我的问题是,是否有一种简单的方法可以通过已编写的算法来实现这样的事情。还是必须遍历每个项目的每个单次迭代才能获得每个值的组合总数。 确切的公式还可以为您提供组合,以使值从1到12。 因此,它将为您提供一个分布数组,其中每个索引在每个索引处都有组合。如果是0-12。那么0将具有0,1将具有0,而2将具有1。 我觉得这是其他人曾经想要解决的问题,并且算法已经完成。如果任何人都有简单的方法做到这一点,而不仅仅是简单地遍历每个可能的值,那就太棒了。 我不知道为什么要解决这个问题,但是由于某种原因,今天我只是有想解决这个问题的感觉。而且自从我一直在谷歌搜索,使用Wolfram alpha以及自己尝试使用它时。我认为是该承认失败并询问社区的时候了。 我希望算法在c或PHP中(尽管我不愿这样做,因为它要慢得多)。使用c的原因仅仅是因为我想要原始速度,并且我不想处理类或对象。 伪代码或C是显示算法的最佳方法。 编辑: 另外,如果由于数学方面的问题而冒犯了他的名字“ b”的人,我也很抱歉。因为我不是故意要冒犯,但我只想说我不明白。但是答案一直没有解决,因为我敢肯定有人会来问这个问题并理解它背后的数学原理。 另外,我无法决定我要用哪种方式编写代码。我想我会尝试同时使用两者,然后决定在我的小图书馆中查看/使用我更喜欢的一个。 我忘了说的最后一件事是,微积分大约是五年前的四次。我对概率,统计量和随机性的理解来自我自己的学习,即通过阅读代码/阅读维基百科/阅读书籍。 如果有人好奇,是什么引发了这个问题。我有一本我要推迟阅读的书,叫做The Drunkards Walk,然后当我说XKCD 904时,我决定是时候该开始阅读了。然后两天前,当我要睡觉的时候……我考虑过如何通过一种简单的算法来解决这个问题,并且想到了一个。 我对代码的编码理解来自于修补其他程序,查看我破坏某物时发生的情况,然后尝试自己的事情,同时查看内置函数的文档。通过阅读维基百科,我确实理解了大O表示法(从中可以读得最多),而伪代码是因为它与python非常相似。我自己,不能编写伪代码(或说大学的老师)。我不断收到类似“使它不像真实代码,而更像伪代码”这样的注释。这件事没有变。 编辑2:如果任何人搜索此问题只是很快想要代码。我将其包含在下面。由于我确定该代码存在封闭源等效代码,因此已根据LGPLv3获得许可。 它应该是完全可移植的,因为它完全是用c编写的。如果要使用c语言编写的各种语言将其扩展,则只需花费很少的精力即可。我选择“标记”第一个链接到“问数学博士”的答案作为答案,因为这是我用于此问题的实现。 第一个文件的名称为\“ sum_probability.c \”
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <limits.h>

/*!
*    file_name: sum_probability.c
*    
*    Set of functions to calculate the probabilty of n number of items adding up to s
*    with sides x. The question that this program relates to can be found at the url of
*    http://stackoverflow.com/questions/6394120/
*    
*     Copyright 2011-2019, Macarthur Inbody
*    
*   This program is free software: you can redistribute it and/or modify
*   it under the terms of the Lesser GNU General Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the Lesser GNU General Public License
*   along with this program.  If not, see <http://www.gnu.org/licenses/lgpl-3.0.html>.
*     
*   2011-06-20 06:03:57 PM -0400
*    
*   These functions work by any input that is provided. For a function demonstrating it.
*   Please look at the second source file at the post of the question on stack overflow.
*   It also includes an answer for implenting it using recursion if that is your favored
*   way of doing it. I personally do not feel comfortable working with recursion so that is
*   why I went with the implementation that I have included.
*
*/

/*
* The following functions implement falling factorials so that we can
* do binomial coefficients more quickly.
* Via the following formula.
*
*   K
*  PROD    (n-(k-i))/i
*   i=1;
*
*/

//unsigned int return
unsigned int m_product_c( int k,  int n){
    int i=1;
    float result=1;
    for(i=1;i<=k;++i){
        result=((n-(k-i))/i)*result;
    }
    return result;
}

//float return
float m_product_cf(float n, float k){
    int i=1;
    float result=1;
    for(i=1;i<=k;++i){
        result=((n-(k-i))/i)*result;
    }
    return result;
}


/*
* The following functions calculates the probability of n items with x sides
* that add up to a value of s. The formula for this is included below.
*
* The formula comes from. http://mathforum.org/library/drmath/view/52207.html
*
*s=sum
*n=number of items
*x=sides
*(s-n)/x
* SUM  (-1)^k * C(n,k) * C(s-x*k-1,n-1)
* k=0
*
*/

float chance_calc_single(float min, float max, float amount, float desired_result){
    float range=(max-min)+1;
    float series=ceil((desired_result-amount)/range);
    float i;
    --amount;
    float chances=0.0;
    for(i=0;i<=series;++i){
        chances=pow((-1),i)*m_product_cf(amount,i)*m_product_cf(desired_result-(range*i)-1,amount)+chances;
    }
    return chances;
}
这是显示实现的文件,正如我在上一个文件中所说的。
#include \"sum_probability.c\"

/*
* 
* file_name:test.c
*
* Function showing off the algorithms working. User provides input via a cli
* And it will give you the final result.
*
*/
int main(void){
        int amount,min,max,desired_results;
        printf(\"%s\",\"Please enter the amount of items.\\n\");
        scanf(\"%i\",&amount);
        printf(\"%s\",\"Please enter the minimum value allowed.\\n\");
        scanf(\"%i\",&min);
        printf(\"%s\",\"Please enter the maximum value allowed.\\n\");
        scanf(\"%i\",&max);
        printf(\"%s\",\"Please enter the value you wish to have them add up to. \\n\");
        scanf(\"%i\",&desired_results);
        printf(\"The total chances for %i is %f.\\n\", desired_results, chance_calc_single(min, max, amount, desired_results));
}
    
已邀请:
首先,您不必担心范围从
a
b
。您可以从
y
中减去
a*x
,然后假装范围从
0
b-a
。 (因为每个项目对总和的贡献至少为
a
。因此,您可以为每个
x
项目减去subtract2ѭ。) 其次,请注意,您真正想做的是计算获得特定金额的方法数量。概率就是该计数除以简单的指数ѭ11。 大约十年前,“问数学博士”解决了这个问题: http://mathforum.org/library/drmath/view/52207.html 他的公式假设骰子的编号从1到X,因此要使用他的答案,您可能希望将范围移动
a-1
(而不是
a
)以将其转换为该形式。 他的推导使用生成函数,我觉得应该对此进行一点解释。这个想法是定义一个多项式“ 14”,使得“ 15”上的系数是滚动“ 16”的方式的数量。例如,对于单个6面模具,这是生成函数:
z + z^2 + z^3 + z^4 + z^5 + z^6
...因为有一种将每个数字从1滚动到6的方法,而有零种将其他数字滚动的方法。 现在,如果您有两组骰子的两个生成函数
g(z)
h(z)
,那么证明这两个骰子并集的生成函数只是
g
h
的乘积。 (凝视“乘以两个多项式”操作一段时间以说服自己是对的。)例如,对于两个骰子,我们可以对上述表达式求平方以得到:
z^2 + 2z^3 + 3z^4 +4z^5 + 5z^6 + 6z^7 + 5z^8 + 4z^9 + 3z^10 + 2z^11 + z^12
请注意,我们如何直接从系数中读取组合的数量:1种方法获得2(
1*z^2
),6种方法获得7(
6*z^7
),依此类推。 表达式的立方体将为我们提供三个骰子的生成函数;第四力量,四个骰子;等等。 当您以封闭形式编写生成函数,相乘,然后使用二项式定理再次展开时,这种公式化的力量就来了。对于细节,我服从数学博士的解释。     
        假设“ 25”代表您可以选择a和b之间的n个数字(总计x)的方式数量。 然后注意:
f(a, b, n, x) = f(0, b-a, n, x-n*a)
确实,只要采取一种方法来获得x的总和,然后从n个数字中的每一个中减去a,则总和将变为
x - n*a
,并且每个数字都将在0到b-a之间。 因此,编写代码足以找到
f(0, m, n, x)
。 现在注意,实现目标的所有方法(例如,最后一个数字为c)是:
f(0, m, n-1, x-c)
确实,我们剩下n-1个数字,并且希望总和为x-c。 然后我们有一个递归公式:
f(0,m,n,x) = f(0,m,n-1,x) + f(0,m,n-1,x-1) + ... + f(0,m,n-1,x-m)
右边的求和项对应于最后一个等于0、1,...,m的数字 现在您可以使用递归来实现,但这太慢了。 但是,有一个技巧称为记忆式递归,即保存函数的结果,这样就不必再次计算(对于相同的参数)。 记录的递归将具有
O(m * n)
的复杂度,因为这是您需要计算和保存的不同输入参数的数量。 一旦计算出计数,就需要除以总数(m + 1)* n,以得到最终概率。     
        数论,统计和组合运算使您相信要得出事件发生概率的数值-那么您必须知道两件事: 可能结果的数量 在总结果集中,有多少等于您要寻找其概率值的结果“ y”。 用伪代码:
numPossibleOutcomes = calcNumOutcomes(x, a, b);
numSpecificOutcomes = calcSpecificOutcome(y);
probabilityOfOutcome = numSpecificOutcomes / numPossibleOutcomes;
然后,只需编写上面的2个函数就可以了。     
        要获得所有可能性,您可以制作一张价值图:
for (i=a to b) {
 for (j=a to b) {
  map.put(i+j, 1+map.get(i+j))
 }
}
为了更有效地计算总和,可以使用模式 6个7、5个6、4个5、3个4、2个3、1个两个。 该模式适用于n x n的网格,将有n(n + 1)个,对于总和1更大或更小的可能性较小。 这将计算可能性,例如,Count(6,1/2/3/4/5/6)将提供骰子总和的可能性。
import math
def Count(poss,sumto):
  return poss - math.fabs(sumto-(poss+1));
编辑:在C中这将是:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>;

int count(int poss, int sumto)
{
  return poss - abs(sumto-(poss+1));
}

int main(int argc, char** argv) {
    printf(\"With two dice,\\n\");
    int i;
    for (i=1; i<= 13; i++)
    {
        printf(\"%d ways to sum to %d\\n\",count(6,i),i);
    }
    return (EXIT_SUCCESS);
}
给出:
With two dice,
0 ways to sum to 1
1 ways to sum to 2
2 ways to sum to 3
3 ways to sum to 4
4 ways to sum to 5
5 ways to sum to 6
6 ways to sum to 7
5 ways to sum to 8
4 ways to sum to 9
3 ways to sum to 10
2 ways to sum to 11
1 ways to sum to 12
0 ways to sum to 13
    

要回复问题请先登录注册