前言:
这次是写作业,质量管理课程里面的 OC 曲线, 我自己写了 分解质因数,计算组合数,计算二项分布,二项分布求和 这些函数。
然后描点画图。
效果图:
OC曲线.png 第一问.png 第二问.png代码地址:
代码地址:https://github.com/gityuency/Autolayout
示例代码类名 【OCCurveViewController】【SecondQuestion】
关键代码
计算部分的代码: SecondQuestion.swift
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]()
@discardableResult
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
}
}
在ViewController里面画图:OCCurveViewController.swift
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
}()
override func viewDidLoad() {
super.viewDidLoad()
self.navigationController?.navigationBar.isHidden = true
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)
backVVVV.layer.addSublayer(bLayer)
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.cornerRadius = pointWH / 2
pLayer.position = CGPoint(x: Double(i) * rate, y: (score))
pLayer.backgroundColor = UIColor.red.cgColor
bLayer.addSublayer(pLayer)
}
//开始二阶段的是算数
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)
backShortK.layer.addSublayer(bbbb)
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)
bbbb.addSublayer(heng)
let shu = CALayer()
shu.backgroundColor = UIColor.black.cgColor;
shu.frame = CGRect(x: 0, y: score, width: Double(i) * rate, height: 1)
bbbb.addSublayer(shu)
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)
backShortK.addSubview(label)
}
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))
bbbb.addSublayer(pLayer)
}
}
}
///保留两位小数 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
}
}
结语
花了两天。
网友评论