计算π [蒙特卡洛+碰撞计数+巴塞尔]

Posted by Yinode on Wednesday, May 6, 2020

TOC

仅供娱乐

蒙特卡洛方法

基于统计的方法

发射大量的随机点,通过这个比值就能换算出π的值

至于判断点是否在圆内用简单的通项公式 sqrt((a - x) ^ 2 + (b - y) ^ 2) <= r即可

方块碰撞方法

这个相对最有意思,原理可以看视频

[](https://www.youtube.com/watch?v=jsYwFizhncE&t=602s)

class Block {
  x: number // X 坐标
  w: number
  m: number // 质量
  v: number // 速度

  constructor(x: number, w: number, m: number, v: number) {
    this.x = x
    this.w = w
    this.m = m
    this.v = v
  }

  update() {
    this.x += this.v
  }

  isHitWall(): boolean {
    return this.x <= 0
  }

  reverse() {
    this.v *= -1
  }

  isCollision(otherBlock: Block) {
    const isRightCollision = this.x + this.w < otherBlock.x // 该方块的右侧是否与其他方块的左侧发生碰撞
    const isLeftCollision = this.x > otherBlock.x + otherBlock.w // 该方块的左侧是否与其他方块的右侧发生碰撞
    return !(isLeftCollision || isRightCollision)
  }

  bounce(otherBlock: Block): number {
    let sumM = this.m + otherBlock.m
    let newV = (this.m - otherBlock.m) / sumM * this.v
    newV += (2 * otherBlock.m / sumM) * otherBlock.v
    return newV
  }
}

let count = 0
let diagits = 7
let timeSteps = 10 ** (diagits - 2)


let miniBlock = new Block(100, 20, 1, 0)
let m2 = 100 ** diagits - 1
let bigBlock = new Block(300, 100, m2, -1 / timeSteps)

while (true) {
  for (let i = 0; i < timeSteps; i++) {
    if (miniBlock.isCollision(bigBlock)) {
      const v1 = miniBlock.bounce(bigBlock)
      const v2 = bigBlock.bounce(miniBlock)
      miniBlock.v = v1
      bigBlock.v = v2

      count++
    }

    if (miniBlock.isHitWall()) {
      miniBlock.reverse()
      count++
    }

    miniBlock.update()
    bigBlock.update()
  }

  console.log(count)
}

巴塞尔递推公式(无穷级数)

let total = 1
let maxCount = 1000000000

for (let i = 2; i < maxCount; i++) {
  total += 1 / (i * i)
}

// 因为 JS 的浮点数精度限制 所以大概只能到3.1415926的样子 想要提高精度得自己写一套基本运算体系
console.log(Math.sqrt(total * 6))