1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

arctanのBigDecimal計算

Posted at

前回のπの記事で、
@zacky1972 様にコメントを頂きました。

上記の、arctan系公式 を教えてもらいました。

ストマーの公式

44 * arctan( 1/57) + 7 * arctan( 1/239 ) - 12 * arctan( 1/682 ) + 24 * arctan( 1/12943 )

前回の記事では、ストマーの公式の一番左の項を気にしていましたが、
上記の「arctan系公式」ので、解決策が見えたので、第2項の
arctan( 1/239 )で、桁数を増やした時の性能を測ってみました。

計測に使ったプログラム

package calcpi;

import java.math.BigDecimal;
import java.math.MathContext;

public class Arctan1 {

    static MathContext mi = new MathContext(40000); // (1)

    static BigDecimal limit;
    /*
    *   arctan の求め方
    *   https://math-fun.net/20211121/20366/#google_vignette
    */
    static BigDecimal arctan(BigDecimal arg) {

        BigDecimal accum = arg;
        BigDecimal bunshi = arg;
        BigDecimal square = arg.multiply(arg, mi);
        BigDecimal bunbo = new BigDecimal("3");
        BigDecimal two = new BigDecimal("2");

        boolean minus = true;
        int i = 0;
        for (;; i++) {

            bunshi = bunshi.multiply(square, mi);
            
            BigDecimal kou = bunshi.divide(bunbo, mi);
            

            if (kou.compareTo(limit) < 0) {
                break;
            }

            if (minus) {
                accum = accum.subtract(kou, mi);
            } else {
                accum = accum.add(kou, mi);
            }
            bunbo = bunbo.add(two, mi);
            minus = !minus;
        }
        System.out.println("i = " + i );  // (3)
        return accum;
    }

    public static void main(String[] args) throws InterruptedException {

        BigDecimal stop = new BigDecimal("1");
        
        for (int i = 0; i < 40000; i++) { // (2)
     //       stop = stop.divide(new BigDecimal("10"), mi);
            stop = stop.multiply(new BigDecimal("0.1"), mi);
        }
        limit = stop;
        System.out.println("----- sleep -----");
        
        Thread.sleep(9000);

        System.out.println("----- start -----");
        
        BigDecimal one = new BigDecimal("1");

        BigDecimal d239 = one.divide(new BigDecimal("239"), mi);
        
        long start = System.currentTimeMillis();
        
        BigDecimal atan239 = arctan(d239);

        long end = System.currentTimeMillis();

        
        System.out.println("time in millis =" + (end - start));
        
        Thread.sleep(3000);

        System.out.println("----- end -----");
    }

}

(1) と (2) の値を、1万、2万、3万、4万と変えて計測してみました。

PC は CPUがM1 の Mac Book Air で、メモリは8GBです。
Javaは17です。

測定結果

桁数 iの表示値 秒数
1万桁 2,100 3.7
2万桁 4,203 18.6
3万桁 6,305 47.9
4万桁 8,407 107.1

「iの表示値」というのは、プログラム中の(3)の表示で、arctanの計算を何項まで計算したか(ループ回数)です。

メモリ使用量

VisualVMというツールで、表示してみました。
(このツールは、最近使い始めたので、使い方がよくわかっていません)

Arctan.jpg

右上のグラフを見ると、ガーベージコレクションを何回もしているように、思えます。

プログラム中に Thread.sleepと書いているのは、この VisualVMというツールを使うためです。
(プログラムの本質には関係ありません)

わかった事

BigDecimalの割り算は結構時間がかかる。(かなり遅い)

public static void main(String[] args) throws InterruptedException {

    BigDecimal stop = new BigDecimal("1");
        
    for (int i = 0; i < 40000; i++) {
    //       stop = stop.divide(new BigDecimal("10"), mi); // (4)
        stop = stop.multiply(new BigDecimal("0.1"), mi); //(5)
    }
    limit = stop;


前回のπの記事では、(4)のようにしていました。
しかし10で割っていく(divide)のは、めちゃくちゃ時間が、かかります。
仕方ないので、(5)のように、0.1を掛け算する事にしました。

これから類推すると、arctanの中にも1箇所、divideを使っていますので、
ここをうまく書き換えると、もっとスピードが上がると思われます。

    static BigDecimal arctan(BigDecimal arg) {

        BigDecimal accum = arg;
        BigDecimal bunshi = arg;
        BigDecimal square = arg.multiply(arg, mi);
        BigDecimal bunbo = new BigDecimal("3");
        BigDecimal two = new BigDecimal("2");

        boolean minus = true;
        int i = 0;
        for (;; i++) {

            bunshi = bunshi.multiply(square, mi);
            
            BigDecimal kou = bunshi.divide(bunbo, mi);//(6)
            

            if (kou.compareTo(limit) < 0) {
                break;
            }

            if (minus) {
                accum = accum.subtract(kou, mi);
            } else {
                accum = accum.add(kou, mi);
            }
            bunbo = bunbo.add(two, mi);
            minus = !minus;
        }
        System.out.println("i = " + i );
        return accum;
    }


上記の(6)の行の divide命令です。

( このJavaのプログラムを発展させて、 πの桁数を増やすのは、難しそう、との印象を持ちました)

以上です。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?