1

I have this mathematical expression :

∑(2k+1)/(2k)! , k =0,... ,∞ , it is sum from zero to infinity of all fractions in the form (2k+1)/(2k)!

I want to create a method which when passed an integer "n", it will output me the result with n digits after the decimal point.This expression first 100 digits can be viewed here : https://miniwebtool.com/first-n-digits-of-e/?number=100

Here is my code, what I have attempted

package pi.strategy;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.stream.IntStream;
import java.util.stream.LongStream;

public class Tester {

    public static BigInteger factorial(long k) {
        return LongStream.range(2, k + 1).mapToObj(BigInteger::valueOf).reduce(BigInteger.ONE,
                (current, factSoFar) -> factSoFar.multiply(current));
    }

    protected static BigDecimal strategy(int precision) {


        return IntStream.range(0, precision).mapToObj(i -> computeMember(i, precision + 2))
               .reduce(BigDecimal.ZERO, (current, sumSoFar) -> sumSoFar.add(current));
    }


    static BigDecimal computeMember(int n, int scale) {


        final BigDecimal dominator = new BigDecimal((2 * n) + 1);
        final BigDecimal enumenator = new BigDecimal(factorial(2 * n));
        // System.out.println("Temp Result:" + dominator.divide(enumenator, scale,
        // RoundingMode.HALF_UP));
        BigDecimal res = dominator.divide(enumenator, scale, RoundingMode.HALF_UP);

        return res;



    }

    public static void main(String... args) {
        System.out.println(strategy(6));

    }

}

The problem is that when I add fractions, sometimes they will overflow and create extra digits at the end. In case of strategy(6) , it outputs extra digits 2.71828179 instead of 2.718281

In the case of strategy(5) it outputs wrong answer 2.7182787 instead of 2.71828. Any ideas where is he problem and how can I limit it correctly to output with precision?

Emma
  • 27,428
  • 11
  • 44
  • 69
Mark
  • 23
  • 3
  • Does this answer your question? [Set specific precision of a BigDecimal](https://stackoverflow.com/questions/9482889/set-specific-precision-of-a-bigdecimal) – NotZack Jun 15 '20 at 22:16
  • 1
    Nah not really , I am trying at runtime to stop adding.Imagine if it takes 1 hour to calculate the whole number and you just want the first 5 digits or 10.That is my goal , to stop the computation when we have reached our precision. – Mark Jun 15 '20 at 22:24
  • 1
    If _at runtime to stop adding_ is your goal, you should invest into math. To compute how many terms you need for a given precision, look at the Taylor theorem, specifically at the [estimates for the remainder](https://en.wikipedia.org/wiki/Taylor%27s_theorem#Estimates_for_the_remainder). – user58697 Jun 16 '20 at 00:21

1 Answers1

1

The problem with your code is that the result is being rounded after each step, and so rounding errors are being summed.

You should use a Fraction class (such as the one described here: https://stackoverflow.com/a/474612) and extract the decimal representation at the end of the process.

EDIT

I'm not a Java developer, so I don't have a proper dev environment set up on my machine. I've tried to update your code to use the BigFraction class I linked earlier:

package pi.strategy;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.stream.IntStream;
import java.util.stream.LongStream;

public class Tester {
    public static BigInteger factorial(long k) {
        return LongStream.range(2, k + 1).mapToObj(BigInteger::valueOf).reduce(BigInteger.ONE,
                (current, factSoFar) -> factSoFar.multiply(current));
    }

    protected static BigFraction strategy(int precision) {
        return IntStream.range(0, precision).mapToObj(i -> computeMember(i, precision + 2))
               .reduce(BigFraction.ZERO, (current, sumSoFar) -> sumSoFar.add(current));
    }


    static BigFraction computeMember(int n, int scale) {
        final BigDecimal numerator = new BigDecimal((2 * n) + 1);
        final BigDecimal denominator = new BigDecimal(factorial(2 * n));

        return new BigFraction(numerator, denominator);
    }

    public static void main(String... args) {
        final BigFraction result = strategy(6);
        System.out.println(result);
        System.out.println(result.toBigDecimal());
    }
}

It may be more efficient to refactor this code so that it doesn't use the factorial function or factorials are cached and don't have to be recomputed each time from 1.

didymus
  • 250
  • 2
  • 9