Example usage for java.math BigDecimal round

List of usage examples for java.math BigDecimal round

Introduction

In this page you can find the example usage for java.math BigDecimal round.

Prototype

public BigDecimal round(MathContext mc) 

Source Link

Document

Returns a BigDecimal rounded according to the MathContext settings.

Usage

From source file:org.nd4j.linalg.util.BigDecimalMath.java

/**
 * Pochhammers function./* ww  w .  j a va  2 s .  co m*/
 *
 * @param x The main argument.
 * @param n The non-negative index.
 * @return (x)_n = x(x+1)(x+2)*...*(x+n-1).
 */
static public BigDecimal pochhammer(final BigDecimal x, final int n) {
    /* reduce to interval near 1.0 with the functional relation, Abramowitz-Stegun 6.1.33
     */
    if (n < 0) {
        throw new ProviderException("Unimplemented pochhammer with negative index " + n);
    } else if (n == 0) {
        return BigDecimal.ONE;
    } else {
        /* internally two safety digits
         */
        BigDecimal xhighpr = scalePrec(x, 2);
        BigDecimal resul = xhighpr;

        double xUlpDbl = x.ulp().doubleValue();

        double xDbl = x.doubleValue();
        /* relative error of the result is the sum of the relative errors of the factors
         */

        double eps = 0.5 * xUlpDbl / Math.abs(xDbl);

        for (int i = 1; i < n; i++) {
            eps += 0.5 * xUlpDbl / Math.abs(xDbl + i);

            resul = resul.multiply(xhighpr.add(new BigDecimal(i)));
            final MathContext mcloc = new MathContext(4 + err2prec(eps));
            resul = resul.round(mcloc);

        }
        return resul.round(new MathContext(err2prec(eps)));

    }
}

From source file:org.nd4j.linalg.util.BigDecimalMath.java

/**
 * Broadhurst ladder sequence.//from w w  w .j  a v  a2 s  .  c om
 *
 * @param a  The vector of 8 integer arguments
 * @param mc Specification of the accuracy of the result
 * @return S_(n, p)(a)
 * @see \protect\vrule width0pt\protect\href{http://arxiv.org/abs/math/9803067}{arXiv:math/9803067}
 */
static protected BigDecimal broadhurstBBP(final int n, final int p, final int a[], MathContext mc) {
    /* Explore the actual magnitude of the result first with a quick estimate.
    */
    double x = 0.0;

    for (int k = 1; k < 10; k++) {
        x += a[(k - 1) % 8] / Math.pow(2., p * (k + 1) / 2) / Math.pow((double) k, n);
    }
    /* Convert the relative precision and estimate of the result into an absolute precision.
     */

    double eps = prec2err(x, mc.getPrecision());
    /* Divide this through the number of terms in the sum to account for error accumulation
     * The divisor 2^(p(k+1)/2) means that on the average each 8th term in k has shrunk by
     * relative to the 8th predecessor by 1/2^(4p). 1/2^(4pc) = 10^(-precision) with c the 8term
     * cycles yields c=log_2( 10^precision)/4p = 3.3*precision/4p with k=8c
     */

    int kmax = (int) (6.6 * mc.getPrecision() / p);
    /* Now eps is the absolute error in each term */
    eps /= kmax;
    BigDecimal res = BigDecimal.ZERO;

    for (int c = 0;; c++) {
        Rational r = new Rational();

        for (int k = 0; k < 8; k++) {
            Rational tmp = new Rational(new BigInteger("" + a[k]),
                    (new BigInteger("" + (1 + 8 * c + k))).pow(n));
            /* floor( (pk+p)/2)
             */

            int pk1h = p * (2 + 8 * c + k) / 2;
            tmp = tmp.divide(BigInteger.ONE.shiftLeft(pk1h));
            r = r.add(tmp);

        }
        if (Math.abs(r.doubleValue()) < eps) {
            break;
        }
        MathContext mcloc = new MathContext(1 + err2prec(r.doubleValue(), eps));
        res = res.add(r.BigDecimalValue(mcloc));

    }
    return res.round(mc);

}

From source file:org.nd4j.linalg.util.BigDecimalMath.java

/**
 * The trigonometric co-tangent.//w  w w . jav a 2 s.c o m
 *
 * @param x the argument in radians.
 * @return the cot(x)
 */
static public BigDecimal cot(final BigDecimal x) {
    if (x.compareTo(BigDecimal.ZERO) == 0) {
        throw new ArithmeticException("Cannot take cot of zero " + x.toString());
    } else if (x.compareTo(BigDecimal.ZERO) < 0) {
        return cot(x.negate()).negate();
    } else {
        /* reduce modulo pi
         */
        BigDecimal res = modpi(x);
        /* absolute error in the result is err(x)/sin^2(x) to lowest order
         */
        final double xDbl = res.doubleValue();
        final double xUlpDbl = x.ulp().doubleValue() / 2.;
        final double eps = xUlpDbl / 2. / Math.pow(Math.sin(xDbl), 2.);
        final BigDecimal xhighpr = scalePrec(res, 2);
        final BigDecimal xhighprSq = multiplyRound(xhighpr, xhighpr);
        MathContext mc = new MathContext(err2prec(xhighpr.doubleValue(), eps));
        BigDecimal resul = BigDecimal.ONE.divide(xhighpr, mc);
        /* x^(2i-1) */
        BigDecimal xpowi = xhighpr;
        Bernoulli b = new Bernoulli();
        /* 2^(2i) */
        BigInteger fourn = new BigInteger("4");
        /* (2i)! */
        BigInteger fac = BigInteger.ONE;
        for (int i = 1;; i++) {
            Rational f = b.at(2 * i);
            fac = fac.multiply(new BigInteger("" + (2 * i))).multiply(new BigInteger("" + (2 * i - 1)));
            f = f.multiply(fourn).divide(fac);
            BigDecimal c = multiplyRound(xpowi, f);
            if (i % 2 == 0) {
                resul = resul.add(c);
            } else {
                resul = resul.subtract(c);
            }
            if (Math.abs(c.doubleValue()) < 0.1 * eps) {
                break;
            }
            fourn = fourn.shiftLeft(2);
            xpowi = multiplyRound(xpowi, xhighprSq);
        }
        mc = new MathContext(err2prec(resul.doubleValue(), eps));
        return resul.round(mc);
    }
}

From source file:org.nd4j.linalg.util.BigDecimalMath.java

/**
 * The trigonometric tangent./*from   w ww . j a  va 2  s  . c om*/
 *
 * @param x the argument in radians.
 * @return the tan(x)
 */
static public BigDecimal tan(final BigDecimal x) {
    if (x.compareTo(BigDecimal.ZERO) == 0) {
        return BigDecimal.ZERO;
    } else if (x.compareTo(BigDecimal.ZERO) < 0) {
        return tan(x.negate()).negate();
    } else {
        /* reduce modulo pi
         */
        BigDecimal res = modpi(x);
        /* absolute error in the result is err(x)/cos^2(x) to lowest order
         */
        final double xDbl = res.doubleValue();
        final double xUlpDbl = x.ulp().doubleValue() / 2.;
        final double eps = xUlpDbl / 2. / Math.pow(Math.cos(xDbl), 2.);
        if (xDbl > 0.8) {
            /* tan(x) = 1/cot(x) */
            BigDecimal co = cot(x);
            MathContext mc = new MathContext(err2prec(1. / co.doubleValue(), eps));
            return BigDecimal.ONE.divide(co, mc);
        } else {
            final BigDecimal xhighpr = scalePrec(res, 2);
            final BigDecimal xhighprSq = multiplyRound(xhighpr, xhighpr);
            BigDecimal resul = xhighpr.plus();
            /* x^(2i+1) */
            BigDecimal xpowi = xhighpr;
            Bernoulli b = new Bernoulli();
            /* 2^(2i) */
            BigInteger fourn = new BigInteger("4");
            /* (2i)! */
            BigInteger fac = new BigInteger("2");
            for (int i = 2;; i++) {
                Rational f = b.at(2 * i).abs();
                fourn = fourn.shiftLeft(2);
                fac = fac.multiply(new BigInteger("" + (2 * i))).multiply(new BigInteger("" + (2 * i - 1)));
                f = f.multiply(fourn).multiply(fourn.subtract(BigInteger.ONE)).divide(fac);
                xpowi = multiplyRound(xpowi, xhighprSq);
                BigDecimal c = multiplyRound(xpowi, f);
                resul = resul.add(c);
                if (Math.abs(c.doubleValue()) < 0.1 * eps) {
                    break;
                }
            }
            MathContext mc = new MathContext(err2prec(resul.doubleValue(), eps));
            return resul.round(mc);
        }
    }
}

From source file:org.nd4j.linalg.util.BigDecimalMath.java

/**
 * Euler-Mascheroni constant./*from  ww w. ja v a  2s.co  m*/
 *
 * @param mc The required precision of the result.
 * @return 0.577...
 */
static public BigDecimal gamma(MathContext mc) {
    /* look it up if possible */
    if (mc.getPrecision() < GAMMA.precision()) {
        return GAMMA.round(mc);
    } else {
        double eps = prec2err(0.577, mc.getPrecision());
        /* Euler-Stieltjes as shown in Dilcher, Aequat Math 48 (1) (1994) 55-85
        14
         */
        MathContext mcloc = new MathContext(2 + mc.getPrecision());
        BigDecimal resul = BigDecimal.ONE;
        resul = resul.add(log(2, mcloc));
        resul = resul.subtract(log(3, mcloc));
        /* how many terms: zeta-1 falls as 1/2^(2n+1), so the
         * terms drop faster than 1/2^(4n+2). Set 1/2^(4kmax+2) < eps.
         * Leading term zeta(3)/(4^1*3) is 0.017. Leading zeta(3) is 1.2. Log(2) is 0.7
         */
        int kmax = (int) ((Math.log(eps / 0.7) - 2.) / 4.);
        mcloc = new MathContext(1 + err2prec(1.2, eps / kmax));
        for (int n = 1;; n++) {
            /* zeta is close to 1. Division of zeta-1 through
             * 4^n*(2n+1) means divion through roughly 2^(2n+1)
             */
            BigDecimal c = zeta(2 * n + 1, mcloc).subtract(BigDecimal.ONE);
            BigInteger fourn = new BigInteger("" + (2 * n + 1));
            fourn = fourn.shiftLeft(2 * n);
            c = divideRound(c, fourn);
            resul = resul.subtract(c);
            if (c.doubleValue() < 0.1 * eps) {
                break;
            }
        }
        return resul.round(mc);
    }
}

From source file:org.nd4j.linalg.util.BigDecimalMath.java

/**
 * The integer root.//from w  ww.  j a  v  a 2 s  . co m
 *
 * @param n the positive argument.
 * @param x the non-negative argument.
 * @return The n-th root of the BigDecimal rounded to the precision implied by x, x^(1/n).
 */
static public BigDecimal root(final int n, final BigDecimal x) {
    if (x.compareTo(BigDecimal.ZERO) < 0) {
        throw new ArithmeticException("negative argument " + x.toString() + " of root");
    }
    if (n <= 0) {
        throw new ArithmeticException("negative power " + n + " of root");
    }
    if (n == 1) {
        return x;
    }
    /* start the computation from a double precision estimate */
    BigDecimal s = new BigDecimal(Math.pow(x.doubleValue(), 1.0 / n));
    /* this creates nth with nominal precision of 1 digit
     */
    final BigDecimal nth = new BigDecimal(n);
    /* Specify an internal accuracy within the loop which is
     * slightly larger than what is demanded by eps below.
     */
    final BigDecimal xhighpr = scalePrec(x, 2);
    MathContext mc = new MathContext(2 + x.precision());
    /* Relative accuracy of the result is eps.
     */
    final double eps = x.ulp().doubleValue() / (2 * n * x.doubleValue());
    for (;;) {
        /* s = s -(s/n-x/n/s^(n-1)) = s-(s-x/s^(n-1))/n; test correction s/n-x/s for being
         * smaller than the precision requested. The relative correction is (1-x/s^n)/n,
         */
        BigDecimal c = xhighpr.divide(s.pow(n - 1), mc);
        c = s.subtract(c);
        MathContext locmc = new MathContext(c.precision());
        c = c.divide(nth, locmc);
        s = s.subtract(c);
        if (Math.abs(c.doubleValue() / s.doubleValue()) < eps) {
            break;
        }
    }
    return s.round(new MathContext(err2prec(eps)));
}

From source file:org.nd4j.linalg.util.BigDecimalMath.java

/**
 * The exponential function.//  w  w w.jav  a 2 s .  c  om
 *
 * @param x the argument.
 * @return exp(x).
 * The precision of the result is implicitly defined by the precision in the argument.
 * 16
 * In particular this means that "Invalid Operation" errors are thrown if catastrophic
 * cancellation of digits causes the result to have no valid digits left.
 */
static public BigDecimal exp(BigDecimal x) {
    /* To calculate the value if x is negative, use exp(-x) = 1/exp(x)
     */
    if (x.compareTo(BigDecimal.ZERO) < 0) {
        final BigDecimal invx = exp(x.negate());
        /* Relative error in inverse of invx is the same as the relative errror in invx.
         * This is used to define the precision of the result.
         */
        MathContext mc = new MathContext(invx.precision());
        return BigDecimal.ONE.divide(invx, mc);
    } else if (x.compareTo(BigDecimal.ZERO) == 0) {
        /* recover the valid number of digits from x.ulp(), if x hits the
         * zero. The x.precision() is 1 then, and does not provide this information.
         */
        return scalePrec(BigDecimal.ONE, -(int) (Math.log10(x.ulp().doubleValue())));
    } else {
        /* Push the number in the Taylor expansion down to a small
         * value where TAYLOR_NTERM terms will do. If x<1, the n-th term is of the order
         * x^n/n!, and equal to both the absolute and relative error of the result
         * since the result is close to 1. The x.ulp() sets the relative and absolute error
         * of the result, as estimated from the first Taylor term.
         * We want x^TAYLOR_NTERM/TAYLOR_NTERM! < x.ulp, which is guaranteed if
         * x^TAYLOR_NTERM < TAYLOR_NTERM*(TAYLOR_NTERM-1)*...*x.ulp.
         */
        final double xDbl = x.doubleValue();
        final double xUlpDbl = x.ulp().doubleValue();
        if (Math.pow(xDbl, TAYLOR_NTERM) < TAYLOR_NTERM * (TAYLOR_NTERM - 1.0) * (TAYLOR_NTERM - 2.0)
                * xUlpDbl) {
            /* Add TAYLOR_NTERM terms of the Taylor expansion (Eulers sum formula)
             */
            BigDecimal resul = BigDecimal.ONE;
            /* x^i */
            BigDecimal xpowi = BigDecimal.ONE;
            /* i factorial */
            BigInteger ifac = BigInteger.ONE;
            /* TAYLOR_NTERM terms to be added means we move x.ulp() to the right
             * for each power of 10 in TAYLOR_NTERM, so the addition wont add noise beyond
             * whats already in x.
             */
            MathContext mcTay = new MathContext(err2prec(1., xUlpDbl / TAYLOR_NTERM));
            for (int i = 1; i <= TAYLOR_NTERM; i++) {
                ifac = ifac.multiply(new BigInteger("" + i));
                xpowi = xpowi.multiply(x);
                final BigDecimal c = xpowi.divide(new BigDecimal(ifac), mcTay);
                resul = resul.add(c);
                if (Math.abs(xpowi.doubleValue()) < i && Math.abs(c.doubleValue()) < 0.5 * xUlpDbl) {
                    break;
                }
            }
            /* exp(x+deltax) = exp(x)(1+deltax) if deltax is <<1. So the relative error
             * in the result equals the absolute error in the argument.
             */
            MathContext mc = new MathContext(err2prec(xUlpDbl / 2.));
            return resul.round(mc);
        } else {
            /* Compute exp(x) = (exp(0.1*x))^10. Division by 10 does not lead
             * to loss of accuracy.
             */
            int exSc = (int) (1.0 - Math.log10(TAYLOR_NTERM * (TAYLOR_NTERM - 1.0) * (TAYLOR_NTERM - 2.0)
                    * xUlpDbl / Math.pow(xDbl, TAYLOR_NTERM)) / (TAYLOR_NTERM - 1.0));
            BigDecimal xby10 = x.scaleByPowerOfTen(-exSc);
            BigDecimal expxby10 = exp(xby10);
            /* Final powering by 10 means that the relative error of the result
             * is 10 times the relative error of the base (First order binomial expansion).
             * This looses one digit.
             */
            MathContext mc = new MathContext(expxby10.precision() - exSc);
            /* Rescaling the powers of 10 is done in chunks of a maximum of 8 to avoid an invalid operation
            17
             * response by the BigDecimal.pow library or integer overflow.
             */
            while (exSc > 0) {
                int exsub = Math.min(8, exSc);
                exSc -= exsub;
                MathContext mctmp = new MathContext(expxby10.precision() - exsub + 2);
                int pex = 1;
                while (exsub-- > 0) {
                    pex *= 10;
                }
                expxby10 = expxby10.pow(pex, mctmp);
            }
            return expxby10.round(mc);
        }
    }
}

From source file:com.impetus.kundera.ycsb.runner.YCSBRunner.java

public void run(final String workLoad, final int threadCount) throws IOException {
    int runCounter = crudUtils.getMaxRunSequence(new Date(), runType);
    runCounter = runCounter + 1;/*from w ww  .j a  v a2s .c  o  m*/
    noOfThreads = threadCount;
    // id column of performanceNoInfo table
    Date id = new Date();

    int counter = 1;
    for (String client : clients) {
        currentClient = client;
        if (clientjarlocation != null && ycsbJarLocation != null && client != null && runType != null
                && host != null && schema != null && columnFamilyOrTable != null) {
            Runtime runtime = Runtime.getRuntime();
            counter++;
            String runCommand = getCommandString(client, workLoad);

            logger.info(runCommand);
            double totalTime = 0.0;
            long noOfOperations = 0;

            Process process = runtime.exec(runCommand);
            process.getErrorStream();
            InputStream is = process.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String line = null;
            BigDecimal avgLatency = null;
            BigDecimal throughput = null;

            boolean processed = false;
            while ((line = br.readLine()) != null) {
                processed = true;
                if (line.contains("RunTime")) {
                    totalTime = Double.parseDouble(line.substring(line.lastIndexOf(", ") + 2));
                    logger.info("Total time taken " + totalTime);
                }
                if (line.contains("Operations") && noOfOperations == 0) {
                    noOfOperations = Long.parseLong(line.substring(line.lastIndexOf(", ") + 2));
                    logger.info("Total no of oprations " + noOfOperations);
                }
                if (line.contains("Throughput")) {

                    throughput = new BigDecimal(line.substring(line.lastIndexOf(", ") + 2));
                    logger.info("Throughput(ops/sec) " + line);
                }
                if (line.contains("AverageLatency")) {
                    if (avgLatency == null) {
                        avgLatency = new BigDecimal(line.substring(line.lastIndexOf(", ") + 2));
                        logger.info("AverageLatency " + line);
                    }
                }
                /*
                 * if(line.contains("MinLatency")) {
                 * logger.info("MinLatency " + line); }
                 * if(line.contains("MaxLatency")) {
                 * logger.info("MaxLatency " + line); }
                 */
                // if(!(line.contains("CLEANUP") || line.contains("UPDATE")
                // || line.contains("INSERT") )){
                //                     logger.info(line);
                // }
            }

            if (!processed) {
                is = process.getErrorStream();
                isr = new InputStreamReader(is);
                br = new BufferedReader(isr);
                line = null;
                while ((line = br.readLine()) != null) {
                    logger.info(line);

                }
                throw new RuntimeException("Error while processing");
            }

            PerformanceNoInfo info = new PerformanceNoInfo(id, releaseNo,
                    client.substring(client.lastIndexOf(".") + 1), runType, noOfThreads, noOfOperations,
                    totalTime, runCounter);

            if (avgLatency != null) {
                info.setAvgLatency(avgLatency.round(MathContext.DECIMAL32));
            }

            if (throughput != null) {
                info.setThroughput(throughput.round(MathContext.DECIMAL32));
            }
            crudUtils.persistInfo(info);
            timeTakenByClient.put(client, throughput);
        }
    }

    sendMail();
}

From source file:org.nd4j.linalg.util.BigDecimalMath.java

/**
 * Trigonometric cosine.//from   w w  w .j  a va 2  s  . c o m
 *
 * @param x The argument in radians.
 * @return cos(x) in the range -1 to 1.
 */
static public BigDecimal cos(final BigDecimal x) {
    if (x.compareTo(BigDecimal.ZERO) < 0) {
        return cos(x.negate());
    } else if (x.compareTo(BigDecimal.ZERO) == 0) {
        return BigDecimal.ONE;
    } else {
        /* reduce modulo 2pi
         */
        BigDecimal res = mod2pi(x);
        double errpi = 0.5 * Math.abs(x.ulp().doubleValue());
        int val = +err2prec(FastMath.PI, errpi);
        MathContext mc = new MathContext(val);
        BigDecimal p = pi(mc);
        mc = new MathContext(x.precision());
        if (res.compareTo(p) > 0) {
            /* pi<x<=2pi: cos(x)= - cos(x-pi)
             */
            return cos(subtractRound(res, p)).negate();
        } else if (res.multiply(new BigDecimal("2")).compareTo(p) > 0) {
            /* pi/2<x<=pi: cos(x)= -cos(pi-x)
             */
            return cos(subtractRound(p, res)).negate();
        } else {
            /* for the range 0<=x<Pi/2 one could use cos(2x)= 1-2*sin^2(x)
             * to split this further, or use the cos up to pi/4 and the sine higher up.
            throw new ProviderException("Unimplemented cosine ") ;
             */
            if (res.multiply(new BigDecimal("4")).compareTo(p) > 0) {
                /* x>pi/4: cos(x) = sin(pi/2-x)
                 */
                return sin(subtractRound(p.divide(new BigDecimal("2")), res));
            } else {
                /* Simple Taylor expansion, sum_{i=0..infinity} (-1)^(..)res^(2i)/(2i)! */
                BigDecimal resul = BigDecimal.ONE;
                /* x^i */
                BigDecimal xpowi = BigDecimal.ONE;
                /* 2i factorial */
                BigInteger ifac = BigInteger.ONE;
                /* The absolute error in the result is the error in x^2/2 which is x times the error in x.
                 */
                double xUlpDbl = 0.5 * res.ulp().doubleValue() * res.doubleValue();
                /* The error in the result is set by the error in x^2/2 itself, xUlpDbl.
                 * We need at most k terms to push x^(2k+1)/(2k+1)! below this value.
                 * x^(2k) < xUlpDbl; (2k)*log(x) < log(xUlpDbl);
                 */
                int k = (int) (Math.log(xUlpDbl) / Math.log(res.doubleValue())) / 2;
                MathContext mcTay = new MathContext(err2prec(1., xUlpDbl / k));
                for (int i = 1;; i++) {
                    /* TBD: at which precision will 2*i-1 or 2*i overflow?
                     */
                    ifac = ifac.multiply(new BigInteger("" + (2 * i - 1)));
                    ifac = ifac.multiply(new BigInteger("" + (2 * i)));
                    xpowi = xpowi.multiply(res).multiply(res).negate();
                    BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay);
                    resul = resul.add(corr);
                    if (corr.abs().doubleValue() < 0.5 * xUlpDbl) {
                        break;
                    }
                }
                /* The error in the result is governed by the error in x itself.
                 */
                mc = new MathContext(err2prec(resul.doubleValue(), xUlpDbl));
                return resul.round(mc);
            }
        }
    }
}

From source file:org.nd4j.linalg.util.BigDecimalMath.java

/**
 * Trigonometric sine.// ww  w .j  a  v a 2s.  c o  m
 *
 * @param x The argument in radians.
 * @return sin(x) in the range -1 to 1.
 */
static public BigDecimal sin(final BigDecimal x) {
    if (x.compareTo(BigDecimal.ZERO) < 0) {
        return sin(x.negate()).negate();
    } else if (x.compareTo(BigDecimal.ZERO) == 0) {
        return BigDecimal.ZERO;
    } else {
        /* reduce modulo 2pi
         */
        BigDecimal res = mod2pi(x);
        double errpi = 0.5 * Math.abs(x.ulp().doubleValue());
        int val = 2 + err2prec(FastMath.PI, errpi);
        MathContext mc = new MathContext(val);
        BigDecimal p = pi(mc);
        mc = new MathContext(x.precision());
        if (res.compareTo(p) > 0) {
            /* pi<x<=2pi: sin(x)= - sin(x-pi)
             */
            return sin(subtractRound(res, p)).negate();
        } else if (res.multiply(new BigDecimal("2")).compareTo(p) > 0) {
            /* pi/2<x<=pi: sin(x)= sin(pi-x)
             */
            return sin(subtractRound(p, res));
        } else {
            /* for the range 0<=x<Pi/2 one could use sin(2x)=2sin(x)cos(x)
             * to split this further. Here, use the sine up to pi/4 and the cosine higher up.
             */
            if (res.multiply(new BigDecimal("4")).compareTo(p) > 0) {
                /* x>pi/4: sin(x) = cos(pi/2-x)
                 */
                return cos(subtractRound(p.divide(new BigDecimal("2")), res));
            } else {
                /* Simple Taylor expansion, sum_{i=1..infinity} (-1)^(..)res^(2i+1)/(2i+1)! */
                BigDecimal resul = res;
                /* x^i */
                BigDecimal xpowi = res;
                /* 2i+1 factorial */
                BigInteger ifac = BigInteger.ONE;
                /* The error in the result is set by the error in x itself.
                 */
                double xUlpDbl = res.ulp().doubleValue();
                /* The error in the result is set by the error in x itself.
                 * We need at most k terms to squeeze x^(2k+1)/(2k+1)! below this value.
                 * x^(2k+1) < x.ulp; (2k+1)*log10(x) < -x.precision; 2k*log10(x)< -x.precision;
                 * 2k*(-log10(x)) > x.precision; 2k*log10(1/x) > x.precision
                 */
                int k = (int) (res.precision() / Math.log10(1.0 / res.doubleValue())) / 2;
                MathContext mcTay = new MathContext(err2prec(res.doubleValue(), xUlpDbl / k));
                for (int i = 1;; i++) {
                    /* TBD: at which precision will 2*i or 2*i+1 overflow?
                     */
                    ifac = ifac.multiply(new BigInteger("" + (2 * i)));
                    ifac = ifac.multiply(new BigInteger("" + (2 * i + 1)));
                    xpowi = xpowi.multiply(res).multiply(res).negate();
                    BigDecimal corr = xpowi.divide(new BigDecimal(ifac), mcTay);
                    resul = resul.add(corr);
                    if (corr.abs().doubleValue() < 0.5 * xUlpDbl) {
                        break;
                    }
                }
                /* The error in the result is set by the error in x itself.
                 */
                mc = new MathContext(res.precision());
                return resul.round(mc);
            }
        }
    } /* sin */
}