challenge exp(pi * sqrt(n))が整数に近くなるnを探す

1以上200未満の整数nのうち、 exp(pi * sqrt(n))がほとんど整数であるようなnを求めるコードを書いてください。 なお、expは底がeである指数関数 - Wikipedia、 piは円周率、sqrtは平方根です。また「ほとんど整数である」とは 整数からプラスマイナス0.0001の範囲にあることとします。

Pythonで34行のスクリプトを書いて得られた出力の例が下のようになります。

37 199148647.999978
58 24591257752.000000
67 147197952743.999999
163 262537412640768744.000000 
この問題は光成さんに教えて頂いた e^{π*sqrt{163}}≒26253741640768744 が元になっています。ご協力ありがとうございました。

Posted feedbacks - Java

強引に解いてみました。BigDecimalを使用していますがライブラリがないので自前で計算しています。expの計算方法が非効率的なので非常に時間がかかります(苦笑)。
 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import java.math.BigDecimal;
import java.math.MathContext;

public class Sample {
    private static final double EPS = 0.000001;
    private static final double EPS2 = 1e-25;
    private static final BigDecimal TWO = new BigDecimal(2);
    private static final BigDecimal PI = new BigDecimal
        ("3.1415926535897932384626433");
    public static BigDecimal exp(BigDecimal x) {
        int i = 1;
        BigDecimal b = new BigDecimal(i++);
        BigDecimal c = x;
        BigDecimal a = new BigDecimal(1.0);
        BigDecimal d;
        while ((d = c.divide(b, MathContext.DECIMAL128)).doubleValue() > EPS) {
            a = a.add(d);
            b = b.multiply(new BigDecimal(i++));
            c = c.multiply(x);
        }
        return a;
    }

    public static BigDecimal sqrt(BigDecimal a) {
        BigDecimal x = new BigDecimal(10);
        BigDecimal delta;
        do {
            delta = (x.multiply(x).subtract(a)).divide(TWO.multiply(x), 
                                                       MathContext.DECIMAL128);
            x = x.subtract(delta);
        } while (delta.abs().doubleValue() > EPS2);
        return x;
    }

    public static void main(String[] args) {
        for (int i = 1; i < 200; i++) {
            BigDecimal er = exp(PI.multiply(sqrt(new BigDecimal(i))));
            BigDecimal rer = new BigDecimal(er.toBigInteger());
            double a = er.subtract(rer).doubleValue();
            if (a < 0.0001 || a > 0.9999) {
                System.out.printf("%d: %f%n", i, er);
            }
        }
    }
}

expの計算の効率を上げる事で、なんとか実用(?)的な性能にする事ができました。

x = n log 10 + k の時
    exp(x) = 10^n * exp(k)
の性質を使っています。
 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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import java.math.BigDecimal;
import java.math.MathContext;

public class Sample {
    private static final double EPS = 0.000001;
    private static final double EPS2 = 1e-25;
    private static final BigDecimal TWO = new BigDecimal(2);
    private static final BigDecimal PI = new BigDecimal
        ("3.141592653589793238462643383279");
    private static final BigDecimal LN10 = new BigDecimal
        ("2.3025850929940456840179914546844");
    public static BigDecimal exp(BigDecimal x) {
        BigDecimal[] dr = x.divideAndRemainder(LN10);
        int n = dr[0].intValue();
        x = dr[1];
        int i = 1;
        BigDecimal b = new BigDecimal(i++);
        BigDecimal c = x.scaleByPowerOfTen(n);;
        BigDecimal a = new BigDecimal(1.0).scaleByPowerOfTen(n);
        BigDecimal d;
        while ((d = c.divide(b, MathContext.DECIMAL128)).doubleValue() > EPS) {
            a = a.add(d);
            b = b.multiply(new BigDecimal(i++));
            c = c.multiply(x);
        }
        return a;
    }

    public static BigDecimal sqrt(BigDecimal a) {
        BigDecimal x = new BigDecimal(Math.sqrt(a.doubleValue()));
        BigDecimal delta;
        do {
            delta = (x.multiply(x).subtract(a)).divide(TWO.multiply(x), 
                                                       MathContext.DECIMAL128);
            x = x.subtract(delta);
        } while (delta.abs().doubleValue() > EPS2);
        return x;
    }

    public static void main(String[] args) {
        for (int i = 1; i < 200; i++) {
            BigDecimal er = exp(PI.multiply(sqrt(new BigDecimal(i))));
            BigDecimal rer = new BigDecimal(er.toBigInteger());
            double a = er.subtract(rer).doubleValue();
            if (a < 0.0001 || a > 0.9999) {
                System.out.printf("%d: %f%n", i, er);
            }
        }
    }
}

Index

Feed

Other

Link

Pathtraq

loading...