趣味 SQL:使用蒙特卡洛方法计算圆周率 Pi 的值
圆周率(Pi)是圆的周长与直径的比值,一般用希腊字母 π 表示,是一个在数学及物理学中普遍存在的数学常数。π 也等于圆形之面积与半径平方之比,是精确计算圆周长、圆面积、球体积等几何形状的关键值。
蒙特卡洛方法(Monte Carlo method)也称统计模拟法、统计试验法。蒙特卡洛方法的基本思想是:首先建立一个描述问题的概率模型或随机过程,使它的参数或数字特征等于问题的解;然后通过对模型或过程的观察或抽样试验来计算这些参数或数字特征;最后给出所求解的近似值。
使用蒙特卡洛法求解 π 值基本步骤如下:构造一个单位正方形和一个单位圆的 1/4;往正方形内随机投点,根据点到原点的距离是否大于 1 判断点是落在 1/4 的圆内还是在圆外。
根据落在两个不同区域的点的数目,例如总的点数为 N,1/4 圆内的点数为 n。如果次数够多,根据两者的面积公式:
nN≈14π1.021.02=π4 \frac n N \approx \frac {{\frac1 4}{\pi 1.0^2}} {1.0^2} = \frac \pi 4 Nn≈1.0241π1.02=4π
也就是说,
π≈4nN \pi \approx 4 \frac n N π≈4Nn
我们只要知道 n 和 N 的值,就可以获得 π 的近似值。
接下来我们介绍如何在不同的数据库中实现以上过程,首先是 MySQL:
with recursive pi(x, y, n) as ( select rand() x,rand() y, 1 n union all select rand(), rand(), n+1 from pi where n<100 ) select 4*sum(1-floor(x*x+y*y))/count(*) val from pi; val | ----| 3.16|
其中,WITH 表示通用表表达式。关于通用表表达式(Common Table Expression)的详细介绍可以参考这篇文章。
rand() 函数随机返回 0 到 1 之间的数字;floor() 函数用于返回小于等于参数的整数,这里表示点落在 1/4 圆内(0)或者圆外(1)。
试验次数 | 100 | 1000 | 10000 | 100000 | 10000000 | 100000000 |
---|---|---|---|---|---|---|
近似值 | 3.16 | 3.156 | 3.1076 | 3.1362 | 3.14114 | 3.1415404 |
随着次数的增加,模拟计算出的值越接近 π 的真实值。
其他的数据库也可以使用类似的方式进行模拟,语法略微有些差异:
-- Oracle 使用 dbms_random.value() 函数获取随机值 with pi(x, y, n) as ( select dbms_random.value() x,dbms_random.value() y, 1 n from dual union all select dbms_random.value(), dbms_random.value(), n+1 from pi where n<10000 ) select 4*sum(1-floor(x*x+y*y))/count(*) val from pi; VAL | -----| 3.166| -- SQL Server rand() 函数在一个 SELECT 中只返回一个相同的值,需要设置不同的 seed with pi(x, y, n) as ( select rand(CHECKSUM(NEWID())) x,rand(CHECKSUM(NEWID())) y, 1 n union all select rand(CHECKSUM(NEWID())), rand(CHECKSUM(NEWID())), n+1 from pi where n<10000 ) select 4*sum(1-floor(x*x+y*y))/count(*) val from pi OPTION( MAXRECURSION 32767); val | -----| 3.134| -- PostgreSQL 使用 random() 函数获取随机数 with recursive pi(x, y, n) as ( select random() x,random() y, 1 n union all select random(), random(), n+1 from pi where n<10000 ) select 4*sum(1-floor(x*x+y*y))/count(*) val from pi; val | ------| 3.1476| -- SQLite random() 函数返回 -9223372036854775808 到 +9223372036854775807 之间的数字 with recursive pi(x, y, n) as ( select abs((random()/9223372036854775808.0)) x,abs((random()/9223372036854775808.0)) y, 1 n union all select abs((random()/9223372036854775808.0)), abs((random()/9223372036854775808.0)), n+1 from pi where n<10000 ) select 4*sum(1.0-floor(x*x+y*y))/count(*) val from pi; val | ------| 3.1584|
除了 Oracle 之外,以上其他数据库都提供了 pi() 函数。
定期更新数据库领域相关文章,欢迎关注❤️、点赞👍、转发📣!
- 点赞 5
- 收藏
- 分享
- 文章举报
- 使用规则引擎Drools计算圆周率PI
- scala下使用akka计算圆周率pi
- 采用蒙特卡洛方法计算PI的值
- 蒙特卡洛方法计算圆周率的三种实现-MPI openmp pthread
- 字符串相似度计算的方法,使用SQL以及C#实现,本文非原创摘自网络(.NET SQL技术交流群入群206656202需注明博客园)
- vs中使用M_PI的问题及解决 角度转弧度&根据弧度计算圆周上点的坐标的方法
- 算法之美--1.蒙特卡洛方法计算pi
- 使用Java Math.random()利用蒙特卡洛方法计算pi值
- Java使用Math.random()结合蒙特卡洛方法计算pi值示例
- Java运用蒙特卡洛方法计算圆周率
- C# 中使用 MD5 算法计算 hash (哈希)值的四种方法
- sql中各种日期的计算方法~
- SQL中Case的使用方法
- 计算圆周率 Pi (π)值
- [SQL模板] 避免使用游标 cursor 的最佳方法
- [SQL基础]SQL常用命令使用方法
- SQL*Plus 使用技巧--编辑功能使用方法
- SQL常用命令使用方法
- ASP中 SQL语句 使用方法第1/3页
- 在LINQ to SQL中使用Translate方法以及修改查询用SQL