计算十六进制的pi,BBP公式的工具

时间:2016-03-16 14:41:19

标签: java double pi

我试图使这个工具正常工作,但未能找到使我的测试单元失败的错误。你能告诉我这个bug可能在哪里吗?我很确定algorithm是对的。

package piwords;

public class PiGenerator {
    /**
     * Returns precision hexadecimal digits of the fractional part of pi.
     * Returns digits in most significant to least significant order.
     * 
     * If precision < 0, return null.
     * 
     * @param precision The number of digits after the decimal place to
     *                  retrieve.
     * @return precision digits of pi in hexadecimal.
     */
    public static int[] computePiInHex(int precision) {
        // TODO: Implement (Problem 1.d)
        int [] b = new int [precision];
        for (int a = 0; a < precision; a++) {
            b[a] = piDigit( a + 1 );
        }
        return b;
    }

    /**
     * Computes a^b mod m
     * 
     * If a < 0, b < 0, or m < 0, return -1.
     * 
     * @param a
     * @param b
     * @param m
     * @return a^b mod m
     */
    public static int powerMod(int a, int b, int m) {
        // TODO: Implement (Problem 1.b)
        if (( a > 0 ) && ( b > 0 ) && ( m > 0 )) {
            Double t = new Double(0);
            t = Math.pow(a, b);
            Double re = new Double( t % m );
            return re.intValue();
        }
        return -1;
    }

    /**
     * Computes the nth digit of Pi in base-16.
     * 
     * If n < 0, return -1.
     * 
     * @param n The digit of Pi to retrieve in base-16.
     * @return The nth digit of Pi in base-16.
     */
    public static int piDigit(int n) {
        if (n < 0) return -1;

        n -= 1;
        double x = 4 * piTerm(1, n) - 2 * piTerm(4, n) -
                   piTerm(5, n) - piTerm(6, n);
        x = x - Math.floor(x);

        return (int)(x * 16);
    }

    private static double piTerm(int j, int n) {
        // Calculate the left sum
        double s = 0;
        for (int k = 0; k <= n; ++k) {
            int r = 8 * k + j;
            s += powerMod(16, n-k, r) / (double) r;
            s = s - Math.floor(s);
        }

        // Calculate the right sum
        double t = 0;
        int k = n+1;
        // Keep iterating until t converges (stops changing)
        while (true) {
            int r = 8 * k + j;
            double newt = t + Math.pow(16, n-k) / r;
            if (t == newt) {
                break;
            } else {
                t = newt;
            }
            ++k;
        }

     //   return s+t;   // little bug, should be as following
        return ( ( s + t ) - Math.floor( s + t ) );
    }
}

=============================================== ====================

这是我的test课程

=============================================== ===================

package piwords;

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.experimental.theories.suppliers.TestedOn;

public class PiGeneratorTest {
    @Test
    public void basicPowerModTest() {
        // 5^7 mod 23 = 17
        assertEquals(17, PiGenerator.powerMod(5, 7, 23));
        assertEquals(44, PiGenerator.powerMod(11, 5, 51));
    }

    // TODO: Write more tests (Problem 1.a, 1.c)
    @Test
    public void testComputePiInHex() {
        int[] a = {2, 4, 3, 15, 6};
        assertArrayEquals(a, PiGenerator.computePiInHex(5));
    }
}

1 个答案:

答案 0 :(得分:1)

您应该将b > 0更改为b >= 0,然后结果似乎没问题 请注意,对于较大的值,您不能依赖pow中的双数(powerMod},因为它们的精度有限。你应该使用整数并使用这个相等:

  

a ^(b + c)mod m =(a ^ b mod m)*(a ^ c mod m)mod m