# iOS Swift 计算组合数　二项分布　二项分布求和

## 前言:

OC曲线.png

### 关键代码

``````import Foundation

/// 这个就是我用来做二项式计算的代码
class SecondQuestion {

/// 二项分布求和
/// - Parameters:
///   - m: 组合的上
///   - n: 组合的下
///   - p: 概率
/// - Returns: 求和结果
static func sumBinomialDistribution(m: Int, n:Int, p:Int) -> Double {
var result: Double = 0
for i in 0..<m {
result = result + calculateBinomialDistribution(m: i, n: n, p: p)
}
result = result + calculateBinomialDistribution(m: m, n: n, p: p)
//print("单次求和结果: \(result)")
return result
}

/// 计算单个二项分布
/// - Parameters:
///   - m: 上方
///   - n: 下方
///   - p: 发生的概率, 这个概率如果使用小数, 那么就会有精度丢失的问题, 那么, 在传入的时候,把这个精度使用 Int, 在计算的时候, 再转换成Double 取值范围 0-100
///   - d: 发生了多少次
/// - Returns: 本次二项分布的概率
static func calculateBinomialDistribution(m: Int, n:Int, p: Int) -> Double {
let a = Double(xindejiechengfanan(m: m, n: n))
let b = pow(Double(p) * 0.0001, Double(m))
let c = pow((Double(10000 - p)) * 0.0001, Double(n - m))
let result = a * b * c;
return result
}

//计算组合数
static func xindejiechengfanan(m: Int, n: Int) -> Int {

var fenMuArray = [Int]()
var fenZiArray = [Int]()

//去掉最大的数
let l = m
let r = n - m
var count: Int = 0
if l > r {
count = (n - l)
} else {
count = (n - r)
}
var k = n
for _ in 0..<count {
fenZiArray.append(k)
k = k - 1
}
//print("fenZiArray  \(fenZiArray)")

var B: Int = 0
let zuixiaofenmuxunhuanshu = l > r ? r : l
for _ in 0..<zuixiaofenmuxunhuanshu {
B = B + 1
fenMuArray.append(B)
}
if fenMuArray.count > 0 {
fenMuArray.remove(at: fenMuArray.firstIndex(of: 1)!)
}
//print("fenMuArray  \(fenMuArray)")

//把分子里面的每一个数,分解质因数,然后放到数组里面
var fenziFenjiezhiyinshu = [Int]()
for i in fenZiArray {
fenziFenjiezhiyinshu += needZhiYinShuZu(n: i)
}
//print("fenziFenjiezhiyinshu \(fenziFenjiezhiyinshu)")

var fenmufenjieshuzu = [Int]()
for i in fenMuArray {
fenmufenjieshuzu += needZhiYinShuZu(n: i)
}
//print("fenmufenjieshuzu \(fenmufenjieshuzu)")

//遍历分子数组,然后把分母中相同元素移除掉
for i in fenmufenjieshuzu {
for k in fenziFenjiezhiyinshu.reversed() {
if k == i {
fenziFenjiezhiyinshu.remove(at: fenziFenjiezhiyinshu.firstIndex(of: k)!)
break
}
}
}

//print("简化之后 fenziFenjiezhiyinshu \(fenziFenjiezhiyinshu)")
let sum = fenziFenjiezhiyinshu.reduce(1,{\$0 * \$1})
//print(sum)
return sum;
}

/// 得到一个数分解质因数后的数组
/// - Parameter n: 需要分解的数
/// - Returns: 数组
static func needZhiYinShuZu(n: Int) -> [Int] {
var result = [Int]()
func fenjizhiyinshu(n: Int) -> Int {

for i in 2..<n {
if (n % i == 0) {
let temp = n / i
result.append(i)
return fenjizhiyinshu(n: temp)
}
}
result.append(n)
return n;
}
fenjizhiyinshu(n: n)
//print("分解得到质因数数组: \(result)")
return result
}
}

``````

``````import UIKit

//!!!!!!!!   请调整为横屏!!!!!!!

/*

第一问:
α = 0.036564459244395664
β = 0.07374950015762405

第二问:
P0 = 0.0043
p1 = 0.0277

第三问:
在样本具有代表性前提下, 结合 OC 曲线图, 可以看到,这两种抽样方案, 对与生产方来说, 弃真风险较小, 对于接收方来说,取伪风险也较小.
在第一种情况下, α = 0.036564, β = 0.07375 双方风险相差较小, 对于买卖双方来说, 相对公平.
第二种情况下,  α = 0.05, β = 0.1 这是一种推荐 α,β 取值对, 结合 OC曲线图, 同样可以认为对买卖双方来说,具有操作空间,具有公平性.

关于画图和求和计算: 使用电脑进行暴力计算, 合格品率我从 0.00% 取到了 100.00%, 一共是一万零一个数, 都把对应的接收概率P计算出来,
然后每个数值都在屏幕上描点, 因为点足够多, 就画出了 OC 曲线.
但是一万个点太多, 不适宜进行 作业中的 第二问, 第三问回答, 所以, 我取了曲线中变化最快的那一段进行放大,
于是就有了下方 从 0 - 0.05 描 501 个点的 OC 曲线, 这样图看起来就比较直观, 也易于求解.

*/
class OCCurveViewController: UIViewController {

@IBOutlet weak var backShortK: UIView!

///宽1200 高 400
@IBOutlet weak var backVVVV: UIView!
/// 放曲线的背景
lazy var backView: UIView = {
let v = UIView()
v.backgroundColor = UIColor.orange
v.frame = CGRect(x: 100, y: 100, width: 400, height: 400)
return v
}()

for i in 0...10000 {
let a = SecondQuestion.sumBinomialDistribution(m: 2, n: 190, p: i)
let ki = (Double(i) * 0.01).roundTo(places: 2)
print("不合格品率: \(ki)%    P: \(a)   α: \(1 - a)")
}
/*
第一问:
不合格品率: 0.38%    P: 0.9634355407556043   α: 0.036564459244395664
α = 0.036564459244395664

不合格品率: 3.0%    P: 0.07374950015762405   α: 0.926250499842376
β = 0.07374950015762405

*/

/*
第二问:

α 为 0.05, 那么 接受概率是 0.95
在
不合格品率: 0.43%    P: 0.9504782551776189   α: 0.04952174482238114
P0 = 0.0043

β 为 0.1
不合格品率: 2.77%    P: 0.10092052472525978   α: 0.8990794752747402
p1 = 0.0277

*/

}

///这个函数是用来画曲线的
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

/// 放曲线的背景
let bLayer = CALayer()
//bLayer.backgroundColor = UIColor.blue.cgColor
bLayer.frame = CGRect(x: 0, y: 0, width: backVVVV.frame.width, height: backVVVV.frame.height)

var allPointArray = [Double]()

for i in 0...10000 {
let a = SecondQuestion.sumBinomialDistribution(m: 2, n: 190, p: i)
let k = (1 - a) * 400.0
allPointArray.append(k)
}

let pointWH: CGFloat = 1
let rate: Double = 3 / 25.0

// 添加分数点
for (i, score) in allPointArray.enumerated() {
let pLayer = CALayer()
pLayer.frame = CGRect(x: 0, y: 0, width: pointWH, height: pointWH)
pLayer.position = CGPoint(x: Double(i) * rate, y: (score))
pLayer.backgroundColor = UIColor.red.cgColor
}

//开始二阶段的是算数
startNew()
}

func startNew() {

/// 放曲线的背景
let bbbb = CALayer()
//bLayer.backgroundColor = UIColor.blue.cgColor
bbbb.frame = CGRect(x: 0, y: 0, width: backShortK.frame.width, height: backShortK.frame.height)

var allPointArray = [Double]()

//不合格品率: 5.0%    P: 0.003555799076021292   α: 0.9964442009239787
for i in 0...500 {
let a = SecondQuestion.sumBinomialDistribution(m: 2, n: 190, p: i)
let k = (1 - a) * 400.0
allPointArray.append(k)
}

let pointWH: CGFloat = 1
let rate: Double = 1200 / Double(allPointArray.count - 1)

// 添加分数点
for (i, score) in allPointArray.enumerated() {

let pLayer = CALayer()

if i == 43 || i == 277 {
//if i == 38 || i == 300 {

let heng = CALayer()
heng.backgroundColor = UIColor.black.cgColor;
heng.frame = CGRect(x: Double(i) * rate, y: score, width: 1, height: Double(bbbb.frame.height) - score)

let shu = CALayer()
shu.backgroundColor = UIColor.black.cgColor;
shu.frame = CGRect(x: 0, y: score, width: Double(i) * rate, height: 1)

let label = UILabel()
let ki = (Double(i) * 0.01).roundTo(places: 2)
let shuzhi = SecondQuestion.sumBinomialDistribution(m: 2, n: 190, p: i)
label.text = "(\(ki)%, \(shuzhi.roundTo(places: 6)))"
label.sizeToFit()

label.frame = CGRect(x: CGFloat((Double(i) * rate) + 5), y: CGFloat(score - 10), width: label.frame.width, height: label.frame.height)
}

pLayer.backgroundColor = UIColor.red.cgColor
pLayer.frame = CGRect(x: 0, y: 0, width: pointWH, height: pointWH)
pLayer.position = CGPoint(x: Double(i) * rate, y: (score))
}
}
}

///保留两位小数 Rounds the double to decimal places value
extension Double {
func roundTo(places:Int) -> Double {
let divisor = pow(10.0, Double(places))
return (self * divisor).rounded() / divisor
}
}

``````