package jp.yucchi.highprecisionpi;
import java.lang.management.ManagementFactory;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class HighPrecisionPi implements Callable<BigDecimal> {
private static final int KETA = 10_000;
private static final int LIMIT_NUMBER = KETA + 2;
private static final int LIMIT_NUMBER2 = KETA ;
private static long startTime;
private static long time;
private final BigDecimal s_q;
private final BigDecimal _limit;
private BigDecimal ss;
public HighPrecisionPi(BigDecimal _limit, BigDecimal ss, BigDecimal s_q) {
this._limit = _limit;
this.ss = ss;
this.s_q = s_q;
}
public static void main(String[] args) {
System.out.println("<--- 円周率計算開始 --->");
startTime = System.nanoTime();
//精度KETA桁 四捨五入で丸める
int setPrecision = KETA;
RoundingMode setRoundingMode = RoundingMode.HALF_UP;
MathContext mc2 = new MathContext(1, setRoundingMode);
MathContext mc = new MathContext(setPrecision, setRoundingMode);
BigDecimal f = BigDecimal.ZERO; // 0
BigDecimal r = BigDecimal.ZERO; // 0
BigDecimal one = BigDecimal.ONE; // 1
BigDecimal two = new BigDecimal(2, mc); //2
BigDecimal n239 = new BigDecimal(239, mc); // 239
BigDecimal sq239 = new BigDecimal(57121, mc); // 239^2
int procs = ManagementFactory.getOperatingSystemMXBean().getAvailableProcessors();
if (procs > 1) {
procs = 2;
}
ExecutorService executor = Executors.newFixedThreadPool(procs);
List<Future<BigDecimal>> futures = new ArrayList<>();
for (int i = 0; i < 2; i++) {
final BigDecimal _limit;
final BigDecimal ss;
final BigDecimal s_q;
if (i > 0) {
_limit = new BigDecimal(LIMIT_NUMBER, mc);
ss = new BigDecimal(0.2, mc2); // 1 / 5
s_q = new BigDecimal(0.04, mc2); // 1 / 25
} else {
_limit = new BigDecimal(LIMIT_NUMBER2, mc);
ss = one.divide(n239, mc); // 1 / 239
s_q = one.divide(sq239, mc); // 1 / 57121
}
futures.add(executor.submit(new HighPrecisionPi(_limit, ss, s_q)));
}
try {
f = futures.get(1).get().multiply(new BigDecimal(16, mc));
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(HighPrecisionPi.class.getName()).log(Level.SEVERE, null, ex);
}
try {
r = futures.get(0).get().multiply(new BigDecimal(4, mc));
} catch (InterruptedException | ExecutionException ex) {
Logger.getLogger(HighPrecisionPi.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("\n" + KETA + "桁の円周率は、\n" + f.subtract(r, mc));
time = System.nanoTime() - startTime;
System.out.println("\n" + KETA + "桁の円周率計算時間は、"
+ (int) (time * 1e-9) / 3_600 + "時間"
+ (int) ((time * 1e-9) / 60) % 60 + "分"
+ (int) (time * 1e-9 % 60) + "秒"
+ Double.toString((time * 1e-9 % 60) % 1).substring(2) + "\n");
System.out.println("<--- 円周率計算終了 --->");
executor.shutdown();
}
@Override
public BigDecimal call() throws Exception {
int setPrecision = KETA;
RoundingMode setRoundingMode = RoundingMode.HALF_UP;
MathContext mc = new MathContext(setPrecision, setRoundingMode);
MathContext mc2 = new MathContext(1, setRoundingMode);
BigDecimal fr = BigDecimal.ZERO; // 0
BigDecimal p2 = BigDecimal.ZERO; // 0
BigDecimal one = BigDecimal.ONE; // 1
BigDecimal two = new BigDecimal(2, mc); //2
for (int i = 0; p2.compareTo(_limit) < 0; i++) {
BigDecimal bi = new BigDecimal(i, mc);
fr = fr.add(ss.divide((bi.multiply(two).add(one)), mc));
ss = ss.multiply(s_q, mc).negate();
p2 = p2.add(one);
}
return fr;
}
}