LeetCode:計算PI後面的100位小數點
阿新 • • 發佈:2019-01-01
首先,這個題目是以前讀書時候競賽上出現的一道題目,當時沒有做出來,我只是知道思路,因為數太大沒計算出現;最近剛好複習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