//php 计算地图上两个坐标之间的距离
define('EARTH_RADIUS', 6378137);//地球半径,假设地球是规则的球体
define('PI', 31415926);
/
计算两组经纬度坐标 之间的距离
params :lat1 纬度1; lng1 经度1; lat2 纬度2; lng2 经度2; len_type (1:m or 2:km);
return m or km
/
function GetDistance($lat1, $lng1, $lat2, $lng2, $len_type = 1, $decimal = 2)
{
$radLat1 = $lat1 PI ()/ 1800; //PI()圆周率
$radLat2 = $lat2 PI() / 1800;
$a = $radLat1 - $radLat2;
$b = ($lng1 PI() / 1800) - ($lng2 PI() / 1800);
$s = 2 asin(sqrt(pow(sin($a/2),2) + cos($radLat1) cos($radLat2) pow(sin($b/2),2)));
$s = $s EARTH_RADIUS;
$s = round($s 1000);
if ($len_type --> 1)
{
$s /= 1000;
}
return round($s, $decimal);
}
echo GetDistance(39908156,1164767, 39908452,116450479, 1);//输出距离/米
PHP常用 *** 作数组的函数
变量和数组的转换
compact() 将变量整合成数组
extract() 将数组中的每个值以键的名分解成变量
变量和字符串转换
explode() 以某个子串分解字符串成数组
implode() 将一维数组根据某个符号拼接成字符串
数组与数组之间关系
array_merge() 合并/并集
array_diff() 差集
array_intersect() 交集
数组值的 *** 作
array_pop() 删除(d出)数组最后一个值
array_push() 向数组中追加一个值
判断数组是否存在数组中
in_array() 判断一个值是否存在数组中
array_key_exists() 判断键是否存在数组中
数组去重
array_unique() 数组去重
获取二维数组中的值的集合
array_column() 获取二维数组中的值的集合
提取数组的键与值
array_values 提取数组的值构成一维数组
array_keys 提取数组的键构成一维数组
返回数组中的随机的键
array_rand() 返回数组中的随机的键
返回数组中值的数量
count() 返回数组中值的和
查询数组中的值
array_search() 查询数组中的值是否存在/in_array()有点相似
排序
sort() 排序有很多种,按键或值升降序
array_multisort() 多维数组排序
分割数组
array_chunk()
le-7改成1e-7,是数字1,不是字母l。
pi的近似计算公式是pi=4(1-1/3+1/5-1/7+),所以上述注释为:
while((fabs(t))>le-7) // 如果1/n小于1e-7,则停止计算。
{ pi=pi+t; // 对照近似计算公式
n=n+2; // 对照近似计算公式
s=-s; // s是用来交替变化+、-号的
t=s/n; // 对照近似计算公式
}
pi=pi4; // 对照近似计算公式
圆周率有无数位数
圆周率(Pi)是圆的周长与直径的比值,一般用希腊字母π表示,是一个在数学及物理学中普遍存在的数学常数。π也等于圆形之面积与半径平方之比。是精确计算圆周长、圆面积、球体积等几何形状的关键值。在分析学里,π可以严格地定义为满足sin x = 0的最小正实数x。
圆周率用希腊字母 π(读作pài)表示,是一个常数(约等于3141592654),是代表圆周长和直径的比值。它是一个无理数,即无限不循环小数。在日常生活中,通常都用314代表圆周率去进行近似计算。而用十位小数3141592654便足以应付一般计算。即使是工程师或物理学家要进行较精密的计算,充其量也只需取值至小数点后几百个位。
1965年,英国数学家约翰·沃利斯(John Wallis)出版了一本数学专著,其中他推导出一个公式,发现圆周率等于无穷个分数相乘的积。
2015年,罗切斯特大学的科学家们在氢原子能级的量子力学计算中发现了圆周率相同的公式。
2021年8月18日,圆周率π计算到小数点后628万亿位,创下该常数迄今最精确值记录。
第一类算法:arctan 的级数展开
PI/4 = 4 arctan(1/5) - arctan(1/239) (1)
arctan(x) = x - x3/3 + x5/5 - x7/7 + (2)
很容易想到,要得到超高精度的 PI 值,实数在计算机中必须以数组的形式进行存取,数组的大小跟所需的有效位数成正比。在这个算法中,PI 的有效位数 n 随 (2) 的求和项数线性增加。而为计算 (2) 中的每一项,需要进行超高精度实数除以小整数(52, 2392, 2k+1)的循环,循环所需次数也跟 n 成正比。所以,这个算法总的时间复杂度为 O(n2)。
这个算法的优点是简单,而且只需要进行整数运算。下面给出我写的算 PI 程序。在程序中,我采用了一些提高速度的措施:超高精度实数以数组的形式进行存取,数组元素的类型为 64 位整数(long long),每个元素储存 12 个十进制位;对 xk (x = 1/5, 1/239) 的头部和尾部的 0 的数量进行估计,只对非 0 的部分进行计算。
picpp C++ 源程序,在 Linux 下以 g++ picpp -o pi -O2 编译
pis 在 g++ 生成的汇编程序的基础上进行修改,速度更快,在 Linux 下以 g++ pis -o pi 编译
另外,还有许多跟 (1) 类似的式子,但不常用。例如:
PI/4 = arctan(1/2) + arctan(1/3)
PI/4 = 8 arctan(1/10) - arctan(1/239) - 4 arctan(1/515)
第二类算法:与 1/PI 有关的级数
1/PI = (sqrt(8) / 9801) sumk=0~inf { [(4k)! (1103 + 26390k)] / [(k!)4 3964k] } (Ramanujan)
1/PI = (sqrt(10005) / 4270934400) sumk=0~inf { [(6k)! (13591409 + 545140134k)] / [(k!)3 (3k)! (-640320)3k] } (Chudnovsky)
以上两个级数(还有其它类似形式的级数,但不常用)比起 arctan 的泰勒级数要复杂得多。虽然仍然是线性收敛,总的时间复杂度也仍然是 O(n2),但它们的收敛速度相当快, (Ramanujan) 每项可以增加 8 位有效数字, (Chudnovsky) 每项可以增加 14 位。
在这个算法中,除了要进行超高精度实数(数组形式)和小整数的运算外,还有一次超高精度实数的开方和倒数的运算,这需要用到 FFT(快速傅立叶变换),在下文叙述。
第三类算法:算术几何平均值和迭代法
算术几何平均值(Arithmetic-Geometric Mean, AGM) M(a, b) 定义如下:
a0 = a, b0 = b
ak = (ak-1 + bk-1) / 2, bk = sqrt(ak-1 bk-1)
M(a, b) = limk->inf ak = limk->inf bk
然后,由椭圆积分的一系列理论(抱歉,过程我不懂)可以推导出如下公式:
a0 = 1, b0 = 1 / sqrt(2)
1/PI = { 1 - sumk=0~inf [2k (ak2 - bk2)] } / 2M(a0, b0)2 (AGM)
根据这条公式可以制定适当的迭代算法。在迭代过程中,有效位数随迭代次数按 2 的指数增加,即每迭代一次有效位数乘 2。算法中的超高精度实数的乘、除、开方等运算需要使用 FFT,在下文叙述。综合考虑 FFT 的时间复杂度,整个算法的时间复杂度约为 O(n log(n)2)。
除了 (AGM) 以外,还有其它的迭代序列,它们具有同样的时间复杂度。例如下面的这个序列将按 4 的指数收敛到 1/PI:
y0 = sqrt(2) - 1, a0 = 6 - 4 sqrt(2)
yk = [1 - sqrt(sqrt(1 - yk-14))] / [1 + sqrt(sqrt(1 - yk-14))], ak = (1 + yk)4 ak-1 - 22k+1 yk (1 + yk + yk2)
1/PI = limk->inf ak (Borwein)
FFT
如上所述,第二和第三类算法不可避免地要涉及超高精度实数(数组形式存取的多位数)的乘、除、开方等运算。多位数乘法如果按照常规方法来计算,逐位相乘然后相加,其时间复杂度将达到 O(n2)。使用 FFT 可大大减少计算量。
设有复数数组 a[k] 和 b[k] (k=0~n-1),正向和反向的离散傅立叶变换(DFT)定义如下: (i = sqrt(-1))
b = FFTforward(a) : b[k] = sumj=0~n-1 ( a[j] e-ij2PIk/n ) (3)
b = FFTbackward(a) : b[k] = (1/n) sumj=0~n-1 ( a[j] eij2PIk/n ) (4)
(3) 和 (4) 中的 (1/n) 可以放在任何一个式子中,也可以拆成 (1/sqrt(n)) 同时放在两个式子中,目的是保证正向和反向傅立叶变换以后不会相差一个因子。
当 n 的所有素因子均为小整数,尤其是当 n 为 2 的整数次幂的时候,使用适当的算法经过仔细的协调,可以避免多余的计算,使离散傅立叶变换 (3) 和 (4) 减少至 O(n log(n)) 的时间复杂度,即所谓的快速傅立叶变换(FFT)。具体的细节请查阅相关书籍。下面给出我写的一段 FFT 程序,仅供参考。另外也有已经开发的 FFT 函数库,例如 FFTW ,可以直接使用。
fftcpp FFT 的 C++ 源程序
利用 FFT,要计算 n1 位和 n2 位的两个多位数乘法,可以这样进行:开辟两个长度为 n(n>=n1+n2,取 2m 最佳) 的复数数组,将两个多位数从低位到高位分别填入,高位补 0。对两个数组分别进行正向傅立叶变换。将得到的两个变换后的数组的对应项相乘,然后进行反向傅立叶变换,最后得到一个结果数组。由于傅立叶变换是在复数域中进行的,因此还要对结果数组进行取整和进位,才能得到最终的乘积。
值得留意的是傅立叶变换的精度问题。我们知道,在计算机中实数用单精度数或双精度数表示,它们会存在一定的误差。在计算多位数乘法时,n 往往是一个很大的数字,傅立叶变换过程中需要对数组的每一项进行求和,如何保证精度带来的误差不会因为求和而超出允许的范围?我的观点是必须使用双精度实数,而且由于统计特性,精度带来的误差在求和过程中不会很大,一般不会影响计算的正确性。如果需要保证计算的正确性,我想到两种检查方法。第一种是取模验算。例如,如果乘数和被乘数对 17 的模分别是 8 和 6,那么积对 17 的模就应该是 14。第二种是检查运算结果中浮点数偏离整数的最大值。如果偏差只有比如 10-3 量级,我们可以认为这个尺度的乘法运算很安全;如果偏差达到 05,说明运算已经出错了;如果偏差达到 01 量级,那也比较危险,也许换个别的乘数和被乘数就溢出了。
多位数的倒数和开方可以通过牛顿迭代求根法转化为乘法运算。例如,要计算 x = 1/a ,根据牛顿迭代法令 f(x) = 1/x - a ,可以得到以下迭代序列:
x0 ~= 1/a
xk = xk-1 - f(xk-1)/f'(xk-1) = 2xk-1 - axk-12 (5)
要计算 x = sqrt(a) ,可以先计算 x = 1 / sqrt(a) ,令 f(x) = 1/x2 - a ,可以得到以下迭代序列:
x0 ~= 1 / sqrt(a)
xk = xk-1 - f(xk-1)/f'(xk-1) = (3/2)xk-1 - (1/2)axk-13 (6)
(5) 和 (6) 均以 2 的指数收敛到所求结果。还存在其它更复杂一些的迭代序列,它们以更高的指数收敛,在此不提。不过需要提醒的是,跟 (AGM) 不同,这里 (5) 和 (6) 中的 x0 只是 1/a 和 1 / sqrt(a) 的约值,在前几次的迭代中不必进行满 n 位数的乘法运算,因而可以减少计算量。
圆周率的计算方法
古人计算圆周率,一般是用割圆法。即用圆的内接或外切正多边形来逼近圆的周长。Archimedes用正96边形得到圆周率小数点后3位的精度;刘徽用正3072边形得到5位精度;Ludolph Van Ceulen用正262边形得到了35位精度。这种基于几何的算法计算量大,速度慢,吃力不讨好。随着数学的发展,数学家们在进行数学研究时有意无意地发现了许多计算圆周率的公式。下面挑选一些经典的常用公式加以介绍。除了这些经典公式外,还有很多其它公式和由这些经典公式衍生出来的公式,就不一一列举了。
1、 Machin公式
[这个公式由英国天文学教授John Machin于1706年发现。他利用这个公式计算到了100位的圆周率。Machin公式每计算一项可以得到14位的十进制精度。因为它的计算过程中被乘数和被除数都不大于长整数,所以可以很容易地在计算机上编程实现。
Machinc 源程序
还有很多类似于Machin公式的反正切公式。在所有这些公式中,Machin公式似乎是最快的了。虽然如此,如果要计算更多的位数,比如几千万位,Machin公式就力不从心了。下面介绍的算法,在PC机上计算大约一天时间,就可以得到圆周率的过亿位的精度。这些算法用程序实现起来比较复杂。因为计算过程中涉及两个大数的乘除运算,要用FFT(Fast Fourier Transform)算法。FFT可以将两个大数的乘除运算时间由O(n2)缩短为O(nlog(n))。
2、 Ramanujan公式
1914年,印度数学家Srinivasa Ramanujan在他的论文里发表了一系列共14条圆周率的计算公式,这是其中之一。这个公式每计算一项可以得到8位的十进制精度。1985年Gosper用这个公式计算到了圆周率的17,500,000位。
1989年,David & Gregory Chudnovsky兄弟将Ramanujan公式改良成为:
这个公式被称为Chudnovsky公式,每计算一项可以得到15位的十进制精度。1994年Chudnovsky兄弟利用这个公式计算到了4,044,000,000位。Chudnovsky公式的另一个更方便于计算机编程的形式是:
3、AGM(Arithmetic-Geometric Mean)算法
Gauss-Legendre公式:
这个公式每迭代一次将得到双倍的十进制精度,比如要计算100万位,迭代20次就够了。1999年9月Takahashi和Kanada用这个算法计算到了圆周率的206,158,430,000位,创出新的世界纪录。
4、Borwein四次迭代式:
这个公式由Jonathan Borwein和Peter Borwein于1985年发表,它四次收敛于圆周率。
这个公式简称BBP公式,由David Bailey, Peter Borwein和Simon Plouffe于1995年共同发表。它打破了传统的圆周率的算法,可以计算圆周率的任意第n位,而不用计算前面的n-1位。这为圆周率的分布式计算提供了可行性。1997年,Fabrice Bellard找到了一个比BBP快40%的公式:
以上就是关于圆周率是怎么求出来的后面的详细数字是什么全部的内容,包括:圆周率是怎么求出来的后面的详细数字是什么、PHP的常用系统函数有哪些、php 计算经纬度之间相差多少公里等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)