1. 程式人生 > >LeetCode:計算PI後面的100位小數點

LeetCode:計算PI後面的100位小數點

首先,這個題目是以前讀書時候競賽上出現的一道題目,當時沒有做出來,我只是知道思路,因為數太大沒計算出現;最近剛好複習BigInteger和BigDecimal 的知識,而不能用double,就想到了這個題目;

要求解PI首先要知道他的求解公式:

arctan(x)  =  x − x3/3 + x5/5 − x7/7 + x9/9 − x11/11 + . . .

π  =   12·arctan(1/4) +     4·arctan(1/20) +     4·arctan(1/1985)

就可以根據給出的公式來進行求解:

package gc;

import java.math.BigDecimal;
import java.math.BigInteger;

import org.junit.Test;

/**
*類描述:根據泰勒公式計算PI小數點後面的100位數            計算時間太長,但是自我感覺程式沒有問題
*arctan(x) = x − x3/3 + x5/5 − x7/7 + x9/9 − x11/11 + . . .
*
*π  =12·arctan(1/4)	+4·arctan(1/20)	+4·arctan(1/1985)
*根據此公式計算PI的值
*
*@author: 張宇
*@date: 日期: 2018年9月4日 時間: 下午7:23:05
*@version 1.0
 */
public class ComputePI3 {
	@Test
    public void fun(){
    	BigDecimal integerNumber1=new BigDecimal(12);
    	BigDecimal integerNumber2=new BigDecimal(4);
    	BigDecimal integerNumber3=new BigDecimal(4);
    	
    	BigDecimal decimalNumber1=BigDecimal.ONE.divide(new BigDecimal(4),102,BigDecimal.ROUND_HALF_EVEN);
    	BigDecimal decimalNumber2=BigDecimal.ONE.divide(new BigDecimal(20),102,BigDecimal.ROUND_HALF_EVEN);
    	BigDecimal decimalNumber3=BigDecimal.ONE.divide(new BigDecimal(1985),102,BigDecimal.ROUND_HALF_EVEN);
    	
    	BigDecimal partPI1=integerNumber1.multiply(arctanCompute(decimalNumber1));
    	BigDecimal partPI2=integerNumber2.multiply(arctanCompute(decimalNumber2));
    	BigDecimal partPI3=integerNumber3.multiply(arctanCompute(decimalNumber3));
    	
    	BigDecimal PI=partPI1.add(partPI2).add(partPI3);
    	System.out.println(PI.toString());
    }
    //arctan(x) = x − x3/3 + x5/5 − x7/7 + x9/9 − x11/11 + . . .
	private BigDecimal arctanCompute(BigDecimal decimalNumber) {
		// TODO Auto-generated method stub
		BigDecimal xx=decimalNumber.multiply(decimalNumber);
		BigDecimal x=decimalNumber;
		BigDecimal sum=BigDecimal.ZERO;
		boolean flag=true;
		BigDecimal temp;
		BigDecimal res=BigDecimal.ONE;
		for(int i=1;;i+=2){
			temp=BigDecimal.ONE.divide(new BigDecimal(i),102,BigDecimal.ROUND_HALF_EVEN).multiply(res);
			if(temp.compareTo(BigDecimal.ZERO)==0){
				break;
			}
			
			if(flag){
				sum=sum.add(temp);
				flag=false;
			}else{
				sum=sum.subtract(temp);
				flag=true;
			}		    
			res=res.multiply(xx);			
		}
		    sum=sum.multiply(x);
		return sum;
	}
}

自認為這個方法沒有問題,就是計算時間太長,後面在網上找到了一種效率比較高的方法;

package gc;

import java.math.BigDecimal;
import java.math.BigInteger;
import org.junit.Test;

/**
*類描述:根據泰勒公式計算PI小數點後面的100位數           
*arctan(x) = x − x3/3 + x5/5 − x7/7 + x9/9 − x11/11 + . . .
*
*π  =12·arctan(1/4)	+4·arctan(1/20)	+4·arctan(1/1985)
*根據此公式計算PI的值
*
 */
public class ComputePI4 {
	@Test
    public void fun(){
    	BigDecimal integerNumber1=new BigDecimal(12);
    	BigDecimal integerNumber2=new BigDecimal(4);
    	BigDecimal integerNumber3=new BigDecimal(4);
    	   	
    	BigDecimal partPI1=integerNumber1.multiply(arctanCompute(4));
    	BigDecimal partPI2=integerNumber2.multiply(arctanCompute(20));
    	BigDecimal partPI3=integerNumber3.multiply(arctanCompute(1985));
    	
    	BigDecimal PI=partPI1.add(partPI2).add(partPI3);
    	System.out.println(PI.toString().substring(2,102));
    }
    //arctan(x) = x − x3/3 + x5/5 − x7/7 + x9/9 − x11/11 + . . .
	private BigDecimal arctanCompute(int x) {
		// TODO Auto-generated method stub
		BigDecimal result = BigDecimal.ZERO;
		BigDecimal squreXx = new BigDecimal(x * x);
		BigDecimal decimalX = new BigDecimal(x);
		BigDecimal temp;
		BigDecimal res = BigDecimal.ONE.divide(decimalX, 102,BigDecimal.ROUND_HALF_EVEN);

		boolean flag = true;
		for (int i = 1;; i += 2) {
			temp = res.divide(new BigDecimal(i), 102, BigDecimal.ROUND_HALF_EVEN);
			if (temp.compareTo(BigDecimal.ZERO) == 0) {// 根據萊布尼茲級數結果=0時返回
				break;
			}			
			if (flag) {
				result = result.add(temp);
				flag=false;
				
			} else {
				result = result.subtract(temp);
				flag=true;
			}			
			res = res.divide(squreXx, 102, BigDecimal.ROUND_HALF_EVEN);
		}
		return result;
	}
}

這種方法能很快計算出來PI的後面100位小數:

1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679