鱼C论坛

 找回密码
 立即注册
查看: 3931|回复: 14

[技术交流] Python:每日一题 56

[复制链接]
发表于 2017-6-1 17:19:15 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 ooxx7788 于 2017-6-2 08:55 编辑

对于今天的题目,我原本只想写这样一句。
利用蒙特卡洛算法,计算pi.

但想想估计这样很多人都不知道从哪里开始,所以我把步骤稍微分解下。
先介绍下,如何根据蒙特卡洛算法来算出pi的。
基本思想: 利用圆与其外接正方形面积之比为pi/4的关系,通过产生大量均匀分布的二维点,计算落在单位圆和单位正方形的数量之比再乘以4便得到pi的近似值。样本点越多,计算出的数据将会越接近真识的pi(前提时样本是“真正的”随机分布)。

步骤:
1、产生一定数量的位于正方形内部的样本(样本越大越精确)。
2、计算样本中位于圆内的样本数量。
3、利用圆与其外接正方形面积之比为pi/4的关系,计算出pi值
4、和真实的pi值进行对比,获得误差。

网上已经有一些二维的例子,当然你也可以参考。

如果觉得练习不够,还可以试试下面这个三维的球体外接正方体计算pi,道理和步骤都是相似的。
QQ图片20170601164729.jpg

冬雪给了个二维版的,我就给这个三维版的吧。
游客,如果您要查看本帖隐藏内容请回复

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-6-1 18:33:12 | 显示全部楼层
先写一个,速度比较慢。
  1. import math, random
  2. a = 0
  3. n = 10000000 #样本量
  4. for i in range(n):
  5.     x = random.random()
  6.     y = random.random()
  7.     if x * x + y * y <= 1:
  8.         a += 1
  9. pi = a / n * 4
  10. print('计算出的pi值是:%f'%pi)
  11. print('与内置pi值的相对误差是:%f%%'%((pi - math.pi) / math.pi * 100))

复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-6-1 19:31:28 | 显示全部楼层
冬雪雪冬 发表于 2017-6-1 18:33
先写一个,速度比较慢。

蒙特卡洛算法
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-6-1 23:27:22 From FishC Mobile | 显示全部楼层
本帖最后由 jerryxjr1220 于 2017-6-2 11:44 编辑

貌似我的小练习中已经算过了
http://bbs.fishc.com/thread-80125-1-1.html
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-6-7 18:09:10 From FishC Mobile | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2017-7-18 21:06:03 | 显示全部楼层
一样的思想,用了4种写法,结果numpy快了好几个数量级
  1. import random
  2. import math
  3. import time
  4. import numpy

  5. # 通过参数半径r及实验次数trial返回pi估计值,涉及平方和用整数可能会好算一点,集合可能会缩小概率,还是用列表

  6. # 直接在推导式中判断,然后返回
  7. def cal_pi_1(r,trial):
  8.     return 4*len([1 for i in range(trial) if (random.randint(-r,r)**2+random.randint(-r,r)**2)<=r**2])/ trial

  9. # 将生成和判断分开两半,瞅瞅有没有变化
  10. def cal_pi_2(r,trial):
  11.     q = [(random.randint(-r,r),random.randint(-r,r)) for i in range(trial)]
  12.     w = [1 for i in q if i[0]**2+i[1]**2 <= r**2]
  13.     return 4*len(w)/ trial

  14. # 不用推导式,直接循环赋值
  15. def cal_pi_3(r,trial):
  16.     p=0
  17.     for i in range(trial):
  18.         a,b = random.randint(-r,r),random.randint(-r,r)
  19.         if a**2+b**2 <= r**2:
  20.             p +=1
  21.     return (4*p/trial)

  22. # 使用 numpy 库,数字比较大,没有定好dtype会出错
  23. def cal_pi_4(r,trial):
  24.     m = numpy.random.randint(-r,r+1,trial,dtype=numpy.int64)
  25.     n = numpy.random.randint(-r,r+1,trial,dtype=numpy.int64)
  26.     k = pow(m,2)+pow(n,2)
  27.     return (4*len(numpy.nonzero(k<=r**2)[0])/trial)
复制代码

r = 100000,trial = 100000
结果
  1. ##第1个函数耗时  1.0870623s -----:my pi is: 3.13892    ,error approaches to  0.0850732 %
  2. ##第2个函数耗时  1.1000628s -----:my pi is: 3.14136    ,error approaches to  0.0074055 %
  3. ##第3个函数耗时  1.0660610s -----:my pi is: 3.1406     ,error approaches to  0.0315971 %
  4. ##第4个函数耗时  0.0110006s -----:my pi is: 3.14204    ,error approaches to  0.0142394 %
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2017-12-6 15:01:55 | 显示全部楼层
  1. def getPiBy(n=1000): #半径1000,样本数为2000*2000=4000000
  2.     if n < 10:
  3.         return '样本太小'
  4.     else:
  5.         count = 0
  6.         total = 4*n**2
  7.         for x in range(-n,n):
  8.             for y in range(-n,n):
  9.                 if x**2+y**2<=n**2:
  10.                     count+=1
  11.         pi = count*4/total
  12.         return '%.7f'%pi

  13. for i in (50, 1000, 2000, 3000):
  14.     pi = getPiBy(i)
  15.     print('采样数:{0},pi近似值:{1},误差率:{2}%'.format(4*i**2, pi, '%.4f'%(100-float(pi)*(100/3.1415926))))

  16. ##    采样数:10000,pi近似值:3.1372000,误差率:0.1398%
  17. ##    采样数:4000000,pi近似值:3.1415470,误差率:0.0015%
  18. ##    采样数:16000000,pi近似值:3.1415857,误差率:0.0002%
  19. ##    采样数:36000000,pi近似值:3.1415772,误差率:0.0005%

复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2019-1-10 20:16:37 | 显示全部楼层
看看
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2019-5-2 14:11:45 | 显示全部楼层
好像不难。
  1. import random
  2. counter_in = 0
  3. counter_all = 0
  4. for i in range(10000000):
  5.     x = random.uniform(0, 2)
  6.     y = random.uniform(0, 2)
  7.     if (x-1)**2 + (y-1)**2 <= 1:
  8.         counter_in += 1
  9.     counter_all += 1
  10.    
  11. print(counter_in, counter_all)
  12. pi = (counter_in * 4) / counter_all
  13. print('pi = %f' % pi)
复制代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2020-6-11 16:20:56 | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-7-2 09:22:58 | 显示全部楼层
1
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-10-3 11:09:55 | 显示全部楼层
666
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-10-4 10:37:32 | 显示全部楼层
学习
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-11-18 00:18:05 | 显示全部楼层
nice
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2020-11-18 17:17:24 | 显示全部楼层
蒙特卡洛算法
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-1 06:32

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表