Machin formula /梅钦公式

梅钦公式( Machin formula )是一个计算 π 值的公式,至今仍被广泛应用,本文介绍如何使用计算机实现它。

π 的简史

四千年前,巴比伦人用 3+ 1/8 作为圆周率, 同时期的埃及人用 4-(8/9)^2 做圆周率;

三千年前,中国先人用3 作为圆周率;

公元前三世纪,古希腊科学家阿基米德首先采用计算的方法,得出 π 可能是  3.14;

公元五世纪,我国数学家祖冲之把 π 算到了 3.1415926 到 3.1415927 之间;

公元 15 世纪, 阿拉伯数学家阿尔·卡西 (Al-Kāshī,1380?– 1429),用几何的方法,计算到了小数点后 16 位;

1666 年, 牛顿用自己设计的公式把 计算到了小数点后的15位,这个公式的收敛速度非常慢,我猜想他可能花了几个月,甚至几年干这事儿。

1706年,英国人 约翰·梅钦( John Machin) 发明了一个用于计算 π 值的公式。

1873 年, William Shanks 使用梅钦公式用了几年时间,计算到了 小数点后的 707 位。

20世纪30年代, 人们( 新西兰的数学家艾特肯(Aitken)教授 )才开始怀疑 Shanks 犯了一个错误。事实上,他在第528位犯了一个错误,所以剩下的180位数是错误的。

1949年,ENIAC(Electronic Numerical Integrator And Computer, 电子数字积分计算机)计算机用了70个小时,计算到了 小数点后的2037位。

近年来,被到了小数点后的1.24万亿位。

简介

虽然印度人拉马努金( Srinivasa Ramanujan ) 整了一堆如何计算 π 的公式,还有了 BBP ( Bailey- Borwein -Plouffe,   David Bailey / Peter Borwein / Simon Plouffe  )公式, 以及其他若干种类梅钦(Machin-like)公式,但梅钦公式至今仍然是计算 π 值的主要公式。

我已建立了百度词条 “梅钦公式”,请自行查看它是什么样的,因为:这里无法发数学公式。

梅钦公式是格里高利/莱布尼茨计算 公式的变体,但是更实用,它的收敛速度显著增加,这使得它成为了更实用的计算π的方法。

实现

多种编程语言可实现使用梅钦公式计算  π 小数点后任意精度的值,这里给出一种 JavaScript 实现:

/*
* @Author: coolwp.com
* @Date:   2017-08-22 05:40:48
* @Last Modified by:   suifengtec
* @Last Modified time: 2017-08-23 03:24:11
**/
/*
用JavaScript 和 梅钦公式计算 PI。

使用

node pi.js

 */
var getPi = (function () {
    function getPi(space) {

        this.aX = [];
        this.cellSize = 11;
   
        this.tStart = new Date();
        this.spaceStr = space ? space : "  ";

        this.aBigInt = Math.pow(10, this.cellSize);
    }

    getPi.prototype.getIt = function (length) {

        var digitsLenAfterDot = Number(length);

        var cellSize = this.cellSize;

        var coeff = Array(10), 

        iAng = Array(10);

        var arrLen = Math.ceil(1 + digitsLenAfterDot / cellSize);

        var aPI = Array(arrLen);

        var aArctan = Array(arrLen);

        coeff[0] = 4;
        coeff[1] = -1;
        coeff[2] = 0;
        iAng[0] = 5;
        iAng[1] = 239;
        iAng[2] = 0;
        aPI = this.makeArr(arrLen, aPI, 0);
        for (var i = 0; coeff[i] != 0; i++) {
            aArctan = this.getArcTan(iAng[i], arrLen, aArctan);
            aArctan = this.Mul(arrLen, aArctan, Math.abs(coeff[i]));
            if (coeff[i] > 0) {
                aPI = this.Add(arrLen, aPI, aArctan);
            }
            else {
                aPI = this.Sub(arrLen, aPI, aArctan);
            }
        }

        aPI = this.Mul(arrLen, aPI, 4);

        var sPI = "3.";
  
        var tempPI = "";

        for (var i = 0; i < aPI.length; i++) {
            aPI[i] = String(aPI[i]);
            if (aPI[i].length < cellSize && i != 0) {
                while (aPI[i].length < cellSize) {
                    aPI[i] = "0" + aPI[i];
                }
            }
            tempPI += aPI[i];
        }
        for (var i = 0; i + 1 <= digitsLenAfterDot; i++) {
            if (i == 0) {
                sPI += tempPI.charAt(i + 1);
            }
            else {
                var newLineSymbol = this.spaceStr, spForPer5Digits = this.spaceStr;
                if ((i + 1) % 50 == 0 && i != 0) {
                    sPI += tempPI.charAt(i + 1) + newLineSymbol;
                }
                else {
                    if ((i + 1) % 5 == 0) {
                        sPI += tempPI.charAt(i + 1) + spForPer5Digits;
                    }
                    else {
                        sPI += tempPI.charAt(i + 1);
                    }
                }
            }
        }
        var tShutdown = new Date();
        var timeTaken = (tShutdown.getTime() - this.tStart.getTime()) / 1000;
        var timeSp = "耗时: " + timeTaken + " 秒";
        return sPI + " \n" + timeSp;
    };

    getPi.prototype.Mul = function (n, aX, iMult) {
        var carry = 0;
        var prod;
        for (var i = n - 1; i >= 0; i--) {
            prod = (aX[i]) * iMult;
            prod += carry;
            if (prod >= this.aBigInt) {
                carry = Math.floor(prod / this.aBigInt);
                prod -= (carry * this.aBigInt);
            }
            else {
                carry = 0;
            }
            aX[i] = prod;
        }
        return aX;
    };
    getPi.prototype.Div = function (n, aX, iDiv, aY) {
        var carry = 0;
        var currVal;
        var theDiv;
        for (var i = 0; i < n; i++) {
            currVal = Number(aX[i]) + Number(carry * this.aBigInt);
            theDiv = Math.floor(currVal / iDiv);
            carry = currVal - theDiv * iDiv;
            aY[i] = theDiv;
        }
        return aY;
    };
    getPi.prototype.Add = function (n, aX, aY) {
        var carry = 0;
        for (var i = n - 1; i >= 0; i--) {
            aX[i] += Number(aY[i]) + Number(carry);
            if (aX[i] < this.aBigInt) {
                carry = 0;
            }
            else {
                carry = 1;
                aX[i] = Number(aX[i]) - Number(this.aBigInt);
            }
        }
        return aX;
    };
    getPi.prototype.Sub = function (n, aX, aY) {
        for (var i = n - 1; i >= 0; i--) {
            aX[i] -= aY[i];
            if (aX[i] < 0) {
                if (i > 0) {
                    aX[i] += this.aBigInt;
                    aX[i - 1]--;
                }
            }
        }
        return aX;
    };
    getPi.prototype.isEmpty = function (aX) {
        var empty = true;
        for (var i = 0; i < aX.length; i++) {
            if (aX[i]) {
                empty = false;
                break;
            }
        }
        return empty;
    };

    getPi.prototype.getArcTan = function (iAng, n, aX) {
        var iAng_squared = iAng * iAng;
        var k = 3;
        var sign = 0;
        var arrAngle = [];
        var aDivK = [];

        aX = this.makeArr(n, aX, 0); 
        arrAngle = this.makeArr(n, arrAngle, 1);

        arrAngle = this.Div(n, arrAngle, iAng, arrAngle);
        aX = this.Add(n, aX, arrAngle);
        while (!this.isEmpty(arrAngle)) {
            arrAngle = this.Div(n, arrAngle, iAng_squared, arrAngle); 
          
            aDivK = this.Div(n, arrAngle, k, aDivK); 
            if (sign) {
                aX = this.Add(n, aX, aDivK); 
            }
            else {
                aX = this.Sub(n, aX, aDivK);
            }
            k += 2;
            sign = 1 - sign;
        }
        return aX;
    };

    getPi.prototype.makeArr = function (n1, arr, n2) {
        for (var i = 0; i < n1; i++) {
            arr[i] = null;
        }
        arr[0] = n2;
        return arr;
    };
    return getPi;
}());
/*
tsc pi.ts && node pi.js

验证
3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510 58209 74944 59230 78164 06286 20899 86280 34825 34211 70679
计算所得(小数点后100位)
3.14159 26535 89793 23846 26433 83279 50288 41971 69399 37510 58209 74944 59230 78164 06286 20899 86280 34825 34211 70679
耗时: 0.001 秒
 */
var spaceSymbol = "  ";
var app = new getPi(spaceSymbol);
var pi = app.getIt(100);
console.log(pi);

把上述代码保存到文件 pi.js, 即可在 HTML 中引用,或者使用 Node.js 查看:

node pi.js

本文首发酷威普和51CTO,转载请注明。

时间: 2024-07-30 16:39:52

Machin formula /梅钦公式的相关文章

如何在Python上实现用文本进度条体现π的计算过程

---恢复内容开始--- 学习有一段时间的Python了,但目前我的编程能力尚未有较大的提高,因此,我找来了一个有关标题的源代码 这段代码采用的算法是梅钦公式,也就是π=圆周长/直径或π=圆面积/半径的平方 上述代码的运行结果如下图: 该方法是没有安装tqdm库的方法,而关于安装了tqdm库的方法我会在后续的博客中接着更新^_^ 原文地址:https://www.cnblogs.com/wumaiqiti1020/p/10568828.html

带有进度条的圆周率计算

圆周率的计算 计算公式:pi / 4=1 - 1/3 + 1/5 - 1/7 + 1/9 ...... 梅钦公式:pi /4 = 4arctan1/5 - arctan1/239 n=圆周长/直径 n=圆面积/半径平方 import math import time scale=10 print("执行开始") t=time.process_time() for i in range(scale+1): a,b='**'*i,'..'*(scale-i) c=(i/scale)*100

7,SFDC 管理员篇 - 数据模型 - 公式和验证 1

1,自定义公式 Customize | Your Object | Fields | Add Fields Field SF的公式和Excel的公式差不多,都是支持各种运算和结果 例1,以opportunity 为例,选择自定义公式的返回类型, 选择文本并填写Field Label 可以填写公式,选择Advanced Formula,填写公式并保存 --------------------------------------------------------------------------

C# 创建、读取Excel公式

对于数据量较大的表格,需要计算一些特殊数值时,我们通过运用公式能有效提高我们数据处理的速度和效率,对于后期数据的增删改查等的批量操作也很方便.此外,对于某些数值的信息来源,我们也可以通过读取数据中包含的公式来获取.下面的示例中将分享通过C# 来创建.读取Excel公式的方法. 工具使用 Spire.XLS for .NET 8.0下载安装该类库后,注意在程序中添加引用Spire.Xls.dll(dll文件可在安装路径下的Bin文件夹中获取)代码示例(供参考) [示例1]创建Excel公式 C#

应用概率统计模板

apsart.cls 1 % !Mode:: "TeX:UTF-8" 2 %% 3 %% This is file `APSart.cls', 4 %% 5 %% Copyright 2006-2012 6 %% 7 %% ---------------------------------------------------------------------- 8 %% 9 %% It may be distributed and/or modified under the 10 %

解剖被称为「外星人程序」的求PI小程序

|版权声明:本文为博主原创文章,未经博主允许不得转载. 原代码如下: 1 /*某年Obfuscated C Contest佳作选录:*/ 2 long a=10000,b,c=2800,d,e,f[2801],g; 3 main(){for(;b-c;)f[b++]=a/5; 4 for(;d=0,g=c*2;c-=14,printf("%.4d",e+d/a),e=d%a) 5 for(b=c;d+=f[b]*a,f[b]=d%--g,d/=g--,--b;d*=b);} 输出: 3

【转】人工智能基本术语

转自:http://wenku.baidu.com/link?url=Xv5CaxpZTlnuw1riGoE9WXG9dBbMXJvp6cn8CkcLBQA8u6y6tJ7ki4L2vdMlcx1IW19IvZRc1TYMtWsFekqHnzIUouvSUNNiwTXioJZVpVO 人工智能概论中英文术语对照表 动作                         action 专家系统                     Expert system 人工智能语言             

【数据分析 R语言实战】学习笔记 第三章 数据预处理 (下)

3.3缺失值处理 R中缺失值以NA表示,判断数据是否存在缺失值的函数有两个,最基本的函数是is.na()它可以应用于向量.数据框等多种对象,返回逻辑值. > attach(data) The following objects are masked fromdata (pos = 3): city, price, salary > data$salary=replace(salary,salary>5,NA) > is.na(salary) [1] FALSEFALSE TRUE

实现简单的计算器

计算器开发需求 实现加减乘除及拓号优先级解析 用户输入 1 - 2 * ( (60-30 +(-40/5) * (9-2*5/3 + 7 /3*99/4*2998 +10 * 568/14 )) - (-4*3)/ (16-3*2) )等类似公式后,必须自己解析里面的(),+,-,*,/符号和公式,运算后得出结果,结果必须与真实的计算器所得出的结果一致 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27