javarecursionbigintegerbigdecimalbernoulli-numbers

Java- Implementation of Bernoulli Numbers in new method


I am having trouble editing an existing implementation of Bernoulli numbers in Java which has the BigRational helper class. The original implementation puts the calculation of the Bernoulli numbers inside the Main method. I made a new class to return the calculation for individual Bernoulli numbers. What am I doing wrong?

import java.math.BigInteger;

public class Bernoulli {

    public static void main(String[] args) {
        int N = 20;
        System.out.println(bern(N));

    }

    public static BigRational bern(int N) {
        BigInteger[][] binomial = new BigInteger[N+1][N+1];
        for (int n = 1; n <= N; n++) binomial[0][n] = BigInteger.ZERO;
        for (int n = 0; n <= N; n++) binomial[n][0] = BigInteger.ONE;
        for (int n = 1; n <= N; n++)
            for (int k = 1; k <= N; k++)
                binomial[n][k] = binomial[n-1][k-1].add(binomial[n-1][k]);

        BigRational[] bernoulli = new BigRational[N+1];
        bernoulli[0] = new BigRational(1, 1);
        bernoulli[1] = new BigRational(-1, 2);
        for (int k = 2; k < N; k++) {
            bernoulli[k] = new BigRational(0, 1);
            for (int i = 0; i < k; i++) {
                BigRational coef = new BigRational(binomial[k + 1][k + 1 - i], 
                        BigInteger.ONE);
                bernoulli[k] = bernoulli[k].minus(coef.times(bernoulli[i]));
            }
            bernoulli[k] = bernoulli[k].divides(new BigRational(k+1, 1));
        }
        return bernoulli[N];
    }
}

I am looking to do this in order to calculate the Zeta function for even numbers.

enter image description here

A Test method that I created calculates the denominator of this equation through BigDecimal. I see an upcoming problem, would I need to convert the Bernoulli BigRational into a BigDecimal? I will likely need to adjust the BigRational class I found.

import java.math.BigDecimal;
import java.math.BigInteger;

public class Test {
    public static void main(String[] args) {
        int N = Integer.parseInt("20");

        // precompute binomial coefficients
        BigInteger[][] binomial = new BigInteger[N+1][N+1];
        for (int n = 1; n <= N; n++) binomial[0][n] = BigInteger.ZERO;
        for (int n = 0; n <= N; n++) binomial[n][0] = BigInteger.ONE;

        // bottom-up dynamic programming
        for (int n = 1; n <= N; n++)
            for (int k = 1; k <= N; k++)
                binomial[n][k] = binomial[n-1][k-1].add(binomial[n-1][k]);


        // now compute Bernoulli numbers
        BigRational[] bernoulli = new BigRational[N+1];
        bernoulli[0] = new BigRational(1, 1);
        bernoulli[1] = new BigRational(-1, 2);
        for (int k = 2; k < N; k++) {
            bernoulli[k] = new BigRational(0, 1);
            for (int i = 0; i < k; i++) {
                BigRational coef = new BigRational(binomial[k + 1][k + 1 - i], 
                        BigInteger.ONE);
                bernoulli[k] = bernoulli[k].minus(coef.times(bernoulli[i]));
            }
            bernoulli[k] = bernoulli[k].divides(new BigRational(k+1, 1));
        }
        BigDecimal n = new BigDecimal(6);
        BigDecimal two = new BigDecimal(2);
        System.out.println(fac(n).multiply(two));
        System.out.println("\u03A0^2");


    }

    public static BigDecimal fac(BigDecimal n) {
        if (n.equals(BigDecimal.ZERO)) {
            return BigDecimal.ONE;
        }
        return n.multiply(fac(n.subtract(BigDecimal.ONE)));
    }

}

Solution

  • Alternative solution

    import java.math.BigDecimal;
    import java.math.BigInteger;
    import java.util.Vector;
    import org.apache.commons.math3.fraction.BigFraction;
    
    /* Generates the Bernoulli number, B_n, by a double sum.
         * @param n The index of the Bernoulli number.
         * @return The Bernoulli number at n.
         */
        private static BigFraction bernoulli(int n) {
            BigFraction result = BigFraction.ZERO;
            for (int k = 0; k <= n; k++) {
                BigFraction jSum = BigFraction.ZERO;
                BigInteger bInt = BigInteger.ONE;
                for (int j = 0; j <= k; j++) {
                    BigInteger jPowN = (new BigInteger("" + j))
                            .pow(n);
                    if (j % 2 == 0) {
                        jSum = jSum.add(bInt.multiply(jPowN));
                    } else {
                        jSum = jSum.subtract(bInt.multiply(jPowN));
                    }
    
                    /* update binomial(k,j) recursively
                     */
                    bInt = bInt.multiply(new BigInteger("" + (k - j))).
                            divide(new BigInteger("" + (j + 1)));
                }
                result = result.add(jSum.divide(new BigInteger("" + (k + 1)))
                );
            }
            return result;
        }