diff --git a/.gitmodules b/.gitmodules
index 6b558787..612f980c 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,6 @@
[submodule "Flow"]
path = Flow
url = https://github.com/Cavallium/Flow
+[submodule "bigdecimal-math"]
+ path = bigdecimal-math
+ url = https://github.com/Cavallium/bigdecimal-math
diff --git a/LICENSE b/LICENSE
index 753842b6..c59b79ea 100644
--- a/LICENSE
+++ b/LICENSE
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
- Copyright [yyyy] [name of copyright owner]
+ Copyright 2018 Andrea Cavalli
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
diff --git a/MmapByteBuffer.java b/MmapByteBuffer.java
deleted file mode 100644
index 5573e989..00000000
--- a/MmapByteBuffer.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package it.cavallium.warppi;
-
-import java.nio.ByteBuffer;
-
-public class MmapByteBuffer {
- private int fd;
- private int address;
- private int length;
- private ByteBuffer buffer;
-
- public MmapByteBuffer(int fd, int address, int length, ByteBuffer buffer) {
- this.fd = fd;
- this.address = address;
- this.length = length;
- this.buffer = buffer;
- }
-
- public int getFd() {
- return fd;
- }
-
- public int getAddress() {
- return address;
- }
-
- public int getLength() {
- return length;
- }
-
- public ByteBuffer getBuffer() {
- return buffer;
- }
-}
\ No newline at end of file
diff --git a/bigdecimal-math b/bigdecimal-math
new file mode 160000
index 00000000..92a67122
--- /dev/null
+++ b/bigdecimal-math
@@ -0,0 +1 @@
+Subproject commit 92a67122350a38af726beae58d2582fb867a4c61
diff --git a/core/pom.xml b/core/pom.xml
index 3d996471..b4e2c2ca 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -6,7 +6,7 @@
it.cavalliumwarppi
- 0.9.0a2
+ 0.9.0a2warppi-core
@@ -17,7 +17,17 @@
it.cavalliumwarppi-flow
- ${project.version}
+ 0.9.0a2
+
+
+ it.cavallium
+ warppi-util
+ 0.9.0a2
+
+
+ it.cavallium
+ bigdecimal-math
+ 0.9.0a2it.unimi.dsi
diff --git a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisScreen.java b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisScreen.java
index 2604a6cd..30c5c402 100644
--- a/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisScreen.java
+++ b/core/src/main/java/it/cavallium/warppi/extra/tetris/TetrisScreen.java
@@ -2,8 +2,6 @@ package it.cavallium.warppi.extra.tetris;
import java.io.IOException;
-import org.nevec.rjm.Wigner3j;
-
import it.cavallium.warppi.Engine;
import it.cavallium.warppi.StaticVars;
import it.cavallium.warppi.device.Keyboard;
diff --git a/core/src/main/java/org/nevec/rjm/Bernoulli.java b/core/src/main/java/org/nevec/rjm/Bernoulli.java
deleted file mode 100644
index d4834db0..00000000
--- a/core/src/main/java/org/nevec/rjm/Bernoulli.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * Bernoulli numbers.
- *
- * @since 2006-06-25
- * @author Richard J. Mathar
- */
-public class Bernoulli {
- /*
- * The list of all Bernoulli numbers as a vector, n=0,2,4,....
- */
- static Vector a = new Vector<>();
-
- public Bernoulli() {
- if (Bernoulli.a.size() == 0) {
- Bernoulli.a.add(Rational.ONE);
- Bernoulli.a.add(new Rational(1, 6));
- }
- }
-
- /**
- * Set a coefficient in the internal table.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * @param value
- * the new value of the coefficient.
- */
- protected void set(final int n, final Rational value) {
- final int nindx = n / 2;
- if (nindx < Bernoulli.a.size()) {
- Bernoulli.a.set(nindx, value);
- } else {
- while (Bernoulli.a.size() < nindx) {
- Bernoulli.a.add(Rational.ZERO);
- }
- Bernoulli.a.add(value);
- }
- }
-
- /**
- * The Bernoulli number at the index provided.
- *
- * @param n
- * the index, non-negative.
- * @return the B_0=1 for n=0, B_1=-1/2 for n=1, B_2=1/6 for n=2 etc
- * @throws Error
- */
- public Rational at(final int n) throws Error {
- if (n == 1) {
- return new Rational(-1, 2);
- } else if (n % 2 != 0) {
- return Rational.ZERO;
- } else {
- final int nindx = n / 2;
- if (Bernoulli.a.size() <= nindx) {
- for (int i = 2 * Bernoulli.a.size(); i <= n; i += 2) {
- set(i, doubleSum(i));
- }
- }
- return Bernoulli.a.elementAt(nindx);
- }
- }
-
- /*
- * Generate a new B_n by a standard double sum.
- *
- * @param n The index of the Bernoulli number.
- *
- * @return The Bernoulli number at n.
- */
- private Rational doubleSum(final int n) throws Error {
- Rational resul = Rational.ZERO;
- for (int k = 0; k <= n; k++) {
- Rational jsum = Rational.ZERO;
- BigInteger bin = BigInteger.ONE;
- for (int j = 0; j <= k; j++) {
- final BigInteger jpown = new BigInteger("" + j).pow(n);
- if (j % 2 == 0) {
- jsum = jsum.add(bin.multiply(jpown));
- } else {
- jsum = jsum.subtract(bin.multiply(jpown));
- }
-
- /*
- * update binomial(k,j) recursively
- */
- bin = bin.multiply(new BigInteger("" + (k - j))).divide(new BigInteger("" + (j + 1)));
- }
- resul = resul.add(jsum.divide(new BigInteger("" + (k + 1))));
- }
- return resul;
- }
-
-} /* Bernoulli */
diff --git a/core/src/main/java/org/nevec/rjm/BigComplex.java b/core/src/main/java/org/nevec/rjm/BigComplex.java
deleted file mode 100644
index 636e53a4..00000000
--- a/core/src/main/java/org/nevec/rjm/BigComplex.java
+++ /dev/null
@@ -1,220 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.MathContext;
-
-/**
- * Complex numbers with BigDecimal real and imaginary components
- *
- * @since 2008-10-26
- * @author Richard J. Mathar
- */
-public class BigComplex {
- /**
- * real part
- */
- BigDecimal re;
-
- /**
- * imaginary part
- */
- BigDecimal im;
-
- /**
- * The constant that equals zero
- */
- final static BigComplex ZERO = new BigComplex(BigDecimal.ZERO, BigDecimal.ZERO);
-
- /**
- * Default ctor equivalent to zero.
- */
- public BigComplex() {
- re = BigDecimal.ZERO;
- im = BigDecimal.ZERO;
- }
-
- /**
- * ctor with real and imaginary parts
- *
- * @param x
- * real part
- * @param y
- * imaginary part
- */
- public BigComplex(final BigDecimal x, final BigDecimal y) {
- re = x;
- im = y;
- }
-
- /**
- * ctor with real part.
- *
- * @param x
- * real part.
- * The imaginary part is set to zero.
- */
- public BigComplex(final BigDecimal x) {
- re = x;
- im = BigDecimal.ZERO;
- }
-
- /**
- * ctor with real and imaginary parts
- *
- * @param x
- * real part
- * @param y
- * imaginary part
- */
- public BigComplex(final double x, final double y) {
- re = new BigDecimal(x);
- im = new BigDecimal(y);
- }
-
- /**
- * Multiply with another BigComplex
- *
- * @param oth
- * The BigComplex which is a factor in the product
- * @param mc
- * Defining precision and rounding mode
- * @return This multiplied by oth
- * @since 2010-07-19 implemented with 3 multiplications and 5
- * additions/subtractions
- */
- BigComplex multiply(final BigComplex oth, final MathContext mc) {
- final BigDecimal a = re.add(im).multiply(oth.re);
- final BigDecimal b = oth.re.add(oth.im).multiply(im);
- final BigDecimal c = oth.im.subtract(oth.re).multiply(re);
- final BigDecimal x = a.subtract(b, mc);
- final BigDecimal y = a.add(c, mc);
- return new BigComplex(x, y);
- }
-
- /**
- * Add a BigDecimal
- *
- * @param oth
- * the value to be added to the real part.
- * @return this added to oth
- */
- BigComplex add(final BigDecimal oth) {
- final BigDecimal x = re.add(oth);
- return new BigComplex(x, im);
- }
-
- /**
- * Subtract another BigComplex
- *
- * @param oth
- * the value to be subtracted from this.
- * @return this minus oth
- */
- BigComplex subtract(final BigComplex oth) {
- final BigDecimal x = re.subtract(oth.re);
- final BigDecimal y = im.subtract(oth.im);
- return new BigComplex(x, y);
- }
-
- /**
- * Complex-conjugation
- *
- * @return the complex conjugate of this.
- */
- BigComplex conj() {
- return new BigComplex(re, im.negate());
- }
-
- /**
- * The absolute value squared.
- *
- * @return The sum of the squares of real and imaginary parts.
- * This is the square of BigComplex.abs() .
- */
- BigDecimal norm() {
- return re.multiply(re).add(im.multiply(im));
- }
-
- /**
- * The absolute value.
- *
- * @return the square root of the sum of the squares of real and imaginary
- * parts.
- * @since 2008-10-27
- */
- BigDecimal abs(final MathContext mc) {
- return BigDecimalMath.sqrt(norm(), mc);
- }
-
- /**
- * The square root.
- *
- * @return the square root of the this.
- * The branch is chosen such that the imaginary part of the result
- * has the
- * same sign as the imaginary part of this.
- * @see Tim Ahrendt, Fast
- * High-precision computation of complex square roots,
- * ISSAC 1996 p142-149.
- * @since 2008-10-27
- */
- BigComplex sqrt(final MathContext mc) {
- final BigDecimal half = new BigDecimal("2");
- /*
- * compute l=sqrt(re^2+im^2), then u=sqrt((l+re)/2)
- * and v= +- sqrt((l-re)/2 as the new real and imaginary parts.
- */
- final BigDecimal l = abs(mc);
- if (l.compareTo(BigDecimal.ZERO) == 0) {
- return new BigComplex(BigDecimalMath.scalePrec(BigDecimal.ZERO, mc), BigDecimalMath.scalePrec(BigDecimal.ZERO, mc));
- }
- final BigDecimal u = BigDecimalMath.sqrt(l.add(re).divide(half, mc), mc);
- final BigDecimal v = BigDecimalMath.sqrt(l.subtract(re).divide(half, mc), mc);
- if (im.compareTo(BigDecimal.ZERO) >= 0) {
- return new BigComplex(u, v);
- } else {
- return new BigComplex(u, v.negate());
- }
- }
-
- /**
- * The inverse of this.
- *
- * @return 1/this
- */
- BigComplex inverse(final MathContext mc) {
- final BigDecimal hyp = norm();
- /* 1/(x+iy)= (x-iy)/(x^2+y^2 */
- return new BigComplex(re.divide(hyp, mc), im.divide(hyp, mc).negate());
- }
-
- /**
- * Divide through another BigComplex number.
- *
- * @return this/oth
- */
- BigComplex divide(final BigComplex oth, final MathContext mc) {
- /* lazy implementation: (x+iy)/(a+ib)= (x+iy)* 1/(a+ib) */
- return multiply(oth.inverse(mc), mc);
- }
-
- /**
- * Human-readable Fortran-type display
- *
- * @return real and imaginary part in parenthesis, divided by a comma.
- */
- @Override
- public String toString() {
- return "(" + re.toString() + "," + im.toString() + ")";
- }
-
- /**
- * Human-readable Fortran-type display
- *
- * @return real and imaginary part in parenthesis, divided by a comma.
- */
- public String toString(final MathContext mc) {
- return "(" + re.round(mc).toString() + "," + im.round(mc).toString() + ")";
- }
-
-} /* BigComplex */
diff --git a/core/src/main/java/org/nevec/rjm/BigDecimalMath.java b/core/src/main/java/org/nevec/rjm/BigDecimalMath.java
deleted file mode 100644
index 926f1ded..00000000
--- a/core/src/main/java/org/nevec/rjm/BigDecimalMath.java
+++ /dev/null
@@ -1,3038 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.security.ProviderException;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * BigDecimal special functions.
- * A Java Math.BigDecimal
- * Implementation of Core Mathematical Functions
- *
- * @since 2009-05-22
- * @author Richard J. Mathar
- * @see apfloat
- * @see dfp
- * @see JScience
- */
-public class BigDecimalMath {
-
- /**
- * The base of the natural logarithm in a predefined accuracy.
- * http://www.cs.arizona.edu/icon/oddsends/e.htm
- * The precision of the predefined constant is one less than
- * the string's length, taking into account the decimal dot.
- * static int E_PRECISION = E.length()-1 ;
- */
- static BigDecimal E = new BigDecimal("2.71828182845904523536028747135266249775724709369995957496696762772407663035354" + "759457138217852516642742746639193200305992181741359662904357290033429526059563" + "073813232862794349076323382988075319525101901157383418793070215408914993488416" + "750924476146066808226480016847741185374234544243710753907774499206955170276183" + "860626133138458300075204493382656029760673711320070932870912744374704723069697" + "720931014169283681902551510865746377211125238978442505695369677078544996996794" + "686445490598793163688923009879312773617821542499922957635148220826989519366803" + "318252886939849646510582093923982948879332036250944311730123819706841614039701" + "983767932068328237646480429531180232878250981945581530175671736133206981125099" + "618188159304169035159888851934580727386673858942287922849989208680582574927961" + "048419844436346324496848756023362482704197862320900216099023530436994184914631" + "409343173814364054625315209618369088870701676839642437814059271456354906130310" + "720851038375051011574770417189861068739696552126715468895703503540212340784981" + "933432106817012100562788023519303322474501585390473041995777709350366041699732" + "972508868769664035557071622684471625607988265178713419512466520103059212366771" + "943252786753985589448969709640975459185695638023637016211204774272283648961342" + "251644507818244235294863637214174023889344124796357437026375529444833799801612" + "549227850925778256209262264832627793338656648162772516401910590049164499828931");
-
- /**
- * Euler's constant Pi.
- * http://www.cs.arizona.edu/icon/oddsends/pi.htm
- */
- static BigDecimal PI = new BigDecimal("3.14159265358979323846264338327950288419716939937510582097494459230781640628620" + "899862803482534211706798214808651328230664709384460955058223172535940812848111" + "745028410270193852110555964462294895493038196442881097566593344612847564823378" + "678316527120190914564856692346034861045432664821339360726024914127372458700660" + "631558817488152092096282925409171536436789259036001133053054882046652138414695" + "194151160943305727036575959195309218611738193261179310511854807446237996274956" + "735188575272489122793818301194912983367336244065664308602139494639522473719070" + "217986094370277053921717629317675238467481846766940513200056812714526356082778" + "577134275778960917363717872146844090122495343014654958537105079227968925892354" + "201995611212902196086403441815981362977477130996051870721134999999837297804995" + "105973173281609631859502445945534690830264252230825334468503526193118817101000" + "313783875288658753320838142061717766914730359825349042875546873115956286388235" + "378759375195778185778053217122680661300192787661119590921642019893809525720106" + "548586327886593615338182796823030195203530185296899577362259941389124972177528" + "347913151557485724245415069595082953311686172785588907509838175463746493931925" + "506040092770167113900984882401285836160356370766010471018194295559619894676783" + "744944825537977472684710404753464620804668425906949129331367702898915210475216" + "205696602405803815019351125338243003558764024749647326391419927260426992279678" + "235478163600934172164121992458631503028618297455570674983850549458858692699569" + "092721079750930295532116534498720275596023648066549911988183479775356636980742" + "654252786255181841757467289097777279380008164706001614524919217321721477235014");
-
- /**
- * Euler-Mascheroni constant lower-case gamma.
- * http://www.worldwideschool.org/library/books/sci/math/
- * MiscellaneousMathematicalConstants/chap35.html
- */
- static BigDecimal GAMMA = new BigDecimal("0.577215664901532860606512090082402431" + "0421593359399235988057672348848677267776646709369470632917467495146314472498070" + "8248096050401448654283622417399764492353625350033374293733773767394279259525824" + "7094916008735203948165670853233151776611528621199501507984793745085705740029921" + "3547861466940296043254215190587755352673313992540129674205137541395491116851028" + "0798423487758720503843109399736137255306088933126760017247953783675927135157722" + "6102734929139407984301034177717780881549570661075010161916633401522789358679654" + "9725203621287922655595366962817638879272680132431010476505963703947394957638906" + "5729679296010090151251959509222435014093498712282479497471956469763185066761290" + "6381105182419744486783638086174945516989279230187739107294578155431600500218284" + "4096053772434203285478367015177394398700302370339518328690001558193988042707411" + "5422278197165230110735658339673487176504919418123000406546931429992977795693031" + "0050308630341856980323108369164002589297089098548682577736428825395492587362959" + "6133298574739302373438847070370284412920166417850248733379080562754998434590761" + "6431671031467107223700218107450444186647591348036690255324586254422253451813879" + "1243457350136129778227828814894590986384600629316947188714958752549236649352047" + "3243641097268276160877595088095126208404544477992299157248292516251278427659657" + "0832146102982146179519579590959227042089896279712553632179488737642106606070659" + "8256199010288075612519913751167821764361905705844078357350158005607745793421314" + "49885007864151716151945");
-
- /**
- * Natural logarithm of 2.
- * http://www.worldwideschool.org/library/books/sci/math/
- * MiscellaneousMathematicalConstants/chap58.html
- */
- static BigDecimal LOG2 = new BigDecimal("0.693147180559945309417232121458176568075" + "50013436025525412068000949339362196969471560586332699641868754200148102057068573" + "368552023575813055703267075163507596193072757082837143519030703862389167347112335" + "011536449795523912047517268157493206515552473413952588295045300709532636664265410" + "423915781495204374043038550080194417064167151864471283996817178454695702627163106" + "454615025720740248163777338963855069526066834113727387372292895649354702576265209" + "885969320196505855476470330679365443254763274495125040606943814710468994650622016" + "772042452452961268794654619316517468139267250410380254625965686914419287160829380" + "317271436778265487756648508567407764845146443994046142260319309673540257444607030" + "809608504748663852313818167675143866747664789088143714198549423151997354880375165" + "861275352916610007105355824987941472950929311389715599820565439287170007218085761" + "025236889213244971389320378439353088774825970171559107088236836275898425891853530" + "243634214367061189236789192372314672321720534016492568727477823445353476481149418" + "642386776774406069562657379600867076257199184734022651462837904883062033061144630" + "073719489002743643965002580936519443041191150608094879306786515887090060520346842" + "973619384128965255653968602219412292420757432175748909770675268711581705113700915" + "894266547859596489065305846025866838294002283300538207400567705304678700184162404" + "418833232798386349001563121889560650553151272199398332030751408426091479001265168" + "243443893572472788205486271552741877243002489794540196187233980860831664811490930" + "667519339312890431641370681397776498176974868903887789991296503619270710889264105" + "230924783917373501229842420499568935992206602204654941510613");
-
- /**
- * Euler's constant.
- *
- * @param mc
- * The required precision of the result.
- * @return 3.14159...
- * @throws Error
- * @since 2009-05-29
- */
- static public BigDecimal pi(final MathContext mc) throws Error {
- /* look it up if possible */
- if (mc.getPrecision() < BigDecimalMath.PI.precision()) {
- return BigDecimalMath.PI.round(mc);
- } else {
- /*
- * Broadhurst arXiv:math/9803067
- */
- final int[] a = { 1, 0, 0, -1, -1, -1, 0, 0 };
- final BigDecimal S = BigDecimalMath.broadhurstBBP(1, 1, a, mc);
- return BigDecimalMath.multiplyRound(S, 8);
- }
- } /* BigDecimalMath.pi */
-
- /**
- * Euler-Mascheroni constant.
- *
- * @param mc
- * The required precision of the result.
- * @return 0.577...
- * @throws Error
- * @since 2009-08-13
- */
- static public BigDecimal gamma(final MathContext mc) throws Error {
- /* look it up if possible */
- if (mc.getPrecision() < BigDecimalMath.GAMMA.precision()) {
- return BigDecimalMath.GAMMA.round(mc);
- } else {
- final double eps = BigDecimalMath.prec2err(0.577, mc.getPrecision());
-
- /*
- * Euler-Stieltjes as shown in Dilcher, Aequat Math 48 (1) (1994)
- * 55-85
- */
- MathContext mcloc = SafeMathContext.newMathContext(2 + mc.getPrecision());
- BigDecimal resul = BigDecimal.ONE;
- resul = resul.add(BigDecimalMath.log(2, mcloc));
- resul = resul.subtract(BigDecimalMath.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
- */
- final int kmax = (int) ((Math.log(eps / 0.7) - 2.) / 4.);
- mcloc = SafeMathContext.newMathContext(1 + BigDecimalMath.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 = BigDecimalMath.zeta(2 * n + 1, mcloc).subtract(BigDecimal.ONE);
- BigInteger fourn = new BigInteger("" + (2 * n + 1));
- fourn = fourn.shiftLeft(2 * n);
- c = BigDecimalMath.divideRound(c, fourn);
- resul = resul.subtract(c);
- if (c.doubleValue() < 0.1 * eps) {
- break;
- }
- }
- return resul.round(mc);
- }
-
- } /* BigDecimalMath.gamma */
-
- /**
- * The square root.
- *
- * @param x
- * the non-negative argument.
- * @param mc
- * @return the square root of the BigDecimal.
- * @since 2008-10-27
- */
- static public BigDecimal sqrt(final BigDecimal x, final MathContext mc) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("negative argument " + x.toString() + " of square root");
- }
- if (x.abs().subtract(new BigDecimal(Math.pow(10., -mc.getPrecision()))).compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.scalePrec(BigDecimal.ZERO, mc);
- }
- /* start the computation from a double precision estimate */
- BigDecimal s = new BigDecimal(Math.sqrt(x.doubleValue()), mc);
- final BigDecimal half = new BigDecimal("2");
-
- /* increase the local accuracy by 2 digits */
- final MathContext locmc = SafeMathContext.newMathContext(mc.getPrecision() + 2, mc.getRoundingMode());
-
- /*
- * relative accuracy requested is 10^(-precision)
- */
- final double eps = Math.pow(10.0, -mc.getPrecision());
- for (;;) {
- /*
- * s = s -(s/2-x/2s); test correction s-x/s for being
- * smaller than the precision requested. The relative correction is
- * 1-x/s^2,
- * (actually half of this, which we use for a little bit of
- * additional protection).
- */
- if (Math.abs(BigDecimal.ONE.subtract(x.divide(s.pow(2, locmc), locmc)).doubleValue()) <= eps) {
- break;
- }
- s = s.add(x.divide(s, locmc)).divide(half, locmc);
- /* debugging */
- // System.out.println("itr "+x.round(locmc).toString() + " " +
- // s.round(locmc).toString()) ;
- }
- return s;
- } /* BigDecimalMath.sqrt */
-
- /**
- * The square root.
- *
- * @param x
- * the non-negative argument.
- * @return the square root of the BigDecimal rounded to the precision
- * implied by x.
- * @since 2009-06-25
- */
- static public BigDecimal sqrt(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("negative argument " + x.toString() + " of square root");
- }
-
- return BigDecimalMath.root(2, x);
- } /* BigDecimalMath.sqrt */
-
- /**
- * The cube root.
- *
- * @param x
- * The argument.
- * @return The cubic root of the BigDecimal rounded to the precision implied
- * by x.
- * The sign of the result is the sign of the argument.
- * @since 2009-08-16
- */
- static public BigDecimal cbrt(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.root(3, x.negate()).negate();
- } else {
- return BigDecimalMath.root(3, x);
- }
- } /* BigDecimalMath.cbrt */
-
- /**
- * The integer root.
- *
- * @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).
- * @since 2009-07-30
- */
- 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 = BigDecimalMath.scalePrec(x, 2);
- final MathContext mc = SafeMathContext.newMathContext(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);
- final MathContext locmc = SafeMathContext.newMathContext(c.precision());
- c = c.divide(nth, locmc);
- s = s.subtract(c);
- if (Math.abs(c.doubleValue() / s.doubleValue()) < eps) {
- break;
- }
- }
- return s.round(SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps)));
- } /* BigDecimalMath.root */
-
- /**
- * The hypotenuse.
- *
- * @param x
- * the first argument.
- * @param y
- * the second argument.
- * @return the square root of the sum of the squares of the two arguments,
- * sqrt(x^2+y^2).
- * @since 2009-06-25
- */
- static public BigDecimal hypot(final BigDecimal x, final BigDecimal y) {
- /*
- * compute x^2+y^2
- */
- BigDecimal z = x.pow(2).add(y.pow(2));
-
- /*
- * truncate to the precision set by x and y. Absolute error =
- * 2*x*xerr+2*y*yerr,
- * where the two errors are 1/2 of the ulp's. Two intermediate protectio
- * digits.
- */
- final BigDecimal zerr = x.abs().multiply(x.ulp()).add(y.abs().multiply(y.ulp()));
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(z, zerr));
-
- /* Pull square root */
- z = BigDecimalMath.sqrt(z.round(mc));
-
- /*
- * Final rounding. Absolute error in the square root is
- * (y*yerr+x*xerr)/z, where zerr holds 2*(x*xerr+y*yerr).
- */
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(z.doubleValue(), 0.5 * zerr.doubleValue() / z.doubleValue()));
- return z.round(mc);
- } /* BigDecimalMath.hypot */
-
- /**
- * The hypotenuse.
- *
- * @param n
- * the first argument.
- * @param x
- * the second argument.
- * @return the square root of the sum of the squares of the two arguments,
- * sqrt(n^2+x^2).
- * @since 2009-08-05
- */
- static public BigDecimal hypot(final int n, final BigDecimal x) {
- /*
- * compute n^2+x^2 in infinite precision
- */
- BigDecimal z = new BigDecimal(n).pow(2).add(x.pow(2));
-
- /*
- * Truncate to the precision set by x. Absolute error = in z (square of
- * the result) is |2*x*xerr|,
- * where the error is 1/2 of the ulp. Two intermediate protection
- * digits.
- * zerr is a signed value, but used only in conjunction with err2prec(),
- * so this feature does not harm.
- */
- final double zerr = x.doubleValue() * x.ulp().doubleValue();
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(z.doubleValue(), zerr));
-
- /* Pull square root */
- z = BigDecimalMath.sqrt(z.round(mc));
-
- /*
- * Final rounding. Absolute error in the square root is x*xerr/z, where
- * zerr holds 2*x*xerr.
- */
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(z.doubleValue(), 0.5 * zerr / z.doubleValue()));
- return z.round(mc);
- } /* BigDecimalMath.hypot */
-
- /**
- * A suggestion for the maximum numter of terms in the Taylor expansion of
- * the exponential.
- */
- static private int TAYLOR_NTERM = 8;
-
- /**
- * The exponential function.
- *
- * @param x
- * the argument.
- * @return exp(x).
- * The precision of the result is implicitly defined by the
- * precision in the argument.
- * In particular this means that "Invalid Operation" errors are
- * thrown if catastrophic
- * cancellation of digits causes the result to have no valid digits
- * left.
- * @since 2009-05-29
- * @author Richard J. Mathar
- */
- static public BigDecimal exp(final 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 = BigDecimalMath.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.
- */
- final MathContext mc = SafeMathContext.newMathContext(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 BigDecimalMath.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, BigDecimalMath.TAYLOR_NTERM) < BigDecimalMath.TAYLOR_NTERM * (BigDecimalMath.TAYLOR_NTERM - 1.0) * (BigDecimalMath.TAYLOR_NTERM - 2.0) * xUlpDbl) {
- /*
- * Add TAYLOR_NTERM terms of the Taylor expansion (Euler's 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 won't
- * add noise beyond
- * what's already in x.
- */
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.err2prec(1., xUlpDbl / BigDecimalMath.TAYLOR_NTERM));
- for (int i = 1; i <= BigDecimalMath.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.
- */
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.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(BigDecimalMath.TAYLOR_NTERM * (BigDecimalMath.TAYLOR_NTERM - 1.0) * (BigDecimalMath.TAYLOR_NTERM - 2.0) * xUlpDbl / Math.pow(xDbl, BigDecimalMath.TAYLOR_NTERM)) / (BigDecimalMath.TAYLOR_NTERM - 1.0));
- final BigDecimal xby10 = x.scaleByPowerOfTen(-exSc);
- BigDecimal expxby10 = BigDecimalMath.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.
- */
- final MathContext mc = SafeMathContext.newMathContext(expxby10.precision() - exSc);
- /*
- * Rescaling the powers of 10 is done in chunks of a maximum of
- * 8 to avoid an invalid operation
- * response by the BigDecimal.pow library or integer overflow.
- */
- while (exSc > 0) {
- int exsub = Math.min(8, exSc);
- exSc -= exsub;
- final MathContext mctmp = SafeMathContext.newMathContext(expxby10.precision() - exsub + 2);
- int pex = 1;
- while (exsub-- > 0) {
- pex *= 10;
- }
- expxby10 = expxby10.pow(pex, mctmp);
- }
- return expxby10.round(mc);
- }
- }
- } /* BigDecimalMath.exp */
-
- /**
- * The base of the natural logarithm.
- *
- * @param mc
- * the required precision of the result
- * @return exp(1) = 2.71828....
- * @since 2009-05-29
- */
- static public BigDecimal exp(final MathContext mc) {
- /* look it up if possible */
- if (mc.getPrecision() < BigDecimalMath.E.precision()) {
- return BigDecimalMath.E.round(mc);
- } else {
- /*
- * Instantiate a 1.0 with the requested pseudo-accuracy
- * and delegate the computation to the public method above.
- */
- final BigDecimal uni = BigDecimalMath.scalePrec(BigDecimal.ONE, mc.getPrecision());
- return BigDecimalMath.exp(uni);
- }
- } /* BigDecimalMath.exp */
-
- /**
- * The natural logarithm.
- *
- * @param x
- * the argument.
- * @return ln(x).
- * The precision of the result is implicitly defined by the
- * precision in the argument.
- * @since 2009-05-29
- * @author Richard J. Mathar
- */
- static public BigDecimal log(final BigDecimal x) {
- /*
- * the value is undefined if x is negative.
- */
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("Cannot take log of negative " + x.toString());
- } else if (x.compareTo(BigDecimal.ONE) == 0) {
- /* log 1. = 0. */
- return BigDecimalMath.scalePrec(BigDecimal.ZERO, x.precision() - 1);
- } else if (Math.abs(x.doubleValue() - 1.0) <= 0.3) {
- /*
- * The standard Taylor series around x=1, z=0, z=x-1.
- * Abramowitz-Stegun 4.124.
- * The absolute error is err(z)/(1+z) = err(x)/x.
- */
- final BigDecimal z = BigDecimalMath.scalePrec(x.subtract(BigDecimal.ONE), 2);
- BigDecimal zpown = z;
- final double eps = 0.5 * x.ulp().doubleValue() / Math.abs(x.doubleValue());
- BigDecimal resul = z;
- for (int k = 2;; k++) {
- zpown = BigDecimalMath.multiplyRound(zpown, z);
- final BigDecimal c = BigDecimalMath.divideRound(zpown, k);
- if (k % 2 == 0) {
- resul = resul.subtract(c);
- } else {
- resul = resul.add(c);
- }
- if (Math.abs(c.doubleValue()) < eps) {
- break;
- }
- }
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- } else {
- final double xDbl = x.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue();
-
- /*
- * Map log(x) = log root[r](x)^r = r*log( root[r](x)) with the aim
- * to move roor[r](x) near to 1.2 (that is, below the 0.3 appearing
- * above), where log(1.2) is roughly 0.2.
- */
- int r = (int) (Math.log(xDbl) / 0.2);
-
- /*
- * Since the actual requirement is a function of the value 0.3
- * appearing above,
- * we avoid the hypothetical case of endless recurrence by ensuring
- * that r >= 2.
- */
- r = Math.max(2, r);
-
- /*
- * Compute r-th root with 2 additional digits of precision
- */
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- BigDecimal resul = BigDecimalMath.root(r, xhighpr);
- resul = BigDecimalMath.log(resul).multiply(new BigDecimal(r));
-
- /*
- * error propagation: log(x+errx) = log(x)+errx/x, so the absolute
- * error
- * in the result equals the relative error in the input,
- * xUlpDbl/xDbl .
- */
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), xUlpDbl / xDbl));
- return resul.round(mc);
- }
- } /* BigDecimalMath.log */
-
- /**
- * The natural logarithm.
- *
- * @param n
- * The main argument, a strictly positive integer.
- * @param mc
- * The requirements on the precision.
- * @return ln(n).
- * @since 2009-08-08
- * @author Richard J. Mathar
- * @throws Error
- */
- static public BigDecimal log(final int n, final MathContext mc) throws Error {
- /*
- * the value is undefined if x is negative.
- */
- if (n <= 0) {
- throw new ArithmeticException("Cannot take log of negative " + n);
- } else if (n == 1) {
- return BigDecimal.ZERO;
- } else if (n == 2) {
- if (mc.getPrecision() < BigDecimalMath.LOG2.precision()) {
- return BigDecimalMath.LOG2.round(mc);
- } else {
- /*
- * Broadhurst arXiv:math/9803067
- * a>
- * Error propagation: the error in log(2) is twice the error in
- * S(2,-5,...).
- */
- final int[] a = { 2, -5, -2, -7, -2, -5, 2, -3 };
- BigDecimal S = BigDecimalMath.broadhurstBBP(2, 1, a, SafeMathContext.newMathContext(1 + mc.getPrecision()));
- S = S.multiply(new BigDecimal(8));
- S = BigDecimalMath.sqrt(BigDecimalMath.divideRound(S, 3));
- return S.round(mc);
- }
- } else if (n == 3) {
- /*
- * summation of a series roughly proportional to (7/500)^k. Estimate
- * count
- * of terms to estimate the precision (drop the favorable additional
- * 1/k here): 0.013^k <= 10^(-precision), so k*log10(0.013) <=
- * -precision
- * so k>= precision/1.87.
- */
- final int kmax = (int) (mc.getPrecision() / 1.87);
- MathContext mcloc = SafeMathContext.newMathContext(mc.getPrecision() + 1 + (int) Math.log10(kmax * 0.693 / 1.098));
- BigDecimal log3 = BigDecimalMath.multiplyRound(BigDecimalMath.log(2, mcloc), 19);
-
- /*
- * log3 is roughly 1, so absolute and relative error are the same.
- * The
- * result will be divided by 12, so a conservative error is the one
- * already found in mc
- */
- final double eps = BigDecimalMath.prec2err(1.098, mc.getPrecision()) / kmax;
- final Rational r = new Rational(7153, 524288);
- Rational pk = new Rational(7153, 524288);
- for (int k = 1;; k++) {
- final Rational tmp = pk.divide(k);
- if (tmp.doubleValue() < eps) {
- break;
- }
-
- /*
- * how many digits of tmp do we need in the sum?
- */
- mcloc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(tmp.doubleValue(), eps));
- final BigDecimal c = pk.divide(k).BigDecimalValue(mcloc);
- if (k % 2 != 0) {
- log3 = log3.add(c);
- } else {
- log3 = log3.subtract(c);
- }
- pk = pk.multiply(r);
- }
- log3 = BigDecimalMath.divideRound(log3, 12);
- return log3.round(mc);
- } else if (n == 5) {
- /*
- * summation of a series roughly proportional to (7/160)^k. Estimate
- * count
- * of terms to estimate the precision (drop the favorable additional
- * 1/k here): 0.046^k <= 10^(-precision), so k*log10(0.046) <=
- * -precision
- * so k>= precision/1.33.
- */
- final int kmax = (int) (mc.getPrecision() / 1.33);
- MathContext mcloc = SafeMathContext.newMathContext(mc.getPrecision() + 1 + (int) Math.log10(kmax * 0.693 / 1.609));
- BigDecimal log5 = BigDecimalMath.multiplyRound(BigDecimalMath.log(2, mcloc), 14);
-
- /*
- * log5 is roughly 1.6, so absolute and relative error are the same.
- * The
- * result will be divided by 6, so a conservative error is the one
- * already found in mc
- */
- final double eps = BigDecimalMath.prec2err(1.6, mc.getPrecision()) / kmax;
- final Rational r = new Rational(759, 16384);
- Rational pk = new Rational(759, 16384);
- for (int k = 1;; k++) {
- final Rational tmp = pk.divide(k);
- if (tmp.doubleValue() < eps) {
- break;
- }
-
- /*
- * how many digits of tmp do we need in the sum?
- */
- mcloc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(tmp.doubleValue(), eps));
- final BigDecimal c = pk.divide(k).BigDecimalValue(mcloc);
- log5 = log5.subtract(c);
- pk = pk.multiply(r);
- }
- log5 = BigDecimalMath.divideRound(log5, 6);
- return log5.round(mc);
- } else if (n == 7) {
- /*
- * summation of a series roughly proportional to (1/8)^k. Estimate
- * count
- * of terms to estimate the precision (drop the favorable additional
- * 1/k here): 0.125^k <= 10^(-precision), so k*log10(0.125) <=
- * -precision
- * so k>= precision/0.903.
- */
- final int kmax = (int) (mc.getPrecision() / 0.903);
- MathContext mcloc = SafeMathContext.newMathContext(mc.getPrecision() + 1 + (int) Math.log10(kmax * 3 * 0.693 / 1.098));
- BigDecimal log7 = BigDecimalMath.multiplyRound(BigDecimalMath.log(2, mcloc), 3);
-
- /*
- * log7 is roughly 1.9, so absolute and relative error are the same.
- */
- final double eps = BigDecimalMath.prec2err(1.9, mc.getPrecision()) / kmax;
- final Rational r = new Rational(1, 8);
- Rational pk = new Rational(1, 8);
- for (int k = 1;; k++) {
- final Rational tmp = pk.divide(k);
- if (tmp.doubleValue() < eps) {
- break;
- }
-
- /*
- * how many digits of tmp do we need in the sum?
- */
- mcloc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(tmp.doubleValue(), eps));
- final BigDecimal c = pk.divide(k).BigDecimalValue(mcloc);
- log7 = log7.subtract(c);
- pk = pk.multiply(r);
- }
- return log7.round(mc);
-
- }
-
- else {
- /*
- * At this point one could either forward to the log(BigDecimal)
- * signature (implemented)
- * or decompose n into Ifactors and use an implemenation of all the
- * prime bases.
- * Estimate of the result; convert the mc argument to an absolute
- * error eps
- * log(n+errn) = log(n)+errn/n = log(n)+eps
- */
- final double res = Math.log(n);
- double eps = BigDecimalMath.prec2err(res, mc.getPrecision());
- /*
- * errn = eps*n, convert absolute error in result to requirement on
- * absolute error in input
- */
- eps *= n;
- /*
- * Convert this absolute requirement of error in n to a relative
- * error in n
- */
- final MathContext mcloc = SafeMathContext.newMathContext(1 + BigDecimalMath.err2prec(n, eps));
- /*
- * Padd n with a number of zeros to trigger the required accuracy in
- * the standard signature method
- */
- final BigDecimal nb = BigDecimalMath.scalePrec(new BigDecimal(n), mcloc);
- return BigDecimalMath.log(nb);
- }
- } /* log */
-
- /**
- * The natural logarithm.
- *
- * @param r
- * The main argument, a strictly positive value.
- * @param mc
- * The requirements on the precision.
- * @return ln(r).
- * @since 2009-08-09
- * @author Richard J. Mathar
- */
- static public BigDecimal log(final Rational r, final MathContext mc) {
- /*
- * the value is undefined if x is negative.
- */
- if (r.compareTo(Rational.ZERO) <= 0) {
- throw new ArithmeticException("Cannot take log of negative " + r.toString());
- } else if (r.compareTo(Rational.ONE) == 0) {
- return BigDecimal.ZERO;
- } else {
-
- /*
- * log(r+epsr) = log(r)+epsr/r. Convert the precision to an absolute
- * error in the result.
- * eps contains the required absolute error of the result, epsr/r.
- */
- final double eps = BigDecimalMath.prec2err(Math.log(r.doubleValue()), mc.getPrecision());
-
- /*
- * Convert this further into a requirement of the relative precision
- * in r, given that
- * epsr/r is also the relative precision of r. Add one safety digit.
- */
- final MathContext mcloc = SafeMathContext.newMathContext(1 + BigDecimalMath.err2prec(eps));
-
- final BigDecimal resul = BigDecimalMath.log(r.BigDecimalValue(mcloc));
-
- return resul.round(mc);
- }
- } /* log */
-
- /**
- * Power function.
- *
- * @param x
- * Base of the power.
- * @param y
- * Exponent of the power.
- * @return x^y.
- * The estimation of the relative error in the result is
- * |log(x)*err(y)|+|y*err(x)/x|
- * @since 2009-06-01
- */
- static public BigDecimal pow(final BigDecimal x, final BigDecimal y) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("Cannot power negative " + x.toString());
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- /*
- * return x^y = exp(y*log(x)) ;
- */
- final BigDecimal logx = BigDecimalMath.log(x);
- final BigDecimal ylogx = y.multiply(logx);
- final BigDecimal resul = BigDecimalMath.exp(ylogx);
-
- /*
- * The estimation of the relative error in the result is
- * |log(x)*err(y)|+|y*err(x)/x|
- */
- final double errR = Math.abs(logx.doubleValue() * y.ulp().doubleValue() / 2.) + Math.abs(y.doubleValue() * x.ulp().doubleValue() / 2. / x.doubleValue());
- final MathContext mcR = SafeMathContext.newMathContext(BigDecimalMath.err2prec(1.0, errR));
- return resul.round(mcR);
- }
- } /* BigDecimalMath.pow */
-
- /**
- * Raise to an integer power and round.
- *
- * @param x
- * The base.
- * @param n
- * The exponent.
- * @return x^n.
- * @since 2009-08-13
- * @since 2010-05-26 handle also n<0 cases.
- */
- static public BigDecimal powRound(final BigDecimal x, final int n) {
- /**
- * Special cases: x^1=x and x^0 = 1
- */
- if (n == 1) {
- return x;
- } else if (n == 0) {
- return BigDecimal.ONE;
- } else {
- /*
- * The relative error in the result is n times the relative error in
- * the input.
- * The estimation is slightly optimistic due to the integer rounding
- * of the logarithm.
- * Since the standard BigDecimal.pow can only handle positive n, we
- * split the algorithm.
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision() - (int) Math.log10(Math.abs(n)));
- if (n > 0) {
- return x.pow(n, mc);
- } else {
- return BigDecimal.ONE.divide(x.pow(-n), mc);
- }
- }
- } /* BigDecimalMath.powRound */
-
- /**
- * Raise to an integer power and round.
- *
- * @param x
- * The base.
- * @param n
- * The exponent.
- * The current implementation allows n only in the interval of
- * the standard int values.
- * @return x^n.
- * @since 2010-05-26
- */
- static public BigDecimal powRound(final BigDecimal x, final BigInteger n) {
- /**
- * For now, the implementation forwards to the cases where n
- * is in the range of the standard integers. This might, however, be
- * implemented to decompose larger powers into cascaded calls to smaller
- * ones.
- */
- if (n.compareTo(Rational.MAX_INT) > 0 || n.compareTo(Rational.MIN_INT) < 0) {
- throw new ProviderException("Not implemented: big power " + n.toString());
- } else {
- return BigDecimalMath.powRound(x, n.intValue());
- }
- } /* BigDecimalMath.powRound */
-
- /**
- * Raise to a fractional power and round.
- *
- * @param x
- * The base.
- * Generally enforced to be positive, with the exception of
- * integer exponents where
- * the sign is carried over according to the parity of the
- * exponent.
- * @param q
- * The exponent.
- * @return x^q.
- * @since 2010-05-26
- */
- static public BigDecimal powRound(final BigDecimal x, final Rational q) {
- /**
- * Special cases: x^1=x and x^0 = 1
- */
- if (q.compareTo(BigInteger.ONE) == 0) {
- return x;
- } else if (q.signum() == 0) {
- return BigDecimal.ONE;
- } else if (q.isInteger()) {
- /*
- * We are sure that the denominator is positive here, because
- * normalize() has been
- * called during constrution etc.
- */
- return BigDecimalMath.powRound(x, q.a);
- } else if (x.compareTo(BigDecimal.ZERO) < 0) {
- throw new ArithmeticException("Cannot power negative " + x.toString());
- } else if (q.isIntegerFrac()) {
- /*
- * Newton method with first estimate in double precision.
- * The disadvantage of this first line here is that the result
- * must fit in the
- * standard range of double precision numbers exponents.
- */
- final double estim = Math.pow(x.doubleValue(), q.doubleValue());
- BigDecimal res = new BigDecimal(estim);
-
- /*
- * The error in x^q is q*x^(q-1)*Delta(x).
- * The relative error is q*Delta(x)/x, q times the relative
- * error of x.
- */
- final BigDecimal reserr = new BigDecimal(0.5 * q.abs().doubleValue() * x.ulp().divide(x.abs(), MathContext.DECIMAL64).doubleValue());
-
- /*
- * The main point in branching the cases above is that this
- * conversion
- * will succeed for numerator and denominator of q.
- */
- final int qa = q.a.intValue();
- final int qb = q.b.intValue();
-
- /* Newton iterations. */
- final BigDecimal xpowa = BigDecimalMath.powRound(x, qa);
- for (;;) {
- /*
- * numerator and denominator of the Newton term. The major
- * disadvantage of this implementation is that the updates
- * of the powers
- * of the new estimate are done in full precision calling
- * BigDecimal.pow(),
- * which becomes slow if the denominator of q is large.
- */
- final BigDecimal nu = res.pow(qb).subtract(xpowa);
- final BigDecimal de = BigDecimalMath.multiplyRound(res.pow(qb - 1), q.b);
-
- /* estimated correction */
- BigDecimal eps = nu.divide(de, MathContext.DECIMAL64);
-
- final BigDecimal err = res.multiply(reserr, MathContext.DECIMAL64);
- final int precDiv = 2 + BigDecimalMath.err2prec(eps, err);
- if (precDiv <= 0) {
- /*
- * The case when the precision is already reached and
- * any precision
- * will do.
- */
- eps = nu.divide(de, MathContext.DECIMAL32);
- } else {
- final MathContext mc = SafeMathContext.newMathContext(precDiv);
- eps = nu.divide(de, mc);
- }
-
- res = BigDecimalMath.subtractRound(res, eps);
- /*
- * reached final precision if the relative error fell below
- * reserr,
- * |eps/res| < reserr
- */
- if (eps.divide(res, MathContext.DECIMAL64).abs().compareTo(reserr) < 0) {
- /*
- * delete the bits of extra precision kept in this
- * working copy.
- */
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(reserr.doubleValue()));
- return res.round(mc);
- }
- }
- } else {
- /*
- * The error in x^q is q*x^(q-1)*Delta(x) + Delta(q)*x^q*log(x).
- * The relative error is q/x*Delta(x) + Delta(q)*log(x). Convert
- * q to a floating point
- * number such that its relative error becomes negligible:
- * Delta(q)/q << Delta(x)/x/log(x) .
- */
- final int precq = 3 + BigDecimalMath.err2prec(x.ulp().divide(x, MathContext.DECIMAL64).doubleValue() / Math.log(x.doubleValue()));
- final MathContext mc = SafeMathContext.newMathContext(precq);
-
- /*
- * Perform the actual calculation as exponentiation of two
- * floating point numbers.
- */
- return BigDecimalMath.pow(x, q.BigDecimalValue(mc));
- }
- } /* BigDecimalMath.powRound */
-
- /**
- * Trigonometric sine.
- *
- * @param x
- * The argument in radians.
- * @return sin(x) in the range -1 to 1.
- * @throws Error
- * @since 2009-06-01
- */
- static public BigDecimal sin(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.sin(x.negate()).negate();
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- /*
- * reduce modulo 2pi
- */
- final BigDecimal res = BigDecimalMath.mod2pi(x);
- final double errpi = 0.5 * Math.abs(x.ulp().doubleValue());
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(3.14159, errpi));
- final BigDecimal p = BigDecimalMath.pi(mc);
- mc = SafeMathContext.newMathContext(x.precision());
- if (res.compareTo(p) > 0) {
- /*
- * pi 0) {
- /*
- * pi/2 0) {
- /*
- * x>pi/4: sin(x) = cos(pi/2-x)
- */
- return BigDecimalMath.cos(BigDecimalMath.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.
- */
- final 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
- */
- final int k = (int) (res.precision() / Math.log10(1.0 / res.doubleValue())) / 2;
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.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();
- final 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 = SafeMathContext.newMathContext(res.precision());
- return resul.round(mc);
- }
- }
- } /* sin */
-
- /**
- * Trigonometric cosine.
- *
- * @param x
- * The argument in radians.
- * @return cos(x) in the range -1 to 1.
- * @throws Error
- * @since 2009-06-01
- */
- static public BigDecimal cos(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.cos(x.negate());
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ONE;
- } else {
- /*
- * reduce modulo 2pi
- */
- final BigDecimal res = BigDecimalMath.mod2pi(x);
- final double errpi = 0.5 * Math.abs(x.ulp().doubleValue());
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(3.14159, errpi));
- final BigDecimal p = BigDecimalMath.pi(mc);
- mc = SafeMathContext.newMathContext(x.precision());
- if (res.compareTo(p) > 0) {
- /*
- * pi 0) {
- /*
- * pi/2 0) {
- /*
- * x>pi/4: cos(x) = sin(pi/2-x)
- */
- return BigDecimalMath.sin(BigDecimalMath.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.
- */
- final 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);
- */
- final int k = (int) (Math.log(xUlpDbl) / Math.log(res.doubleValue())) / 2;
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.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();
- final 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 = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), xUlpDbl));
- return resul.round(mc);
- }
- }
- } /* BigDecimalMath.cos */
-
- /**
- * The trigonometric tangent.
- *
- * @param x
- * the argument in radians.
- * @return the tan(x)
- * @throws Error
- */
- static public BigDecimal tan(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.tan(x.negate()).negate();
- } else {
- /*
- * reduce modulo pi
- */
- final BigDecimal res = BigDecimalMath.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) */
- final BigDecimal co = BigDecimalMath.cot(x);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(1. / co.doubleValue(), eps));
- return BigDecimal.ONE.divide(co, mc);
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(res, 2);
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr);
-
- BigDecimal resul = xhighpr.plus();
-
- /* x^(2i+1) */
- BigDecimal xpowi = xhighpr;
-
- final 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 = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- final BigDecimal c = BigDecimalMath.multiplyRound(xpowi, f);
- resul = resul.add(c);
- if (Math.abs(c.doubleValue()) < 0.1 * eps) {
- break;
- }
- }
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- }
- }
- } /* BigDecimalMath.tan */
-
- /**
- * The trigonometric co-tangent.
- *
- * @param x
- * the argument in radians.
- * @return the cot(x)
- * @throws Error
- * @since 2009-07-31
- */
- static public BigDecimal cot(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) == 0) {
- throw new ArithmeticException("Cannot take cot of zero " + x.toString());
- } else if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.cot(x.negate()).negate();
- } else {
- /*
- * reduce modulo pi
- */
- final BigDecimal res = BigDecimalMath.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 = BigDecimalMath.scalePrec(res, 2);
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr);
-
- MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(xhighpr.doubleValue(), eps));
- BigDecimal resul = BigDecimal.ONE.divide(xhighpr, mc);
-
- /* x^(2i-1) */
- BigDecimal xpowi = xhighpr;
-
- final 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);
- final BigDecimal c = BigDecimalMath.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 = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- }
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- }
- } /* BigDecimalMath.cot */
-
- /**
- * The inverse trigonometric sine.
- *
- * @param x
- * the argument.
- * @return the arcsin(x) in radians.
- * @throws Error
- */
- static public BigDecimal asin(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ONE) > 0 || x.compareTo(BigDecimal.ONE.negate()) < 0) {
- throw new ArithmeticException("Out of range argument " + x.toString() + " of asin");
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else if (x.compareTo(BigDecimal.ONE) == 0) {
- /*
- * arcsin(1) = pi/2
- */
- final double errpi = Math.sqrt(x.ulp().doubleValue());
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(3.14159, errpi));
- return BigDecimalMath.pi(mc).divide(new BigDecimal(2));
- } else if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.asin(x.negate()).negate();
- } else if (x.doubleValue() > 0.7) {
- final BigDecimal xCompl = BigDecimal.ONE.subtract(x);
- final double xDbl = x.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue() / 2.;
- final double eps = xUlpDbl / 2. / Math.sqrt(1. - Math.pow(xDbl, 2.));
-
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(xCompl, 3);
- final BigDecimal xhighprV = BigDecimalMath.divideRound(xhighpr, 4);
-
- BigDecimal resul = BigDecimal.ONE;
-
- /* x^(2i+1) */
- BigDecimal xpowi = BigDecimal.ONE;
-
- /* i factorial */
- BigInteger ifacN = BigInteger.ONE;
- BigInteger ifacD = BigInteger.ONE;
-
- for (int i = 1;; i++) {
- ifacN = ifacN.multiply(new BigInteger("" + (2 * i - 1)));
- ifacD = ifacD.multiply(new BigInteger("" + i));
- if (i == 1) {
- xpowi = xhighprV;
- } else {
- xpowi = BigDecimalMath.multiplyRound(xpowi, xhighprV);
- }
- final BigDecimal c = BigDecimalMath.divideRound(BigDecimalMath.multiplyRound(xpowi, ifacN), ifacD.multiply(new BigInteger("" + (2 * i + 1))));
- resul = resul.add(c);
- /*
- * series started 1+x/12+... which yields an estimate of the
- * sum's error
- */
- if (Math.abs(c.doubleValue()) < xUlpDbl / 120.) {
- break;
- }
- }
- /*
- * sqrt(2*z)*(1+...)
- */
- xpowi = BigDecimalMath.sqrt(xhighpr.multiply(new BigDecimal(2)));
- resul = BigDecimalMath.multiplyRound(xpowi, resul);
-
- MathContext mc = SafeMathContext.newMathContext(resul.precision());
- final BigDecimal pihalf = BigDecimalMath.pi(mc).divide(new BigDecimal(2));
-
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return pihalf.subtract(resul, mc);
- } else {
- /*
- * absolute error in the result is err(x)/sqrt(1-x^2) to lowest
- * order
- */
- final double xDbl = x.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue() / 2.;
- final double eps = xUlpDbl / 2. / Math.sqrt(1. - Math.pow(xDbl, 2.));
-
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr);
-
- BigDecimal resul = xhighpr.plus();
-
- /* x^(2i+1) */
- BigDecimal xpowi = xhighpr;
-
- /* i factorial */
- BigInteger ifacN = BigInteger.ONE;
- BigInteger ifacD = BigInteger.ONE;
-
- for (int i = 1;; i++) {
- ifacN = ifacN.multiply(new BigInteger("" + (2 * i - 1)));
- ifacD = ifacD.multiply(new BigInteger("" + 2 * i));
- xpowi = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- final BigDecimal c = BigDecimalMath.divideRound(BigDecimalMath.multiplyRound(xpowi, ifacN), ifacD.multiply(new BigInteger("" + (2 * i + 1))));
- resul = resul.add(c);
- if (Math.abs(c.doubleValue()) < 0.1 * eps) {
- break;
- }
- }
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- }
- } /* BigDecimalMath.asin */
-
- /**
- * The inverse trigonometric cosine.
- *
- * @param x
- * the argument.
- * @return the arccos(x) in radians.
- * @throws Error
- * @since 2009-09-29
- */
- static public BigDecimal acos(final BigDecimal x) throws Error {
- /*
- * Essentially forwarded to pi/2 - asin(x)
- */
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- BigDecimal resul = BigDecimalMath.asin(xhighpr);
- double eps = resul.ulp().doubleValue() / 2.;
-
- MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(3.14159, eps));
- final BigDecimal pihalf = BigDecimalMath.pi(mc).divide(new BigDecimal(2));
- resul = pihalf.subtract(resul);
-
- /*
- * absolute error in the result is err(x)/sqrt(1-x^2) to lowest order
- */
- final double xDbl = x.doubleValue();
- final double xUlpDbl = x.ulp().doubleValue() / 2.;
- eps = xUlpDbl / 2. / Math.sqrt(1. - Math.pow(xDbl, 2.));
-
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
-
- } /* BigDecimalMath.acos */
-
- /**
- * The inverse trigonometric tangent.
- *
- * @param x
- * the argument.
- * @return the principal value of arctan(x) in radians in the range -pi/2 to
- * +pi/2.
- * @throws Error
- * @since 2009-08-03
- */
- static public BigDecimal atan(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.atan(x.negate()).negate();
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else if (x.doubleValue() > 0.7 && x.doubleValue() < 3.0) {
- /*
- * Abramowitz-Stegun 4.4.34 convergence acceleration
- * 2*arctan(x) = arctan(2x/(1-x^2)) = arctan(y). x=(sqrt(1+y^2)-1)/y
- * This maps 0<=y<=3 to 0<=x<=0.73 roughly. Temporarily with 2
- * protectionist digits.
- */
- final BigDecimal y = BigDecimalMath.scalePrec(x, 2);
- final BigDecimal newx = BigDecimalMath.divideRound(BigDecimalMath.hypot(1, y).subtract(BigDecimal.ONE), y);
-
- /* intermediate result with too optimistic error estimate */
- final BigDecimal resul = BigDecimalMath.multiplyRound(BigDecimalMath.atan(newx), 2);
-
- /*
- * absolute error in the result is errx/(1+x^2), where errx = half
- * of the ulp.
- */
- final double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue()));
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- } else if (x.doubleValue() < 0.71) {
- /* Taylor expansion around x=0; Abramowitz-Stegun 4.4.42 */
-
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr).negate();
-
- BigDecimal resul = xhighpr.plus();
-
- /* signed x^(2i+1) */
- BigDecimal xpowi = xhighpr;
-
- /*
- * absolute error in the result is errx/(1+x^2), where errx = half
- * of the ulp.
- */
- final double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue()));
-
- for (int i = 1;; i++) {
- xpowi = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- final BigDecimal c = BigDecimalMath.divideRound(xpowi, 2 * i + 1);
-
- resul = resul.add(c);
- if (Math.abs(c.doubleValue()) < 0.1 * eps) {
- break;
- }
- }
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- } else {
- /* Taylor expansion around x=infinity; Abramowitz-Stegun 4.4.42 */
-
- /*
- * absolute error in the result is errx/(1+x^2), where errx = half
- * of the ulp.
- */
- final double eps = x.ulp().doubleValue() / (2.0 * Math.hypot(1.0, x.doubleValue()));
-
- /*
- * start with the term pi/2; gather its precision relative to the
- * expected result
- */
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(3.1416, eps));
- final BigDecimal onepi = BigDecimalMath.pi(mc);
- BigDecimal resul = onepi.divide(new BigDecimal(2));
-
- final BigDecimal xhighpr = BigDecimalMath.divideRound(-1, BigDecimalMath.scalePrec(x, 2));
- final BigDecimal xhighprSq = BigDecimalMath.multiplyRound(xhighpr, xhighpr).negate();
-
- /* signed x^(2i+1) */
- BigDecimal xpowi = xhighpr;
-
- for (int i = 0;; i++) {
- final BigDecimal c = BigDecimalMath.divideRound(xpowi, 2 * i + 1);
-
- resul = resul.add(c);
- if (Math.abs(c.doubleValue()) < 0.1 * eps) {
- break;
- }
- xpowi = BigDecimalMath.multiplyRound(xpowi, xhighprSq);
- }
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), eps));
- return resul.round(mc);
- }
- } /* BigDecimalMath.atan */
-
- /**
- * The hyperbolic cosine.
- *
- * @param x
- * The argument.
- * @return The cosh(x) = (exp(x)+exp(-x))/2 .
- * @author Richard J. Mathar
- * @throws Error
- * @since 2009-08-19
- */
- static public BigDecimal cosh(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.cos(x.negate());
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ONE;
- } else if (x.doubleValue() > 1.5) {
- /*
- * cosh^2(x) = 1+ sinh^2(x).
- */
- return BigDecimalMath.hypot(1, BigDecimalMath.sinh(x));
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- /* Simple Taylor expansion, sum_{0=1..infinity} x^(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.
- */
- final double xUlpDbl = 0.5 * x.ulp().doubleValue() * x.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)/(2k)! below this
- * value.
- * x^(2k) < xUlpDbl; (2k)*log(x) < log(xUlpDbl);
- */
- final int k = (int) (Math.log(xUlpDbl) / Math.log(x.doubleValue())) / 2;
-
- /*
- * The individual terms are all smaller than 1, so an estimate
- * of 1.0 for
- * the absolute value will give a safe relative error estimate
- * for the indivdual terms
- */
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.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(xhighpr).multiply(xhighpr);
- final 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.
- */
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), xUlpDbl));
- return resul.round(mc);
- }
- } /* BigDecimalMath.cosh */
-
- /**
- * The hyperbolic sine.
- *
- * @param x
- * the argument.
- * @return the sinh(x) = (exp(x)-exp(-x))/2 .
- * @author Richard J. Mathar
- * @throws Error
- * @since 2009-08-19
- */
- static public BigDecimal sinh(final BigDecimal x) throws Error {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.sinh(x.negate()).negate();
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else if (x.doubleValue() > 2.4) {
- /*
- * Move closer to zero with sinh(2x)= 2*sinh(x)*cosh(x).
- */
- final BigDecimal two = new BigDecimal(2);
- final BigDecimal xhalf = x.divide(two);
- final BigDecimal resul = BigDecimalMath.sinh(xhalf).multiply(BigDecimalMath.cosh(xhalf)).multiply(two);
- /*
- * The error in the result is set by the error in x itself.
- * The first derivative of sinh(x) is cosh(x), so the absolute
- * error
- * in the result is cosh(x)*errx, and the relative error is
- * coth(x)*errx = errx/tanh(x)
- */
- final double eps = Math.tanh(x.doubleValue());
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(0.5 * x.ulp().doubleValue() / eps));
- return resul.round(mc);
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- /*
- * Simple Taylor expansion, sum_{i=0..infinity} x^(2i+1)/(2i+1)!
- */
- BigDecimal resul = xhighpr;
-
- /* x^i */
- BigDecimal xpowi = xhighpr;
-
- /* 2i+1 factorial */
- BigInteger ifac = BigInteger.ONE;
-
- /*
- * The error in the result is set by the error in x itself.
- */
- final double xUlpDbl = x.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
- */
- final int k = (int) (x.precision() / Math.log10(1.0 / xhighpr.doubleValue())) / 2;
- final MathContext mcTay = SafeMathContext.newMathContext(BigDecimalMath.err2prec(x.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(xhighpr).multiply(xhighpr);
- final 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.
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return resul.round(mc);
- }
- } /* BigDecimalMath.sinh */
-
- /**
- * The hyperbolic tangent.
- *
- * @param x
- * The argument.
- * @return The tanh(x) = sinh(x)/cosh(x).
- * @author Richard J. Mathar
- * @since 2009-08-20
- */
- static public BigDecimal tanh(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.tanh(x.negate()).negate();
- } else if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
-
- /*
- * tanh(x) = (1-e^(-2x))/(1+e^(-2x)) .
- */
- final BigDecimal exp2x = BigDecimalMath.exp(xhighpr.multiply(new BigDecimal(-2)));
-
- /*
- * The error in tanh x is err(x)/cosh^2(x).
- */
- final double eps = 0.5 * x.ulp().doubleValue() / Math.pow(Math.cosh(x.doubleValue()), 2.0);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(Math.tanh(x.doubleValue()), eps));
- return BigDecimal.ONE.subtract(exp2x).divide(BigDecimal.ONE.add(exp2x), mc);
- }
- } /* BigDecimalMath.tanh */
-
- /**
- * The inverse hyperbolic sine.
- *
- * @param x
- * The argument.
- * @return The arcsinh(x) .
- * @author Richard J. Mathar
- * @since 2009-08-20
- */
- static public BigDecimal asinh(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
-
- /*
- * arcsinh(x) = log(x+hypot(1,x))
- */
- final BigDecimal logx = BigDecimalMath.log(BigDecimalMath.hypot(1, xhighpr).add(xhighpr));
-
- /*
- * The absolute error in arcsinh x is err(x)/sqrt(1+x^2)
- */
- final double xDbl = x.doubleValue();
- final double eps = 0.5 * x.ulp().doubleValue() / Math.hypot(1., xDbl);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(logx.doubleValue(), eps));
- return logx.round(mc);
- }
- } /* BigDecimalMath.asinh */
-
- /**
- * The inverse hyperbolic cosine.
- *
- * @param x
- * The argument.
- * @return The arccosh(x) .
- * @author Richard J. Mathar
- * @since 2009-08-20
- */
- static public BigDecimal acosh(final BigDecimal x) {
- if (x.compareTo(BigDecimal.ONE) < 0) {
- throw new ArithmeticException("Out of range argument cosh " + x.toString());
- } else if (x.compareTo(BigDecimal.ONE) == 0) {
- return BigDecimal.ZERO;
- } else {
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
-
- /*
- * arccosh(x) = log(x+sqrt(x^2-1))
- */
- final BigDecimal logx = BigDecimalMath.log(BigDecimalMath.sqrt(xhighpr.pow(2).subtract(BigDecimal.ONE)).add(xhighpr));
-
- /*
- * The absolute error in arcsinh x is err(x)/sqrt(x^2-1)
- */
- final double xDbl = x.doubleValue();
- final double eps = 0.5 * x.ulp().doubleValue() / Math.sqrt(xDbl * xDbl - 1.);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(logx.doubleValue(), eps));
- return logx.round(mc);
- }
- } /* BigDecimalMath.acosh */
-
- /**
- * The Gamma function.
- *
- * @param x
- * The argument.
- * @return Gamma(x).
- * @throws Error
- * @since 2009-08-06
- */
- static public BigDecimal Gamma(final BigDecimal x) throws Error {
- /*
- * reduce to interval near 1.0 with the functional relation,
- * Abramowitz-Stegun 6.1.33
- */
- if (x.compareTo(BigDecimal.ZERO) < 0) {
- return BigDecimalMath.divideRound(BigDecimalMath.Gamma(x.add(BigDecimal.ONE)), x);
- } else if (x.doubleValue() > 1.5) {
- /*
- * Gamma(x) = Gamma(xmin+n) = Gamma(xmin)*Pochhammer(xmin,n).
- */
- final int n = (int) (x.doubleValue() - 0.5);
- final BigDecimal xmin1 = x.subtract(new BigDecimal(n));
- return BigDecimalMath.multiplyRound(BigDecimalMath.Gamma(xmin1), BigDecimalMath.pochhammer(xmin1, n));
- } else {
- /*
- * apply Abramowitz-Stegun 6.1.33
- */
- BigDecimal z = x.subtract(BigDecimal.ONE);
-
- /*
- * add intermediately 2 digits to the partial sum accumulation
- */
- z = BigDecimalMath.scalePrec(z, 2);
- MathContext mcloc = SafeMathContext.newMathContext(z.precision());
-
- /*
- * measure of the absolute error is the relative error in the first,
- * logarithmic term
- */
- double eps = x.ulp().doubleValue() / x.doubleValue();
-
- BigDecimal resul = BigDecimalMath.log(BigDecimalMath.scalePrec(x, 2)).negate();
-
- if (x.compareTo(BigDecimal.ONE) != 0) {
-
- final BigDecimal gammCompl = BigDecimal.ONE.subtract(BigDecimalMath.gamma(mcloc));
- resul = resul.add(BigDecimalMath.multiplyRound(z, gammCompl));
- for (int n = 2;; n++) {
- /*
- * multiplying z^n/n by zeta(n-1) means that the two
- * relative errors add.
- * so the requirement in the relative error of zeta(n)-1 is
- * that this is somewhat
- * smaller than the relative error in z^n/n (the absolute
- * error of thelatter is the
- * absolute error in z)
- */
- BigDecimal c = BigDecimalMath.divideRound(z.pow(n, mcloc), n);
- MathContext m = SafeMathContext.newMathContext(BigDecimalMath.err2prec(n * z.ulp().doubleValue() / 2. / z.doubleValue()));
- c = c.round(m);
-
- /*
- * At larger n, zeta(n)-1 is roughly 1/2^n. The product is
- * c/2^n.
- * The relative error in c is c.ulp/2/c . The error in the
- * product should be small versus eps/10.
- * Error from 1/2^n is c*err(sigma-1).
- * We need a relative error of zeta-1 of the order of
- * c.ulp/50/c. This is an absolute
- * error in zeta-1 of c.ulp/50/c/2^n, and also the absolute
- * error in zeta, because zeta is
- * of the order of 1.
- */
- if (eps / 100. / c.doubleValue() < 0.01) {
- m = SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps / 100. / c.doubleValue()));
- } else {
- m = SafeMathContext.newMathContext(2);
- }
- /* zeta(n) -1 */
- final BigDecimal zetm1 = BigDecimalMath.zeta(n, m).subtract(BigDecimal.ONE);
- c = BigDecimalMath.multiplyRound(c, zetm1);
-
- if (n % 2 == 0) {
- resul = resul.add(c);
- } else {
- resul = resul.subtract(c);
- }
-
- /*
- * alternating sum, so truncating as eps is reached suffices
- */
- if (Math.abs(c.doubleValue()) < eps) {
- break;
- }
- }
- }
-
- /*
- * The relative error in the result is the absolute error in the
- * input variable times the digamma (psi) value at that point.
- */
- final double zdbl = z.doubleValue();
- eps = BigDecimalMath.psi(zdbl) * x.ulp().doubleValue() / 2.;
- mcloc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps));
- return BigDecimalMath.exp(resul).round(mcloc);
- }
- } /* BigDecimalMath.gamma */
-
- /**
- * The Gamma function.
- *
- * @param q
- * The argument.
- * @param mc
- * The required accuracy in the result.
- * @return Gamma(x).
- * @throws Error
- * @since 2010-05-26
- */
- static public BigDecimal Gamma(final Rational q, final MathContext mc) throws Error {
- if (q.isBigInteger()) {
- if (q.compareTo(Rational.ZERO) <= 0) {
- throw new ArithmeticException("Gamma at " + q.toString());
- } else {
- /* Gamma(n) = (n-1)! */
- final Factorial f = new Factorial();
- final BigInteger g = f.at(q.trunc().intValue() - 1);
- return BigDecimalMath.scalePrec(new BigDecimal(g), mc);
- }
- } else if (q.b.intValue() == 2) {
- /*
- * half integer cases which are related to sqrt(pi)
- */
- final BigDecimal p = BigDecimalMath.sqrt(BigDecimalMath.pi(mc));
- if (q.compareTo(Rational.ZERO) >= 0) {
- Rational pro = Rational.ONE;
- Rational f = q.subtract(1);
- while (f.compareTo(Rational.ZERO) > 0) {
- pro = pro.multiply(f);
- f = f.subtract(1);
- }
- return BigDecimalMath.multiplyRound(p, pro);
- } else {
- Rational pro = Rational.ONE;
- Rational f = q;
- while (f.compareTo(Rational.ZERO) < 0) {
- pro = pro.divide(f);
- f = f.add(1);
- }
- return BigDecimalMath.multiplyRound(p, pro);
- }
- } else {
- /*
- * The relative error of the result is psi(x)*Delta(x). Tune
- * Delta(x) such
- * that this is equivalent to mc: Delta(x) = precision/psi(x).
- */
- final double qdbl = q.doubleValue();
- final double deltx = 5. * Math.pow(10., -mc.getPrecision()) / BigDecimalMath.psi(qdbl);
-
- final MathContext mcx = SafeMathContext.newMathContext(BigDecimalMath.err2prec(qdbl, deltx));
- final BigDecimal x = q.BigDecimalValue(mcx);
-
- /* forward calculation to the general floating point case */
- return BigDecimalMath.Gamma(x);
- }
- } /* BigDecimalMath.Gamma */
-
- /**
- * Pochhammer's function.
- *
- * @param x
- * The main argument.
- * @param n
- * The non-negative index.
- * @return (x)_n = x(x+1)(x+2)*...*(x+n-1).
- * @since 2009-08-19
- */
- 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("Not implemented: pochhammer with negative index " + n);
- } else if (n == 0) {
- return BigDecimal.ONE;
- } else {
- /*
- * internally two safety digits
- */
- final BigDecimal xhighpr = BigDecimalMath.scalePrec(x, 2);
- BigDecimal resul = xhighpr;
-
- final double xUlpDbl = x.ulp().doubleValue();
- final 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 = SafeMathContext.newMathContext(4 + BigDecimalMath.err2prec(eps));
- resul = resul.round(mcloc);
- }
- return resul.round(SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps)));
- }
- } /* BigDecimalMath.pochhammer */
-
- /**
- * Reduce value to the interval [0,2*Pi].
- *
- * @param x
- * the original value
- * @return the value modulo 2*pi in the interval from 0 to 2*pi.
- * @throws Error
- * @since 2009-06-01
- */
- static public BigDecimal mod2pi(final BigDecimal x) throws Error {
- /*
- * write x= 2*pi*k+r with the precision in r defined by the precision of
- * x and not
- * compromised by the precision of 2*pi, so the ulp of 2*pi*k should
- * match the ulp of x.
- * First get a guess of k to figure out how many digits of 2*pi are
- * needed.
- */
- final int k = (int) (0.5 * x.doubleValue() / Math.PI);
-
- /*
- * want to have err(2*pi*k)< err(x)=0.5*x.ulp, so err(pi) = err(x)/(4k)
- * with two safety digits
- */
- double err2pi;
- if (k != 0) {
- err2pi = 0.25 * Math.abs(x.ulp().doubleValue() / k);
- } else {
- err2pi = 0.5 * Math.abs(x.ulp().doubleValue());
- }
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(6.283, err2pi));
- final BigDecimal twopi = BigDecimalMath.pi(mc).multiply(new BigDecimal(2));
-
- /*
- * Delegate the actual operation to the BigDecimal class, which may
- * return
- * a negative value of x was negative .
- */
- BigDecimal res = x.remainder(twopi);
- if (res.compareTo(BigDecimal.ZERO) < 0) {
- res = res.add(twopi);
- }
-
- /*
- * The actual precision is set by the input value, its absolute value of
- * x.ulp()/2.
- */
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(res.doubleValue(), x.ulp().doubleValue() / 2.));
- return res.round(mc);
- } /* mod2pi */
-
- /**
- * Reduce value to the interval [-Pi/2,Pi/2].
- *
- * @param x
- * The original value
- * @return The value modulo pi, shifted to the interval from -Pi/2 to Pi/2.
- * @throws Error
- * @since 2009-07-31
- */
- static public BigDecimal modpi(final BigDecimal x) throws Error {
- /*
- * write x= pi*k+r with the precision in r defined by the precision of x
- * and not
- * compromised by the precision of pi, so the ulp of pi*k should match
- * the ulp of x.
- * First get a guess of k to figure out how many digits of pi are
- * needed.
- */
- final int k = (int) (x.doubleValue() / Math.PI);
-
- /*
- * want to have err(pi*k)< err(x)=x.ulp/2, so err(pi) = err(x)/(2k) with
- * two safety digits
- */
- double errpi;
- if (k != 0) {
- errpi = 0.5 * Math.abs(x.ulp().doubleValue() / k);
- } else {
- errpi = 0.5 * Math.abs(x.ulp().doubleValue());
- }
- MathContext mc = SafeMathContext.newMathContext(2 + BigDecimalMath.err2prec(3.1416, errpi));
- final BigDecimal onepi = BigDecimalMath.pi(mc);
- final BigDecimal pihalf = onepi.divide(new BigDecimal(2));
-
- /*
- * Delegate the actual operation to the BigDecimal class, which may
- * return
- * a negative value of x was negative .
- */
- BigDecimal res = x.remainder(onepi);
- if (res.compareTo(pihalf) > 0) {
- res = res.subtract(onepi);
- } else if (res.compareTo(pihalf.negate()) < 0) {
- res = res.add(onepi);
- }
-
- /*
- * The actual precision is set by the input value, its absolute value of
- * x.ulp()/2.
- */
- mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(res.doubleValue(), x.ulp().doubleValue() / 2.));
- return res.round(mc);
- } /* modpi */
-
- /**
- * Riemann zeta function.
- *
- * @param n
- * The positive integer argument.
- * @param mc
- * Specification of the accuracy of the result.
- * @return zeta(n).
- * @throws Error
- * @since 2009-08-05
- */
- static public BigDecimal zeta(final int n, final MathContext mc) throws Error {
- if (n <= 0) {
- throw new ProviderException("Not implemented: zeta at negative argument " + n);
- }
- if (n == 1) {
- throw new ArithmeticException("Pole at zeta(1) ");
- }
-
- if (n % 2 == 0) {
- /*
- * Even indices. Abramowitz-Stegun 23.2.16. Start with
- * 2^(n-1)*B(n)/n!
- */
- Rational b = new Bernoulli().at(n).abs();
- b = b.divide(new Factorial().at(n));
- b = b.multiply(BigInteger.ONE.shiftLeft(n - 1));
-
- /*
- * to be multiplied by pi^n. Absolute error in the result of pi^n is
- * n times
- * error in pi times pi^(n-1). Relative error is n*error(pi)/pi,
- * requested by mc.
- * Need one more digit in pi if n=10, two digits if n=100 etc, and
- * add one extra digit.
- */
- final MathContext mcpi = SafeMathContext.newMathContext(mc.getPrecision() + (int) Math.log10(10.0 * n));
- final BigDecimal piton = BigDecimalMath.pi(mcpi).pow(n, mc);
- return BigDecimalMath.multiplyRound(piton, b);
- } else if (n == 3) {
- /*
- * Broadhurst BBP arXiv:math/9803067
- * Error propagation: S31 is roughly 0.087, S33 roughly 0.131
- */
- final int[] a31 = { 1, -7, -1, 10, -1, -7, 1, 0 };
- final int[] a33 = { 1, 1, -1, -2, -1, 1, 1, 0 };
- BigDecimal S31 = BigDecimalMath.broadhurstBBP(3, 1, a31, mc);
- BigDecimal S33 = BigDecimalMath.broadhurstBBP(3, 3, a33, mc);
- S31 = S31.multiply(new BigDecimal(48));
- S33 = S33.multiply(new BigDecimal(32));
- return S31.add(S33).divide(new BigDecimal(7), mc);
- } else if (n == 5) {
- /*
- * Broadhurst BBP arXiv:math/9803067
- * Error propagation: S51 is roughly -11.15, S53 roughly 22.165, S55
- * is roughly 0.031
- * 9*2048*S51/6265 = -3.28. 7*2038*S53/61651= 5.07.
- * 738*2048*S55/61651= 0.747.
- * The result is of the order 1.03, so we add 2 digits to S51 and
- * S52 and one digit to S55.
- */
- final int[] a51 = { 31, -1614, -31, -6212, -31, -1614, 31, 74552 };
- final int[] a53 = { 173, 284, -173, -457, -173, 284, 173, -111 };
- final int[] a55 = { 1, 0, -1, -1, -1, 0, 1, 1 };
- BigDecimal S51 = BigDecimalMath.broadhurstBBP(5, 1, a51, SafeMathContext.newMathContext(2 + mc.getPrecision()));
- BigDecimal S53 = BigDecimalMath.broadhurstBBP(5, 3, a53, SafeMathContext.newMathContext(2 + mc.getPrecision()));
- BigDecimal S55 = BigDecimalMath.broadhurstBBP(5, 5, a55, SafeMathContext.newMathContext(1 + mc.getPrecision()));
- S51 = S51.multiply(new BigDecimal(18432));
- S53 = S53.multiply(new BigDecimal(14336));
- S55 = S55.multiply(new BigDecimal(1511424));
- return S51.add(S53).subtract(S55).divide(new BigDecimal(62651), mc);
- } else {
- /*
- * Cohen et al Exp Math 1 (1) (1992) 25
- */
- Rational betsum = new Rational();
- final Bernoulli bern = new Bernoulli();
- final Factorial fact = new Factorial();
- for (int npr = 0; npr <= (n + 1) / 2; npr++) {
- Rational b = bern.at(2 * npr).multiply(bern.at(n + 1 - 2 * npr));
- b = b.divide(fact.at(2 * npr)).divide(fact.at(n + 1 - 2 * npr));
- b = b.multiply(1 - 2 * npr);
- if (npr % 2 == 0) {
- betsum = betsum.add(b);
- } else {
- betsum = betsum.subtract(b);
- }
- }
- betsum = betsum.divide(n - 1);
- /*
- * The first term, including the facor (2pi)^n, is essentially most
- * of the result, near one. The second term below is roughly in the
- * range 0.003 to 0.009.
- * So the precision here is matching the precisionn requested by mc,
- * and the precision
- * requested for 2*pi is in absolute terms adjusted.
- */
- final MathContext mcloc = SafeMathContext.newMathContext(2 + mc.getPrecision() + (int) Math.log10(n));
- BigDecimal ftrm = BigDecimalMath.pi(mcloc).multiply(new BigDecimal(2));
- ftrm = ftrm.pow(n);
- ftrm = BigDecimalMath.multiplyRound(ftrm, betsum.BigDecimalValue(mcloc));
- BigDecimal exps = new BigDecimal(0);
-
- /*
- * the basic accuracy of the accumulated terms before multiplication
- * with 2
- */
- double eps = Math.pow(10., -mc.getPrecision());
-
- if (n % 4 == 3) {
- /*
- * since the argument n is at least 7 here, the drop
- * of the terms is at rather constant pace at least 10^-3, for
- * example
- * 0.0018, 0.2e-7, 0.29e-11, 0.74e-15 etc for npr=1,2,3.... We
- * want 2 times these terms
- * fall below eps/10.
- */
- final int kmax = mc.getPrecision() / 3;
- eps /= kmax;
- /*
- * need an error of eps for 2/(exp(2pi)-1) = 0.0037
- * The absolute error is
- * 4*exp(2pi)*err(pi)/(exp(2pi)-1)^2=0.0075*err(pi)
- */
- BigDecimal exp2p = BigDecimalMath.pi(SafeMathContext.newMathContext(3 + BigDecimalMath.err2prec(3.14, eps / 0.0075)));
- exp2p = BigDecimalMath.exp(exp2p.multiply(new BigDecimal(2)));
- BigDecimal c = exp2p.subtract(BigDecimal.ONE);
- exps = BigDecimalMath.divideRound(1, c);
- for (int npr = 2; npr <= kmax; npr++) {
- /*
- * the error estimate above for npr=1 is the worst case of
- * the absolute error created by an error in 2pi. So we can
- * safely re-use the exp2p value computed above without
- * reassessment of its error.
- */
- c = BigDecimalMath.powRound(exp2p, npr).subtract(BigDecimal.ONE);
- c = BigDecimalMath.multiplyRound(c, new BigInteger("" + npr).pow(n));
- c = BigDecimalMath.divideRound(1, c);
- exps = exps.add(c);
- }
- } else {
- /*
- * since the argument n is at least 9 here, the drop
- * of the terms is at rather constant pace at least 10^-3, for
- * example
- * 0.0096, 0.5e-7, 0.3e-11, 0.6e-15 etc. We want these terms
- * fall below eps/10.
- */
- final int kmax = (1 + mc.getPrecision()) / 3;
- eps /= kmax;
- /*
- * need an error of eps for
- * 2/(exp(2pi)-1)*(1+4*Pi/8/(1-exp(-2pi)) = 0.0096
- * at k=7 or = 0.00766 at k=13 for example.
- * The absolute error is 0.017*err(pi) at k=9, 0.013*err(pi) at
- * k=13, 0.012 at k=17
- */
- BigDecimal twop = BigDecimalMath.pi(SafeMathContext.newMathContext(3 + BigDecimalMath.err2prec(3.14, eps / 0.017)));
- twop = twop.multiply(new BigDecimal(2));
- final BigDecimal exp2p = BigDecimalMath.exp(twop);
- BigDecimal c = exp2p.subtract(BigDecimal.ONE);
- exps = BigDecimalMath.divideRound(1, c);
- c = BigDecimal.ONE.subtract(BigDecimalMath.divideRound(1, exp2p));
- c = BigDecimalMath.divideRound(twop, c).multiply(new BigDecimal(2));
- c = BigDecimalMath.divideRound(c, n - 1).add(BigDecimal.ONE);
- exps = BigDecimalMath.multiplyRound(exps, c);
- for (int npr = 2; npr <= kmax; npr++) {
- c = BigDecimalMath.powRound(exp2p, npr).subtract(BigDecimal.ONE);
- c = BigDecimalMath.multiplyRound(c, new BigInteger("" + npr).pow(n));
-
- BigDecimal d = BigDecimalMath.divideRound(1, exp2p.pow(npr));
- d = BigDecimal.ONE.subtract(d);
- d = BigDecimalMath.divideRound(twop, d).multiply(new BigDecimal(2 * npr));
- d = BigDecimalMath.divideRound(d, n - 1).add(BigDecimal.ONE);
-
- d = BigDecimalMath.divideRound(d, c);
-
- exps = exps.add(d);
- }
- }
- exps = exps.multiply(new BigDecimal(2));
- return ftrm.subtract(exps, mc);
- }
- } /* zeta */
-
- /**
- * Riemann zeta function.
- *
- * @param n
- * The positive integer argument.
- * @return zeta(n)-1.
- * @throws Error
- * @since 2009-08-20
- */
- static public double zeta1(final int n) throws Error {
- /*
- * precomputed static table in double precision
- */
- final double[] zmin1 = { 0., 0., 6.449340668482264364724151666e-01, 2.020569031595942853997381615e-01, 8.232323371113819151600369654e-02, 3.692775514336992633136548646e-02, 1.734306198444913971451792979e-02, 8.349277381922826839797549850e-03, 4.077356197944339378685238509e-03, 2.008392826082214417852769232e-03, 9.945751278180853371459589003e-04, 4.941886041194645587022825265e-04, 2.460865533080482986379980477e-04, 1.227133475784891467518365264e-04, 6.124813505870482925854510514e-05, 3.058823630702049355172851064e-05, 1.528225940865187173257148764e-05, 7.637197637899762273600293563e-06, 3.817293264999839856461644622e-06, 1.908212716553938925656957795e-06, 9.539620338727961131520386834e-07, 4.769329867878064631167196044e-07, 2.384505027277329900036481868e-07, 1.192199259653110730677887189e-07, 5.960818905125947961244020794e-08, 2.980350351465228018606370507e-08, 1.490155482836504123465850663e-08, 7.450711789835429491981004171e-09, 3.725334024788457054819204018e-09, 1.862659723513049006403909945e-09, 9.313274324196681828717647350e-10, 4.656629065033784072989233251e-10, 2.328311833676505492001455976e-10, 1.164155017270051977592973835e-10, 5.820772087902700889243685989e-11, 2.910385044497099686929425228e-11, 1.455192189104198423592963225e-11, 7.275959835057481014520869012e-12, 3.637979547378651190237236356e-12, 1.818989650307065947584832101e-12, 9.094947840263889282533118387e-13, 4.547473783042154026799112029e-13, 2.273736845824652515226821578e-13, 1.136868407680227849349104838e-13, 5.684341987627585609277182968e-14, 2.842170976889301855455073705e-14, 1.421085482803160676983430714e-14, 7.105427395210852712877354480e-15, 3.552713691337113673298469534e-15, 1.776356843579120327473349014e-15, 8.881784210930815903096091386e-16, 4.440892103143813364197770940e-16, 2.220446050798041983999320094e-16, 1.110223025141066133720544570e-16, 5.551115124845481243723736590e-17, 2.775557562136124172581632454e-17, 1.387778780972523276283909491e-17, 6.938893904544153697446085326e-18, 3.469446952165922624744271496e-18, 1.734723476047576572048972970e-18, 8.673617380119933728342055067e-19, 4.336808690020650487497023566e-19, 2.168404344997219785013910168e-19, 1.084202172494241406301271117e-19, 5.421010862456645410918700404e-20, 2.710505431223468831954621312e-20, 1.355252715610116458148523400e-20, 6.776263578045189097995298742e-21, 3.388131789020796818085703100e-21, 1.694065894509799165406492747e-21, 8.470329472546998348246992609e-22, 4.235164736272833347862270483e-22, 2.117582368136194731844209440e-22, 1.058791184068023385226500154e-22, 5.293955920339870323813912303e-23, 2.646977960169852961134116684e-23, 1.323488980084899080309451025e-23, 6.617444900424404067355245332e-24, 3.308722450212171588946956384e-24, 1.654361225106075646229923677e-24, 8.271806125530344403671105617e-25, 4.135903062765160926009382456e-25, 2.067951531382576704395967919e-25, 1.033975765691287099328409559e-25, 5.169878828456431320410133217e-26, 2.584939414228214268127761771e-26, 1.292469707114106670038112612e-26, 6.462348535570531803438002161e-27, 3.231174267785265386134814118e-27, 1.615587133892632521206011406e-27, 8.077935669463162033158738186e-28, 4.038967834731580825622262813e-28, 2.019483917365790349158762647e-28, 1.009741958682895153361925070e-28, 5.048709793414475696084771173e-29, 2.524354896707237824467434194e-29, 1.262177448353618904375399966e-29, 6.310887241768094495682609390e-30, 3.155443620884047239109841220e-30, 1.577721810442023616644432780e-30, 7.888609052210118073520537800e-31 };
- if (n <= 0) {
- throw new ProviderException("Not implemented: zeta at negative argument " + n);
- }
- if (n == 1) {
- throw new ArithmeticException("Pole at zeta(1) ");
- }
-
- if (n < zmin1.length) {
- /* look it up if available */
- return zmin1[n];
- } else {
- /*
- * Result is roughly 2^(-n), desired accuracy 18 digits. If zeta(n)
- * is computed, the equivalent accuracy
- * in relative units is higher, because zeta is around 1.
- */
- final double eps = 1.e-18 * Math.pow(2., -n);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(eps));
- return BigDecimalMath.zeta(n, mc).subtract(BigDecimal.ONE).doubleValue();
- }
- } /* zeta */
-
- /**
- * trigonometric cot.
- *
- * @param x
- * The argument.
- * @return cot(x) = 1/tan(x).
- */
- static public double cot(final double x) {
- return 1. / Math.tan(x);
- }
-
- /**
- * Digamma function.
- *
- * @param x
- * The main argument.
- * @return psi(x).
- * The error is sometimes up to 10 ulp, where AS 6.3.15 suffers from
- * cancellation of digits and psi=0
- * @throws Error
- * @since 2009-08-26
- */
- static public double psi(final double x) throws Error {
- /*
- * the single positive zero of psi(x)
- */
- final double psi0 = 1.46163214496836234126265954232572132846819;
- if (x > 2.0) {
- /*
- * Reduce to a value near x=1 with the standard recurrence formula.
- * Abramowitz-Stegun 6.3.5
- */
- final int m = (int) (x - 0.5);
- final double xmin1 = x - m;
- double resul = 0.;
- for (int i = 1; i <= m; i++) {
- resul += 1. / (x - i);
- }
- return resul + BigDecimalMath.psi(xmin1);
- } else if (Math.abs(x - psi0) < 0.55) {
- /*
- * Taylor approximation around the local zero
- */
- final double[] psiT0 = { 9.67672245447621170427e-01, -4.42763168983592106093e-01, 2.58499760955651010624e-01, -1.63942705442406527504e-01, 1.07824050691262365757e-01, -7.21995612564547109261e-02, 4.88042881641431072251e-02, -3.31611264748473592923e-02, 2.25976482322181046596e-02, -1.54247659049489591388e-02, 1.05387916166121753881e-02, -7.20453438635686824097e-03, 4.92678139572985344635e-03, -3.36980165543932808279e-03, 2.30512632673492783694e-03, -1.57693677143019725927e-03, 1.07882520191629658069e-03, -7.38070938996005129566e-04, 5.04953265834602035177e-04, -3.45468025106307699556e-04, 2.36356015640270527924e-04, -1.61706220919748034494e-04, 1.10633727687474109041e-04, -7.56917958219506591924e-05, 5.17857579522208086899e-05, -3.54300709476596063157e-05, 2.42400661186013176527e-05, -1.65842422718541333752e-05, 1.13463845846638498067e-05, -7.76281766846209442527e-06, 5.31106092088986338732e-06, -3.63365078980104566837e-06, 2.48602273312953794890e-06, -1.70085388543326065825e-06, 1.16366753635488427029e-06, -7.96142543124197040035e-07, 5.44694193066944527850e-07, -3.72661612834382295890e-07, 2.54962655202155425666e-07, -1.74436951177277452181e-07, 1.19343948298302427790e-07, -8.16511518948840884084e-08, 5.58629968353217144428e-08, -3.82196006191749421243e-08, 2.61485769519618662795e-08, -1.78899848649114926515e-08, 1.22397314032336619391e-08, -8.37401629767179054290e-09, 5.72922285984999377160e-09 };
- final double xdiff = x - psi0;
- double resul = 0.;
- for (int i = psiT0.length - 1; i >= 0; i--) {
- resul = resul * xdiff + psiT0[i];
- }
- return resul * xdiff;
- } else if (x < 0.) {
- /* Reflection formula */
- final double xmin = 1. - x;
- return BigDecimalMath.psi(xmin) + Math.PI / Math.tan(Math.PI * xmin);
- } else {
- final double xmin1 = x - 1;
- double resul = 0.;
- for (int k = 26; k >= 1; k--) {
- resul -= BigDecimalMath.zeta1(2 * k + 1);
- resul *= xmin1 * xmin1;
- }
- /* 0.422... = 1 -gamma */
- return resul + 0.422784335098467139393487909917597568 + 0.5 / xmin1 - 1. / (1 - xmin1 * xmin1) - Math.PI / (2. * Math.tan(Math.PI * xmin1));
- }
- } /* psi */
-
- /**
- * Broadhurst ladder sequence.
- *
- * @param a
- * The vector of 8 integer arguments
- * @param mc
- * Specification of the accuracy of the result
- * @return S_(n,p)(a)
- * @throws Error
- * @since 2009-08-09
- * @see arXiv:math/9803067
- */
- static protected BigDecimal broadhurstBBP(final int n, final int p, final int a[], final MathContext mc)
- throws Error {
- /*
- * 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(k, n);
- }
-
- /*
- * Convert the relative precision and estimate of the result into an
- * absolute precision.
- */
- double eps = BigDecimalMath.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
- */
- final 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)
- */
- final 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;
- }
- final MathContext mcloc = SafeMathContext.newMathContext(1 + BigDecimalMath.err2prec(r.doubleValue(), eps));
- res = res.add(r.BigDecimalValue(mcloc));
- }
- return res.round(mc);
- } /* broadhurstBBP */
-
- /**
- * Add a BigDecimal and a BigInteger.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The sum x+y.
- * @since 2012-03-02
- */
- static public BigDecimal add(final BigDecimal x, final BigInteger y) {
- return x.add(new BigDecimal(y));
- } /* add */
-
- /**
- * Add and round according to the larger of the two ulp's.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The sum x+y.
- * @since 2009-07-30
- */
- static public BigDecimal addRound(final BigDecimal x, final BigDecimal y) {
- final BigDecimal resul = x.add(y);
- /*
- * The estimation of the absolute error in the result is
- * |err(y)|+|err(x)|
- */
- final double errR = Math.abs(y.ulp().doubleValue() / 2.) + Math.abs(x.ulp().doubleValue() / 2.);
- int err2prec = BigDecimalMath.err2prec(resul.doubleValue(), errR);
- if (err2prec < 0) {
- err2prec = 0;
- }
- final MathContext mc = SafeMathContext.newMathContext(err2prec);
- return resul.round(mc);
- } /* addRound */
-
- /**
- * Add and round according to the larger of the two ulp's.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The sum x+y.
- * @since 2010-07-19
- */
- static public BigComplex addRound(final BigComplex x, final BigDecimal y) {
- final BigDecimal R = BigDecimalMath.addRound(x.re, y);
- return new BigComplex(R, x.im);
- } /* addRound */
-
- /**
- * Add and round according to the larger of the two ulp's.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The sum x+y.
- * @since 2010-07-19
- */
- static public BigComplex addRound(final BigComplex x, final BigComplex y) {
- final BigDecimal R = BigDecimalMath.addRound(x.re, y.re);
- final BigDecimal I = BigDecimalMath.addRound(x.im, y.im);
- return new BigComplex(R, I);
- } /* addRound */
-
- /**
- * Subtract and round according to the larger of the two ulp's.
- *
- * @param x
- * The left term.
- * @param y
- * The right term.
- * @return The difference x-y.
- * @since 2009-07-30
- */
- static public BigDecimal subtractRound(final BigDecimal x, final BigDecimal y) {
- final BigDecimal resul = x.subtract(y);
- /*
- * The estimation of the absolute error in the result is
- * |err(y)|+|err(x)|
- */
- final double errR = Math.abs(y.ulp().doubleValue() / 2.) + Math.abs(x.ulp().doubleValue() / 2.);
- final MathContext mc = SafeMathContext.newMathContext(BigDecimalMath.err2prec(resul.doubleValue(), errR));
- return resul.round(mc);
- } /* subtractRound */
-
- /**
- * Subtract and round according to the larger of the two ulp's.
- *
- * @param x
- * The left summand
- * @param y
- * The right summand
- * @return The difference x-y.
- * @since 2010-07-19
- */
- static public BigComplex subtractRound(final BigComplex x, final BigComplex y) {
- final BigDecimal R = BigDecimalMath.subtractRound(x.re, y.re);
- final BigDecimal I = BigDecimalMath.subtractRound(x.im, y.im);
- return new BigComplex(R, I);
- } /* subtractRound */
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param y
- * The right factor.
- * @return The product x*y.
- * @since 2009-07-30
- */
- static public BigDecimal multiplyRound(final BigDecimal x, final BigDecimal y) {
- final BigDecimal resul = x.multiply(y);
- /*
- * The estimation of the relative error in the result is the sum of the
- * relative
- * errors |err(y)/y|+|err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(Math.min(x.precision(), y.precision()));
- return resul.round(mc);
- } /* multiplyRound */
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param y
- * The right factor.
- * @return The product x*y.
- * @since 2010-07-19
- */
- static public BigComplex multiplyRound(final BigComplex x, final BigDecimal y) {
- final BigDecimal R = BigDecimalMath.multiplyRound(x.re, y);
- final BigDecimal I = BigDecimalMath.multiplyRound(x.im, y);
- return new BigComplex(R, I);
- } /* multiplyRound */
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param y
- * The right factor.
- * @return The product x*y.
- * @since 2010-07-19
- */
- static public BigComplex multiplyRound(final BigComplex x, final BigComplex y) {
- final BigDecimal R = BigDecimalMath.subtractRound(BigDecimalMath.multiplyRound(x.re, y.re), BigDecimalMath.multiplyRound(x.im, y.im));
- final BigDecimal I = BigDecimalMath.addRound(BigDecimalMath.multiplyRound(x.re, y.im), BigDecimalMath.multiplyRound(x.im, y.re));
- return new BigComplex(R, I);
- } /* multiplyRound */
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param f
- * The right factor.
- * @return The product x*f.
- * @since 2009-07-30
- */
- static public BigDecimal multiplyRound(final BigDecimal x, final Rational f) {
- if (f.compareTo(BigInteger.ZERO) == 0) {
- return BigDecimal.ZERO;
- } else {
- /*
- * Convert the rational value with two digits of extra precision
- */
- final MathContext mc = SafeMathContext.newMathContext(2 + x.precision());
- final BigDecimal fbd = f.BigDecimalValue(mc);
-
- /*
- * and the precision of the product is then dominated by the
- * precision in x
- */
- return BigDecimalMath.multiplyRound(x, fbd);
- }
- }
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param n
- * The right factor.
- * @return The product x*n.
- * @since 2009-07-30
- */
- static public BigDecimal multiplyRound(final BigDecimal x, final int n) {
- final BigDecimal resul = x.multiply(new BigDecimal(n));
- /*
- * The estimation of the absolute error in the result is |n*err(x)|
- */
- final MathContext mc = SafeMathContext.newMathContext(n != 0 ? x.precision() : 0);
- return resul.round(mc);
- }
-
- /**
- * Multiply and round.
- *
- * @param x
- * The left factor.
- * @param n
- * The right factor.
- * @return the product x*n
- * @since 2009-07-30
- */
- static public BigDecimal multiplyRound(final BigDecimal x, final BigInteger n) {
- final BigDecimal resul = x.multiply(new BigDecimal(n));
- /*
- * The estimation of the absolute error in the result is |n*err(x)|
- */
- final MathContext mc = SafeMathContext.newMathContext(n.compareTo(BigInteger.ZERO) != 0 ? x.precision() : 0);
- return resul.round(mc);
- }
-
- /**
- * Divide and round.
- *
- * @param x
- * The numerator
- * @param y
- * The denominator
- * @return the divided x/y
- * @since 2009-07-30
- */
- static public BigDecimal divideRound(final BigDecimal x, final BigDecimal y) {
- /*
- * The estimation of the relative error in the result is
- * |err(y)/y|+|err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(Math.min(x.precision(), y.precision()));
- final BigDecimal resul = x.divide(y, mc);
- /*
- * If x and y are precise integer values that may have common factors,
- * the method above will truncate trailing zeros, which may result in
- * a smaller apparent accuracy than starte... add missing trailing zeros
- * now.
- */
- return BigDecimalMath.scalePrec(resul, mc);
- }
-
- /**
- * Build the inverse and maintain the approximate accuracy.
- *
- * @param z
- * The denominator
- * @return The divided 1/z = [Re(z)-i*Im(z)]/ [Re^2 z + Im^2 z]
- * @since 2010-07-19
- */
- static public BigComplex invertRound(final BigComplex z) {
- if (z.im.compareTo(BigDecimal.ZERO) == 0) {
- /*
- * In this case with vanishing Im(x), the result is simply 1/Re z.
- */
- final MathContext mc = SafeMathContext.newMathContext(z.re.precision());
- return new BigComplex(BigDecimal.ONE.divide(z.re, mc));
- } else if (z.re.compareTo(BigDecimal.ZERO) == 0) {
- /*
- * In this case with vanishing Re(z), the result is simply -i/Im z
- */
- final MathContext mc = SafeMathContext.newMathContext(z.im.precision());
- return new BigComplex(BigDecimal.ZERO, BigDecimal.ONE.divide(z.im, mc).negate());
- } else {
- /*
- * 1/(x.re+I*x.im) = 1/(x.re+x.im^2/x.re) - I /(x.im +x.re^2/x.im)
- */
- BigDecimal R = BigDecimalMath.addRound(z.re, BigDecimalMath.divideRound(BigDecimalMath.multiplyRound(z.im, z.im), z.re));
- BigDecimal I = BigDecimalMath.addRound(z.im, BigDecimalMath.divideRound(BigDecimalMath.multiplyRound(z.re, z.re), z.im));
- MathContext mc = SafeMathContext.newMathContext(1 + R.precision());
- R = BigDecimal.ONE.divide(R, mc);
- mc = SafeMathContext.newMathContext(1 + I.precision());
- I = BigDecimal.ONE.divide(I, mc);
- return new BigComplex(R, I.negate());
- }
- }
-
- /**
- * Divide and round.
- *
- * @param x
- * The numerator
- * @param y
- * The denominator
- * @return the divided x/y
- * @since 2010-07-19
- */
- static public BigComplex divideRound(final BigComplex x, final BigComplex y) {
- return BigDecimalMath.multiplyRound(x, BigDecimalMath.invertRound(y));
- }
-
- /**
- * Divide and round.
- *
- * @param x
- * The numerator
- * @param n
- * The denominator
- * @return the divided x/n
- * @since 2009-07-30
- */
- static public BigDecimal divideRound(final BigDecimal x, final int n) {
- /*
- * The estimation of the relative error in the result is |err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return x.divide(new BigDecimal(n), mc);
- }
-
- /**
- * Divide and round.
- *
- * @param x
- * The numerator
- * @param n
- * The denominator
- * @return the divided x/n
- * @since 2009-07-30
- */
- static public BigDecimal divideRound(final BigDecimal x, final BigInteger n) {
- /*
- * The estimation of the relative error in the result is |err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return x.divide(new BigDecimal(n), mc);
- } /* divideRound */
-
- /**
- * Divide and round.
- *
- * @param n
- * The numerator
- * @param x
- * The denominator
- * @return the divided n/x
- * @since 2009-08-05
- */
- static public BigDecimal divideRound(final BigInteger n, final BigDecimal x) {
- /*
- * The estimation of the relative error in the result is |err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return new BigDecimal(n).divide(x, mc);
- } /* divideRound */
-
- /**
- * Divide and round.
- *
- * @param n
- * The numerator
- * @param x
- * The denominator
- * @return the divided n/x
- * @since 2012-03-01
- */
- static public BigComplex divideRound(final BigInteger n, final BigComplex x) {
- /*
- * catch case of real-valued denominator first
- */
- if (x.im.compareTo(BigDecimal.ZERO) == 0) {
- return new BigComplex(BigDecimalMath.divideRound(n, x.re), BigDecimal.ZERO);
- } else if (x.re.compareTo(BigDecimal.ZERO) == 0) {
- return new BigComplex(BigDecimal.ZERO, BigDecimalMath.divideRound(n, x.im).negate());
- }
-
- final BigComplex z = BigDecimalMath.invertRound(x);
- /*
- * n/(x+iy) = nx/(x^2+y^2) -nyi/(x^2+y^2)
- */
- final BigDecimal repart = BigDecimalMath.multiplyRound(z.re, n);
- final BigDecimal impart = BigDecimalMath.multiplyRound(z.im, n);
- return new BigComplex(repart, impart);
- } /* divideRound */
-
- /**
- * Divide and round.
- *
- * @param n
- * The numerator.
- * @param x
- * The denominator.
- * @return the divided n/x.
- * @since 2009-08-05
- */
- static public BigDecimal divideRound(final int n, final BigDecimal x) {
- /*
- * The estimation of the relative error in the result is |err(x)/x|
- */
- final MathContext mc = SafeMathContext.newMathContext(x.precision());
- return new BigDecimal(n).divide(x, mc);
- }
-
- /**
- * Append decimal zeros to the value. This returns a value which appears to
- * have
- * a higher precision than the input.
- *
- * @param x
- * The input value
- * @param d
- * The (positive) value of zeros to be added as least significant
- * digits.
- * @return The same value as the input but with increased (pseudo)
- * precision.
- */
- static public BigDecimal scalePrec(final BigDecimal x, final int d) {
- return x.setScale(d + x.scale());
- }
-
- /**
- * Append decimal zeros to the value. This returns a value which appears to
- * have
- * a higher precision than the input.
- *
- * @param x
- * The input value
- * @param d
- * The (positive) value of zeros to be added as least significant
- * digits.
- * @return The same value as the input but with increased (pseudo)
- * precision.
- */
- static public BigComplex scalePrec(final BigComplex x, final int d) {
- return new BigComplex(BigDecimalMath.scalePrec(x.re, d), BigDecimalMath.scalePrec(x.im, d));
- }
-
- /**
- * Boost the precision by appending decimal zeros to the value. This returns
- * a value which appears to have
- * a higher precision than the input.
- *
- * @param x
- * The input value
- * @param mc
- * The requirement on the minimum precision on return.
- * @return The same value as the input but with increased (pseudo)
- * precision.
- */
- static public BigDecimal scalePrec(final BigDecimal x, final MathContext mc) {
- final int diffPr = mc.getPrecision() - x.precision();
- if (diffPr > 0) {
- return BigDecimalMath.scalePrec(x, diffPr);
- } else {
- return x;
- }
- } /* BigDecimalMath.scalePrec */
-
- /**
- * Convert an absolute error to a precision.
- *
- * @param x
- * The value of the variable
- * @param xerr
- * The absolute error in the variable
- * @return The number of valid digits in x.
- * The value is rounded down, and on the pessimistic side for that
- * reason.
- * @since 2009-06-25
- */
- static public int err2prec(final BigDecimal x, final BigDecimal xerr) {
- return BigDecimalMath.err2prec(xerr.divide(x, MathContext.DECIMAL64).doubleValue());
- }
-
- /**
- * Convert an absolute error to a precision.
- *
- * @param x
- * The value of the variable
- * The value returned depends only on the absolute value, not on
- * the sign.
- * @param xerr
- * The absolute error in the variable
- * The value returned depends only on the absolute value, not on
- * the sign.
- * @return The number of valid digits in x.
- * Derived from the representation x+- xerr, as if the error was
- * represented
- * in a "half width" (half of the error bar) form.
- * The value is rounded down, and on the pessimistic side for that
- * reason.
- * @since 2009-05-30
- */
- static public int err2prec(final double x, final double xerr) {
- /*
- * Example: an error of xerr=+-0.5 at x=100 represents 100+-0.5 with
- * a precision = 3 (digits).
- */
- return 1 + (int) Math.log10(Math.abs(0.5 * x / xerr));
- }
-
- /**
- * Convert a relative error to a precision.
- *
- * @param xerr
- * The relative error in the variable.
- * The value returned depends only on the absolute value, not on
- * the sign.
- * @return The number of valid digits in x.
- * The value is rounded down, and on the pessimistic side for that
- * reason.
- * @since 2009-08-05
- */
- static public int err2prec(final double xerr) {
- /*
- * Example: an error of xerr=+-0.5 a precision of 1 (digit), an error of
- * +-0.05 a precision of 2 (digits)
- */
- return 1 + (int) Math.log10(Math.abs(0.5 / xerr));
- }
-
- /**
- * Convert a precision (relative error) to an absolute error.
- * The is the inverse functionality of err2prec().
- *
- * @param x
- * The value of the variable
- * The value returned depends only on the absolute value, not on
- * the sign.
- * @param prec
- * The number of valid digits of the variable.
- * @return the absolute error in x.
- * Derived from the an accuracy of one half of the ulp.
- * @since 2009-08-09
- */
- static public double prec2err(final double x, final int prec) {
- return 5. * Math.abs(x) * Math.pow(10., -prec);
- }
-
-} /* BigDecimalMath */
diff --git a/core/src/main/java/org/nevec/rjm/BigIntegerMath.java b/core/src/main/java/org/nevec/rjm/BigIntegerMath.java
deleted file mode 100644
index 7c2893f2..00000000
--- a/core/src/main/java/org/nevec/rjm/BigIntegerMath.java
+++ /dev/null
@@ -1,644 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * BigInteger special functions and Number theory.
- *
- * @since 2009-08-06
- * @author Richard J. Mathar
- */
-public class BigIntegerMath {
-
- /**
- * Evaluate binomial(n,k).
- *
- * @param n
- * The upper index
- * @param k
- * The lower index
- * @return The binomial coefficient
- */
- static public BigInteger binomial(final int n, final int k) {
- if (k == 0) {
- return BigInteger.ONE;
- }
- BigInteger bin = new BigInteger("" + n);
- final BigInteger n2 = bin;
- for (BigInteger i = new BigInteger("" + (k - 1)); i.compareTo(BigInteger.ONE) >= 0; i = i.subtract(BigInteger.ONE)) {
- bin = bin.multiply(n2.subtract(i));
- }
- for (BigInteger i = new BigInteger("" + k); i.compareTo(BigInteger.ONE) == 1; i = i.subtract(BigInteger.ONE)) {
- bin = bin.divide(i);
- }
- return bin;
- } /* binomial */
-
- /**
- * Evaluate binomial(n,k).
- *
- * @param n
- * The upper index
- * @param k
- * The lower index
- * @return The binomial coefficient
- * @since 2008-10-15
- */
- static public BigInteger binomial(final BigInteger n, final BigInteger k) {
- /*
- * binomial(n,0) =1
- */
- if (k.compareTo(BigInteger.ZERO) == 0) {
- return BigInteger.ONE;
- }
-
- BigInteger bin = new BigInteger("" + n);
-
- /*
- * the following version first calculates n(n-1)(n-2)..(n-k+1)
- * in the first loop, and divides this product through k(k-1)(k-2)....2
- * in the second loop. This is rather slow and replaced by a faster
- * version
- * below
- * BigInteger n2 = bin ;
- * BigInteger i= k.subtract(BigInteger.ONE) ;
- * for( ; i.compareTo(BigInteger.ONE) >= 0 ; i =
- * i.subtract(BigInteger.ONE) )
- * bin = bin.multiply(n2.subtract(i)) ;
- * i= new BigInteger(""+k) ;
- * for( ; i.compareTo(BigInteger.ONE) == 1 ; i =
- * i.subtract(BigInteger.ONE) )
- * bin = bin.divide(i) ;
- */
-
- /*
- * calculate n then n(n-1)/2 then n(n-1)(n-2)(2*3) etc up to
- * n(n-1)..(n-k+1)/(2*3*..k)
- * This is roughly the best way to keep the individual intermediate
- * products small
- * and in the integer domain. First replace C(n,k) by C(n,n-k) if n-k
- * Deprecated: This function is extremely slow and inefficient!
- *
- * @param n
- * The integer of which the divisors are to be found.
- * @return The sorted list of positive divisors.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- @Deprecated
- static public Vector divisors(final BigInteger n) {
- return new Ifactor(n.abs()).divisors();
- }
-
- /**
- * Evaluate sigma(n).
- *
- * @param n
- * the argument for which divisors will be searched.
- * @return the sigma function. Sum of the divisors of the argument.
- * @since 2006-08-14
- * @author Richard J. Mathar
- */
- static public BigInteger sigma(final BigInteger n) {
- return new Ifactor(n.abs()).sigma().n;
- }
-
- /**
- * Evaluate floor(sqrt(n)).
- *
- * @param n
- * The non-negative argument.
- * @return The integer square root. The square root rounded down.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public int isqrt(final int n) {
- if (n < 0) {
- throw new ArithmeticException("Negative argument " + n);
- }
- final double resul = Math.sqrt(n);
- return (int) Math.round(resul);
- }
-
- /**
- * Evaluate floor(sqrt(n)).
- *
- * @param n
- * The non-negative argument.
- * Arguments less than zero throw an ArithmeticException.
- * @return The integer square root, the square root rounded down.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public long isqrt(final long n) {
- if (n < 0) {
- throw new ArithmeticException("Negative argument " + n);
- }
- final double resul = Math.sqrt(n);
- return Math.round(resul);
- }
-
- /**
- * Evaluate floor(sqrt(n)).
- *
- * @param n
- * The non-negative argument.
- * Arguments less than zero throw an ArithmeticException.
- * @return The integer square root, the square root rounded down.
- * @since 2011-02-12
- * @author Richard J. Mathar
- */
- static public BigInteger isqrt(final BigInteger n) {
- if (n.compareTo(BigInteger.ZERO) < 0) {
- throw new ArithmeticException("Negative argument " + n.toString());
- }
- /*
- * Start with an estimate from a floating point reduction.
- */
- BigInteger x;
- final int bl = n.bitLength();
- if (bl > 120) {
- x = n.shiftRight(bl / 2 - 1);
- } else {
- final double resul = Math.sqrt(n.doubleValue());
- x = new BigInteger("" + Math.round(resul));
- }
-
- final BigInteger two = new BigInteger("2");
- while (true) {
- /*
- * check whether the result is accurate, x^2 =n
- */
- final BigInteger x2 = x.pow(2);
- BigInteger xplus2 = x.add(BigInteger.ONE).pow(2);
- if (x2.compareTo(n) <= 0 && xplus2.compareTo(n) > 0) {
- return x;
- }
- xplus2 = xplus2.subtract(x.shiftLeft(2));
- if (xplus2.compareTo(n) <= 0 && x2.compareTo(n) > 0) {
- return x.subtract(BigInteger.ONE);
- }
- /*
- * Newton algorithm. This correction is on the
- * low side caused by the integer divisions. So the value required
- * may end up by one unit too large by the bare algorithm, and this
- * is caught above by comparing x^2, (x+-1)^2 with n.
- */
- xplus2 = x2.subtract(n).divide(x).divide(two);
- x = x.subtract(xplus2);
- }
- }
-
- /**
- * Evaluate core(n).
- * Returns the smallest positive integer m such that n/m is a perfect
- * square.
- *
- * @param n
- * The non-negative argument.
- * @return The square-free part of n.
- * @since 2011-02-12
- * @author Richard J. Mathar
- */
- static public BigInteger core(final BigInteger n) {
- if (n.compareTo(BigInteger.ZERO) < 0) {
- throw new ArithmeticException("Negative argument " + n);
- }
- final Ifactor i = new Ifactor(n);
- return i.core();
- }
-
- /**
- * Minor of an integer matrix.
- *
- * @param A
- * The matrix.
- * @param r
- * The row index of the row to be removed (0-based).
- * An exception is thrown if this is outside the range 0 to the
- * upper row index of A.
- * @param c
- * The column index of the column to be removed (0-based).
- * An exception is thrown if this is outside the range 0 to the
- * upper column index of A.
- * @return The depleted matrix. This is not a deep copy but contains
- * references to the original.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public BigInteger[][] minor(final BigInteger[][] A, final int r, final int c) throws ArithmeticException {
- /* original row count */
- final int rL = A.length;
- if (rL == 0) {
- throw new ArithmeticException("zero row count in matrix");
- }
- if (r < 0 || r >= rL) {
- throw new ArithmeticException("row number " + r + " out of range 0.." + (rL - 1));
- }
- /* original column count */
- final int cL = A[0].length;
- if (cL == 0) {
- throw new ArithmeticException("zero column count in matrix");
- }
- if (c < 0 || c >= cL) {
- throw new ArithmeticException("column number " + c + " out of range 0.." + (cL - 1));
- }
- final BigInteger M[][] = new BigInteger[rL - 1][cL - 1];
- int imrow = 0;
- for (int row = 0; row < rL; row++) {
- if (row != r) {
- int imcol = 0;
- for (int col = 0; col < cL; col++) {
- if (col != c) {
- M[imrow][imcol] = A[row][col];
- imcol++;
- }
- }
- imrow++;
- }
- }
- return M;
- }
-
- /**
- * Replace column of a matrix with a column vector.
- *
- * @param A
- * The matrix.
- * @param c
- * The column index of the column to be substituted (0-based).
- * @param v
- * The column vector to be inserted.
- * With the current implementation, it must be at least as long
- * as the row count, and
- * its elements that exceed that count are ignored.
- * @return The modified matrix. This is not a deep copy but contains
- * references to the original.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- @SuppressWarnings("unused")
- static private BigInteger[][] colSubs(final BigInteger[][] A, final int c, final BigInteger[] v)
- throws ArithmeticException {
- /* original row count */
- final int rL = A.length;
- if (rL == 0) {
- throw new ArithmeticException("zero row count in matrix");
- }
- /* original column count */
- final int cL = A[0].length;
- if (cL == 0) {
- throw new ArithmeticException("zero column count in matrix");
- }
- if (c < 0 || c >= cL) {
- throw new ArithmeticException("column number " + c + " out of range 0.." + (cL - 1));
- }
- final BigInteger M[][] = new BigInteger[rL][cL];
- for (int row = 0; row < rL; row++) {
- for (int col = 0; col < cL; col++) {
- /*
- * currently, v may just be longer than the row count, and
- * surplus
- * elements will be ignored. Shorter v lead to an exception.
- */
- if (col != c) {
- M[row][col] = A[row][col];
- } else {
- M[row][col] = v[row];
- }
- }
- }
- return M;
- }
-
- /**
- * Determinant of an integer square matrix.
- *
- * @param A
- * The square matrix.
- * If column and row dimensions are unequal, an
- * ArithmeticException is thrown.
- * @return The determinant.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public BigInteger det(final BigInteger[][] A) throws ArithmeticException {
- BigInteger d = BigInteger.ZERO;
- /* row size */
- final int rL = A.length;
- if (rL == 0) {
- throw new ArithmeticException("zero row count in matrix");
- }
- /* column size */
- final int cL = A[0].length;
- if (cL != rL) {
- throw new ArithmeticException("Non-square matrix dim " + rL + " by " + cL);
- }
-
- /*
- * Compute the low-order cases directly.
- */
- if (rL == 1) {
- return A[0][0];
- } else if (rL == 2) {
- d = A[0][0].multiply(A[1][1]);
- return d.subtract(A[0][1].multiply(A[1][0]));
- } else {
- /* Work arbitrarily along the first column of the matrix */
- for (int r = 0; r < rL; r++) {
- /*
- * Do not consider minors that do no contribute anyway
- */
- if (A[r][0].compareTo(BigInteger.ZERO) != 0) {
- final BigInteger M[][] = BigIntegerMath.minor(A, r, 0);
- final BigInteger m = A[r][0].multiply(BigIntegerMath.det(M));
- /* recursive call */
- if (r % 2 == 0) {
- d = d.add(m);
- } else {
- d = d.subtract(m);
- }
- }
- }
- }
- return d;
- }
-
- /**
- * Solve a linear system of equations.
- *
- * @param A
- * The square matrix.
- * If it is not of full rank, an ArithmeticException is thrown.
- * @param rhs
- * The right hand side. The length of this vector must match the
- * matrix size;
- * else an ArithmeticException is thrown.
- * @return The vector of x in A*x=rhs.
- * @since 2010-08-28
- * @author Richard J. Mathar
- * @throws Error
- */
- static public Rational[] solve(final BigInteger[][] A, final BigInteger[] rhs) throws ArithmeticException, Error {
-
- final int rL = A.length;
- if (rL == 0) {
- throw new ArithmeticException("zero row count in matrix");
- }
-
- /* column size */
- final int cL = A[0].length;
- if (cL != rL) {
- throw new ArithmeticException("Non-square matrix dim " + rL + " by " + cL);
- }
- if (rhs.length != rL) {
- throw new ArithmeticException("Right hand side dim " + rhs.length + " unequal matrix dim " + rL);
- }
-
- /*
- * Gauss elimination
- */
- final Rational x[] = new Rational[rL];
-
- /*
- * copy of r.h.s ito a mutable Rationalright hand side
- */
- for (int c = 0; c < cL; c++) {
- x[c] = new Rational(rhs[c]);
- }
-
- /*
- * Create zeros downwards column c by linear combination of row c and
- * row r.
- */
- for (int c = 0; c < cL - 1; c++) {
- /*
- * zero on the diagonal? swap with a non-zero row, searched with
- * index r
- */
- if (A[c][c].compareTo(BigInteger.ZERO) == 0) {
- boolean swpd = false;
- for (int r = c + 1; r < rL; r++) {
- if (A[r][c].compareTo(BigInteger.ZERO) != 0) {
- for (int cpr = c; cpr < cL; cpr++) {
- final BigInteger tmp = A[c][cpr];
- A[c][cpr] = A[r][cpr];
- A[r][cpr] = tmp;
- }
- final Rational tmp = x[c];
- x[c] = x[r];
- x[r] = tmp;
- swpd = true;
- break;
- }
- }
- /*
- * not swapped with a non-zero row: determinant zero and no
- * solution
- */
- if (!swpd) {
- throw new ArithmeticException("Zero determinant of main matrix");
- }
- }
- /* create zero at A[c+1..cL-1][c] */
- for (int r = c + 1; r < rL; r++) {
- /*
- * skip the cpr=c which actually sets the zero: this element is
- * not visited again
- */
- for (int cpr = c + 1; cpr < cL; cpr++) {
- final BigInteger tmp = A[c][c].multiply(A[r][cpr]).subtract(A[c][cpr].multiply(A[r][c]));
- A[r][cpr] = tmp;
- }
- final Rational tmp = x[r].multiply(A[c][c]).subtract(x[c].multiply(A[r][c]));
- x[r] = tmp;
- }
- }
- if (A[cL - 1][cL - 1].compareTo(BigInteger.ZERO) == 0) {
- throw new ArithmeticException("Zero determinant of main matrix");
- }
- /* backward elimination */
- for (int r = cL - 1; r >= 0; r--) {
- x[r] = x[r].divide(A[r][r]);
- for (int rpr = r - 1; rpr >= 0; rpr--) {
- x[rpr] = x[rpr].subtract(x[r].multiply(A[rpr][r]));
- }
- }
-
- return x;
- }
-
- /**
- * The lowest common multiple
- *
- * @param a
- * The first argument
- * @param b
- * The second argument
- * @return lcm(|a|,|b|)
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public BigInteger lcm(final BigInteger a, final BigInteger b) {
- final BigInteger g = a.gcd(b);
- return a.multiply(b).abs().divide(g);
- }
-
- /**
- * Evaluate the value of an integer polynomial at some integer argument.
- *
- * @param c
- * Represents the coefficients c[0]+c[1]*x+c[2]*x^2+.. of the
- * polynomial
- * @param x
- * The abscissa point of the evaluation
- * @return The polynomial value.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- static public BigInteger valueOf(final Vector c, final BigInteger x) {
- if (c.size() == 0) {
- return BigInteger.ZERO;
- }
- BigInteger res = c.lastElement();
- for (int i = c.size() - 2; i >= 0; i--) {
- res = res.multiply(x).add(c.elementAt(i));
- }
- return res;
- }
-
- /**
- * The central factorial number t(n,k) number at the indices provided.
- *
- * @param n
- * the first parameter, non-negative.
- * @param k
- * the second index, non-negative.
- * @return t(n,k)
- * @since 2009-08-06
- * @author Richard J. Mathar
- * @throws Error
- * @see P. L. Butzer
- * et al, Num. Funct. Anal. Opt. 10 (5)( 1989) 419-488
- */
- static public Rational centrlFactNumt(final int n, final int k) throws Error {
- if (k > n || k < 0 || k % 2 != n % 2) {
- return Rational.ZERO;
- } else if (k == n) {
- return Rational.ONE;
- } else {
- /* Proposition 6.2.6 */
- final Factorial f = new Factorial();
- Rational jsum = new Rational(0, 1);
- final int kprime = n - k;
- for (int j = 0; j <= kprime; j++) {
- Rational nusum = new Rational(0, 1);
- for (int nu = 0; nu <= j; nu++) {
- Rational t = new Rational(j - 2 * nu, 2);
- t = t.pow(kprime + j);
- t = t.multiply(BigIntegerMath.binomial(j, nu));
- if (nu % 2 != 0) {
- nusum = nusum.subtract(t);
- } else {
- nusum = nusum.add(t);
- }
- }
- nusum = nusum.divide(f.at(j)).divide(n + j);
- nusum = nusum.multiply(BigIntegerMath.binomial(2 * kprime, kprime - j));
- if (j % 2 != 0) {
- jsum = jsum.subtract(nusum);
- } else {
- jsum = jsum.add(nusum);
- }
- }
- return jsum.multiply(k).multiply(BigIntegerMath.binomial(n + kprime, k));
- }
- } /* CentralFactNumt */
-
- /**
- * The central factorial number T(n,k) number at the indices provided.
- *
- * @param n
- * the first parameter, non-negative.
- * @param k
- * the second index, non-negative.
- * @return T(n,k)
- * @since 2009-08-06
- * @author Richard J. Mathar
- * @see P. L. Butzer
- * et al, Num. Funct. Anal. Opt. 10 (5)( 1989) 419-488
- */
- static public Rational centrlFactNumT(final int n, final int k) {
- if (k > n || k < 0 || k % 2 != n % 2) {
- return Rational.ZERO;
- } else if (k == n) {
- return Rational.ONE;
- } else {
- /* Proposition 2.1 */
- return BigIntegerMath.centrlFactNumT(n - 2, k - 2).add(BigIntegerMath.centrlFactNumT(n - 2, k).multiply(new Rational(k * k, 4)));
- }
- } /* CentralFactNumT */
-
-} /* BigIntegerMath */
diff --git a/core/src/main/java/org/nevec/rjm/BigIntegerPoly.java b/core/src/main/java/org/nevec/rjm/BigIntegerPoly.java
deleted file mode 100644
index 0818c02e..00000000
--- a/core/src/main/java/org/nevec/rjm/BigIntegerPoly.java
+++ /dev/null
@@ -1,764 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Scanner;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * Polynomial with integer coefficients.
- * Alternatively to be interpreted as a sequence which has the polynomial as an
- * (approximate)
- * generating function.
- *
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
-public class BigIntegerPoly implements Cloneable {
- /**
- * The list of all coefficients, starting with a0, then a1, as in
- * poly=a0+a1*x+a2*x^2+a3*x^3+...
- */
- Vector a;
-
- /**
- * Default ctor.
- * Creates the polynomial p(x)=0.
- */
- public BigIntegerPoly() {
- a = new Vector<>();
- }
-
- /**
- * Ctor with a comma-separated list as the list of coefficients.
- *
- * @param L
- * the string of the form a0,a1,a2,a3 with the coefficients
- */
- public BigIntegerPoly(final String L) throws NumberFormatException {
- a = new Vector<>();
- final Scanner sc = new Scanner(L);
- sc.useDelimiter(",");
- while (sc.hasNextBigInteger()) {
- a.add(sc.nextBigInteger());
- }
- simplify();
- sc.close();
- } /* ctor */
-
- /**
- * Ctor with a list of coefficients.
- *
- * @param c
- * The coefficients a0, a1, a2 etc in a0+a1*x+a2*x^2+...
- */
- @SuppressWarnings("unchecked")
- public BigIntegerPoly(final Vector c) {
- a = (Vector) c.clone();
- simplify();
- } /* ctor */
-
- /**
- * Ctor with a list of coefficients.
- *
- * @param c
- * The coefficients a0, a1, a2 etc in a0+a1*x+a2*x^2+...
- */
- public BigIntegerPoly(final BigInteger[] c) {
- for (final BigInteger element : c) {
- a.add(element.add(BigInteger.ZERO));
- }
- simplify();
- } /* ctor */
-
- /**
- * Create a copy of this.
- *
- * @since 2010-08-27
- */
- @Override
- public BigIntegerPoly clone() {
- return new BigIntegerPoly(a);
- } /* clone */
-
- /**
- * Translate into a RatPoly copy.
- *
- * @since 2012-03-02
- */
- public RatPoly toRatPoly() {
- final RatPoly bd = new RatPoly();
- for (int i = 0; i < a.size(); i++) {
- bd.set(i, a.elementAt(i));
- }
- return bd;
- } /* toRatPoly */
-
- /**
- * Retrieve a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * @return the polynomial coefficient in front of x^n.
- */
- public BigInteger at(final int n) {
- if (n < a.size()) {
- return a.elementAt(n);
- } else {
- return BigInteger.ZERO;
- }
- } /* at */
-
- /**
- * Evaluate at some integer argument.
- *
- * @param x
- * The abscissa point of the evaluation
- * @return The polynomial value.
- * @since 2010-08-27
- * @author Richard J. Mathar
- */
- public BigInteger valueOf(final BigInteger x) {
- if (a.size() == 0) {
- return BigInteger.ZERO;
- }
- BigInteger res = a.lastElement();
- /*
- * Heron casted form
- */
- for (int i = a.size() - 2; i >= 0; i--) {
- res = res.multiply(x).add(a.elementAt(i));
- }
- return res;
- } /* valueOf */
-
- /**
- * Horner scheme to find the function value at the argument x
- *
- * @param x
- * The argument x.
- * @return Value of the polynomial at x.
- * @since 2008-11-13
- */
- public BigInteger valueOf(final int x) {
- return valueOf(new BigInteger("" + x));
- } /* valueOf */
-
- /**
- * Set a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this
- * coefficient,
- * the intermediate coefficients are set to zero.
- * @param value
- * the new value of the coefficient.
- */
- public void set(final int n, final BigInteger value) {
- if (n < a.size()) {
- a.set(n, value);
- } else {
- /*
- * fill intermediate powers with coefficients of zero
- */
- while (a.size() < n) {
- a.add(BigInteger.ZERO);
- }
- a.add(value);
- }
- } /* set */
-
- /**
- * Set a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this
- * coefficient,
- * the intermediate coefficients are implicitly set to zero.
- * @param value
- * the new value of the coefficient.
- */
- public void set(final int n, final int value) {
- final BigInteger val2 = new BigInteger("" + value);
- set(n, val2);
- } /* set */
-
- /**
- * Count of coefficients.
- *
- * @return the number of polynomial coefficients.
- * Differs from the polynomial degree by one.
- */
- public int size() {
- return a.size();
- } /* size */
-
- /**
- * Polynomial degree.
- *
- * @return the polynomial degree.
- */
- public int degree() {
- return a.size() - 1;
- } /* degree */
-
- /**
- * Polynomial lower degree.
- *
- * @return power of the smallest non-zero coefficient.
- * If the polynomial is identical to 0, 0 is returned.
- */
- public int ldegree() {
- for (int n = 0; n < a.size(); n++) {
- if (a.elementAt(n).compareTo(BigInteger.ZERO) != 0) {
- return n;
- }
- }
- return 0;
- } /* ldegree */
-
- /**
- * Multiply by a constant factor.
- *
- * @param val
- * the factor
- * @return the product of this with the factor.
- * All coefficients of this have been multiplied individually by the
- * factor.
- * @since 2010-08-27
- */
- public BigIntegerPoly multiply(final BigInteger val) {
- final BigIntegerPoly resul = new BigIntegerPoly();
- if (val.compareTo(BigInteger.ZERO) != 0) {
- for (int n = 0; n < a.size(); n++) {
- resul.set(n, a.elementAt(n).multiply(val));
- }
- }
- return resul;
- } /* multiply */
-
- /**
- * Multiply by another polynomial
- *
- * @param val
- * the other polynomial
- * @return the product of this with the other polynomial
- */
- public BigIntegerPoly multiply(final BigIntegerPoly val) {
- final BigIntegerPoly resul = new BigIntegerPoly();
- /*
- * the degree of the result is the sum of the two degrees.
- */
- final int nmax = degree() + val.degree();
- for (int n = 0; n <= nmax; n++) {
- BigInteger coef = BigInteger.ZERO;
- for (int nleft = 0; nleft <= n; nleft++) {
- coef = coef.add(at(nleft).multiply(val.at(n - nleft)));
- }
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* multiply */
-
- /**
- * Raise to a positive power.
- *
- * @param n
- * the exponent of the power
- * @return the n-th power of this.
- */
- public BigIntegerPoly pow(final int n) throws ArithmeticException {
- BigIntegerPoly resul = new BigIntegerPoly("1");
- if (n < 0) {
- throw new ArithmeticException("negative polynomial power " + n);
- } else {
- for (int i = 1; i <= n; i++) {
- resul = resul.multiply(this);
- }
- resul.simplify();
- return resul;
- }
- } /* pow */
-
- /**
- * Add another polynomial
- *
- * @param val
- * the other polynomial
- * @return the sum of this with the other polynomial
- * @since 2010-08-27
- */
- public BigIntegerPoly add(final BigIntegerPoly val) {
- final BigIntegerPoly resul = new BigIntegerPoly();
- /*
- * the degree of the result is the larger of the two degrees (before
- * simplify() at least).
- */
- final int nmax = degree() > val.degree() ? degree() : val.degree();
- for (int n = 0; n <= nmax; n++) {
- final BigInteger coef = at(n).add(val.at(n));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* add */
-
- /**
- * Subtract another polynomial
- *
- * @param val
- * the other polynomial
- * @return the difference between this and the other polynomial
- * @since 2008-10-25
- */
- public BigIntegerPoly subtract(final BigIntegerPoly val) {
- final BigIntegerPoly resul = new BigIntegerPoly();
- /*
- * the degree of the result is the larger of the two degrees (before
- * simplify() at least).
- */
- final int nmax = degree() > val.degree() ? degree() : val.degree();
- for (int n = 0; n <= nmax; n++) {
- final BigInteger coef = at(n).subtract(val.at(n));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* subtract */
-
- /**
- * Divide by another polynomial.
- *
- * @param val
- * the other polynomial
- * @return A vector with [0] containg the polynomial of degree which is the
- * difference of the degree of this and the degree of val. [1] the
- * remainder polynomial.
- * This = returnvalue[0] + returnvalue[1]/val .
- * @since 2012-03-01
- */
- public BigIntegerPoly[] divideAndRemainder(final BigIntegerPoly val) {
- final BigIntegerPoly[] ret = new BigIntegerPoly[2];
- /*
- * remove any high-order zeros. note that the clone() operation calls
- * simplify().
- */
- final BigIntegerPoly valSimpl = val.clone();
- final BigIntegerPoly thisSimpl = clone();
-
- /*
- * catch the case with val equal to zero
- */
- if (valSimpl.degree() == 0 && valSimpl.a.firstElement().compareTo(BigInteger.ZERO) == 0) {
- throw new ArithmeticException("Division through zero polynomial");
- }
- /*
- * degree of this smaller than degree of val: remainder is this
- */
- if (thisSimpl.degree() < valSimpl.degree()) {
- /*
- * leading polynomial equals zero
- */
- ret[0] = new BigIntegerPoly();
- ret[1] = thisSimpl;
- } else {
- /*
- * long division. Highest degree by dividing the highest degree
- * of this thru val. At this point an exception is thrown if the
- * polynomial division cannot be done with integer coefficients.
- */
- ret[0] = new BigIntegerPoly();
- final BigInteger[] newc = thisSimpl.a.lastElement().divideAndRemainder(valSimpl.a.lastElement());
- if (newc[1].compareTo(BigInteger.ZERO) != 0) {
- throw new ArithmeticException("Incompatible leading term in " + this + " / " + val);
- }
- ret[0].set(thisSimpl.degree() - valSimpl.degree(), newc[0]);
-
- /*
- * recurrences: build this - val*(1-termresult) and feed this
- * into another round of division. Have intermediate
- * ret[0]+ret[1]/val.
- */
- ret[1] = thisSimpl.subtract(ret[0].multiply(valSimpl));
-
- /*
- * any remainder left ?
- */
- if (ret[1].degree() < valSimpl.degree()) {
- ;
- } else {
- final BigIntegerPoly rem[] = ret[1].divideAndRemainder(val);
- ret[0] = ret[0].add(rem[0]);
- ret[1] = rem[1];
- }
- }
- return ret;
- } /* divideAndRemainder */
-
- /**
- * Print as a comma-separated list of coefficients.
- *
- * @return the representation a0,a1,a2,a3,...
- * @since 2010-08-27
- */
- @Override
- public String toString() {
- String str = new String();
- for (int n = 0; n < a.size(); n++) {
- if (n == 0) {
- str += a.elementAt(n).toString();
- } else {
- str += "," + a.elementAt(n).toString();
- }
- }
- if (str.length() == 0) {
- str = "0";
- }
- return str;
- } /* toString */
-
- /**
- * Print as a polyomial in x.
- *
- * @return The representation a0+a1*x+a2*x^2+...
- * The terms with zero coefficients are not mentioned.
- * @since 2008-10-26
- */
- public String toPString() {
- String str = new String();
- for (int n = 0; n < a.size(); n++) {
- final BigInteger num = a.elementAt(n);
- if (num.compareTo(BigInteger.ZERO) != 0) {
- str += " ";
- if (num.compareTo(BigInteger.ZERO) > 0 && n > 0) {
- str += "+";
- }
- str += a.elementAt(n).toString();
- if (n > 0) {
- str += "*x";
- if (n > 1) {
- str += "^" + n;
- }
- }
- }
- }
- if (str.length() == 0) {
- str = "0";
- }
- return str;
- } /* toPString */
-
- /**
- * Simplify the representation.
- * Trailing values with zero coefficients (at high powers) are deleted.
- */
- protected void simplify() {
- int n = a.size() - 1;
- if (n >= 0) {
- while (a.elementAt(n).compareTo(BigInteger.ZERO) == 0) {
- a.removeElementAt(n);
- if (--n < 0) {
- break;
- }
- }
- }
- } /* simplify */
-
- /**
- * First derivative.
- *
- * @return The first derivative with respect to the indeterminate variable.
- * @since 2008-10-26
- */
- public BigIntegerPoly derive() {
- if (a.size() <= 1) {
- /*
- * derivative of the constant is just zero
- */
- return new BigIntegerPoly();
- } else {
- final BigIntegerPoly d = new BigIntegerPoly();
- for (int i = 1; i <= degree(); i++) {
- final BigInteger c = a.elementAt(i).multiply(new BigInteger("" + i));
- d.set(i - 1, c);
- }
- return d;
- }
- } /* derive */
-
- /**
- * Truncate polynomial degree.
- *
- * @return The polynomial with all coefficients beyond deg set to zero.
- * @since 2010-08-27
- */
- public BigIntegerPoly trunc(final int newdeg) {
- final BigIntegerPoly t = new BigIntegerPoly();
- for (int i = 0; i <= newdeg; i++) {
- t.set(i, at(i));
- }
- t.simplify();
- return t;
- } /* trunc */
-
- /**
- * Inverse Binomial transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the inverse binomial transform of
- * the original sequence.
- * @since 2010-08-29
- */
- public BigIntegerPoly binomialTInv(final int maxdeg) {
- final BigIntegerPoly r = new BigIntegerPoly();
- for (int i = 0; i <= maxdeg; i++) {
- BigInteger c = BigInteger.ZERO;
- for (int j = 0; j <= i && j < a.size(); j++) {
- if ((j + i) % 2 != 0) {
- c = c.subtract(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- } else {
- c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- }
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* binomialTInv */
-
- /**
- * Compute the order of the root r.
- *
- * @return 1 for simple roots, 2 for order 2 etc., 0 if not a root
- * @since 2010-08-27
- */
- public int rootDeg(final BigInteger r) {
- int o = 0;
- BigIntegerPoly d = clone();
- BigInteger roo = d.valueOf(r);
- while (roo.compareTo(BigInteger.ZERO) == 0) {
- o++;
- d = d.derive();
- roo = d.valueOf(r);
- }
- return o;
- } /* rootDeg */
-
- /**
- * Generate the integer roots of the polynomial.
- *
- * @return The vector of integer roots, without their multiplicity.
- * @since 2010-08-27
- */
- public Vector iroots() {
- /* The vector of the roots */
- final Vector res = new Vector<>();
-
- /*
- * collect the zero
- */
- if (a.firstElement().compareTo(BigInteger.ZERO) == 0) {
- res.add(BigInteger.ZERO);
- }
-
- /*
- * collect the divisors of the constant element (or the reduced
- * polynomial)
- */
- final int l = ldegree();
- if (a.elementAt(l).compareTo(BigInteger.ZERO) != 0) {
- @SuppressWarnings("deprecation")
- final Vector cand = BigIntegerMath.divisors(a.elementAt(l).abs());
-
- /* check the divisors (both signs) */
- for (int i = 0; i < cand.size(); i++) {
- BigInteger roo = valueOf(cand.elementAt(i));
- if (roo.compareTo(BigInteger.ZERO) == 0) {
- /* found a root cand[i] */
- res.add(cand.elementAt(i));
- }
- roo = valueOf(cand.elementAt(i).negate());
- if (roo.compareTo(BigInteger.ZERO) == 0) {
- res.add(cand.elementAt(i).negate());
- }
- }
- }
- return res;
- } /* iroots */
-
- /**
- * Generate the factors which are 2nd degree polynomials.
- *
- * @return A (potentially empty) vector of factors, without multiplicity.
- * Only factors with non-zero absolute coefficient are generated.
- * This means the factors are of the form x^2+a*x+b=0 with nonzero
- * b.
- * @throws Error
- * @since 2012-03-01
- */
- protected Vector i2roots() throws Error {
- /*
- * The vector of the factors to be returned
- */
- final Vector res = new Vector<>();
-
- if (degree() < 2) {
- return res;
- }
-
- final BigInteger bsco = a.firstElement().abs();
- @SuppressWarnings("deprecation")
- final Vector b = BigIntegerMath.divisors(bsco);
- final BigInteger csco = a.lastElement().abs();
- @SuppressWarnings("deprecation")
- final Vector c = BigIntegerMath.divisors(csco);
-
- /*
- * Generate the floating point values of roots. To have some reasonable
- * accuracy in the results, add zeros to the integer coefficients,
- * scaled
- * by the expected division with values of b (which are all <=
- * a.firstele).
- * Number of decimal digits in bsco by using a log2->log10 rough
- * estimate
- * and adding 6 safety digits
- */
- final RatPoly thisDec = toRatPoly();
- final Vector roo = thisDec.roots(6 + (int) (0.3 * bsco.bitCount()));
-
- final BigDecimal half = new BigDecimal("0.5");
-
- /*
- * for each of the roots z try to see whether c*z^2+a*z+b=0 with integer
- * a, b and c
- * where b is restricted to a signed divisor of the constant
- * coefficient.
- * Solve z*(c*z+a)=-b or c*z+a = -b/z or -b/z-c*z = some integer a.
- */
- for (final BigComplex z : roo) {
- for (final BigInteger bco : b) {
- for (final BigInteger cco : c) {
- /*
- * the major reason to avoid the case b=0 is that this would
- * require precaution of double counting below. Note that
- * this
- * case is already covered by using iroots().
- */
- if (bco.signum() != 0) {
- for (int sig = -1; sig <= 1; sig += 2) {
- final BigInteger bcosig = sig > 0 ? bco : bco.negate();
- /*
- * -a = b/z+c*z has real part b*Re(z)/|z|^2+c*Re(z)
- * = Re z *( b/|z|^2+c)
- */
- BigDecimal negA = BigDecimalMath.add(BigDecimalMath.divideRound(bcosig, z.norm()), cco);
- negA = negA.multiply(z.re);
- /*
- * convert to a with round-to-nearest
- */
- final BigInteger a = negA.negate().add(half).toBigInteger();
-
- /*
- * test the polynomial remainder. if zero, add the
- * term
- * to the results.
- */
- final BigIntegerPoly dtst = new BigIntegerPoly("" + bcosig + "," + a + "," + cco);
- try {
- final BigIntegerPoly[] rm = divideAndRemainder(dtst);
- if (rm[1].isZero()) {
- res.add(dtst);
- }
- } catch (final ArithmeticException ex) {}
- }
- }
- }
- }
- }
-
- return res;
- } /* i2roots */
-
- /**
- * Test whether this polynomial value is zero.
- *
- * @return If this is a polynomial p(x)=0 for all x.
- */
- public boolean isZero() {
- simplify();
- return a.size() == 0;
- }
-
- /**
- * Factorization into integer polynomials.
- * The current factorization detects only factors which are polynomials of
- * order up to 2.
- *
- * @return The vector of factors. Factors with higher multiplicity are
- * represented by repetition.
- * @throws Error
- * @since 2012-03-01
- */
- public Vector ifactor() throws Error {
- /*
- * this ought be entirely rewritten in terms of the LLL algorithm
- */
- final Vector fac = new Vector<>();
-
- /* collect integer roots (polynomial factors of degree 1) */
- final Vector r = iroots();
- BigIntegerPoly[] res = new BigIntegerPoly[2];
- res[0] = this;
- for (final BigInteger i : r) {
- final int deg = rootDeg(i);
- /* construct the factor x-i */
- final BigIntegerPoly f = new BigIntegerPoly("" + i.negate() + ",1");
- for (int mu = 0; mu < deg; mu++) {
- fac.add(f);
- res = res[0].divideAndRemainder(f);
- }
- }
-
- /*
- * collect factors which are polynomials of degree 2
- */
- final Vector pol2 = i2roots();
- for (final BigIntegerPoly i : pol2) {
- /*
- * the internal loop catches cases with higher
- * powers of individual polynomials (of actual degree 2 or 4...)
- */
- while (res[0].degree() >= 2) {
- try {
- final BigIntegerPoly[] dtst = res[0].divideAndRemainder(i);
- if (dtst[1].isZero()) {
- fac.add(i);
- res = dtst;
- } else {
- break;
- }
- } catch (final ArithmeticException ex) {
- break;
- }
- }
- }
-
- /*
- * add remaining factor, if not equal to 1
- */
- if (res[0].degree() > 0 || res[0].a.firstElement().compareTo(BigInteger.ONE) != 0) {
- fac.add(res[0]);
- }
- return fac;
- } /* ifactor */
-
-} /* BigIntegerPoly */
diff --git a/core/src/main/java/org/nevec/rjm/BigSurd.java b/core/src/main/java/org/nevec/rjm/BigSurd.java
deleted file mode 100644
index 7e60fa57..00000000
--- a/core/src/main/java/org/nevec/rjm/BigSurd.java
+++ /dev/null
@@ -1,567 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.security.ProviderException;
-
-import it.cavallium.warppi.util.Error;
-import it.cavallium.warppi.util.Utils;
-
-/**
- * Square roots on the real line.
- * These represent numbers which are a product of a (signed) fraction by
- * a square root of a non-negative fraction.
- * This might be extended to values on the imaginary axis by allowing negative
- * values underneath the square root, but this is not yet implemented.
- *
- * @since 2011-02-12
- * @author Richard J. Mathar
- */
-public class BigSurd implements Cloneable, Comparable {
- /**
- * The value of zero.
- */
- static public BigSurd ZERO = new BigSurd();
-
- /**
- * The value of one.
- */
- static public BigSurd ONE = new BigSurd(Rational.ONE, Rational.ONE);
- /**
- * Prefactor
- */
- Rational pref;
-
- /**
- * The number underneath the square root, always non-negative.
- * The mathematical object has the value pref*sqrt(disc).
- */
- Rational disc;
-
- /**
- * Default ctor, which represents the zero.
- *
- * @since 2011-02-12
- */
- public BigSurd() {
- pref = Rational.ZERO;
- disc = Rational.ZERO;
- }
-
- /**
- * ctor given the prefactor and the basis of the root.
- * This creates an object of value a*sqrt(b).
- *
- * @param a
- * the prefactor.
- * @param b
- * the discriminant.
- * @since 2011-02-12
- */
- public BigSurd(final Rational a, final Rational b) {
- pref = a;
- /*
- * reject attempts to use a negative b
- */
- if (b.signum() < 0) {
- throw new ProviderException("Not implemented: imaginary surds");
- }
- disc = b;
- try {
- normalize();
- normalizeG();
- } catch (final Error e) {
- e.printStackTrace();
- }
- }
-
- /**
- * ctor given the numerator and denominator of the root.
- * This creates an object of value sqrt(a/b).
- *
- * @param a
- * the numerator
- * @param b
- * the denominator.
- * @since 2011-02-12
- */
- public BigSurd(final int a, final int b) {
- this(Rational.ONE, new Rational(a, b));
- }
-
- /**
- * ctor given the value under the root.
- * This creates an object of value sqrt(a).
- *
- * @param a
- * the discriminant.
- * @since 2011-02-12
- */
- public BigSurd(final BigInteger a) {
- this(Rational.ONE, new Rational(a, BigInteger.ONE));
- }
-
- public BigSurd(final Rational a) {
- this(Rational.ONE, a);
- }
-
- /**
- * Create a deep copy.
- *
- * @since 2011-02-12
- */
- @Override
- public BigSurd clone() {
- final Rational fclon = pref.clone();
- final Rational dclon = disc.clone();
- /*
- * the main intent here is to bypass any attempt to reduce the
- * discriminant
- * by figuring out the square-free part in normalize(), which has
- * already done
- * in the current copy of the number.
- */
- final BigSurd cl = new BigSurd();
- cl.pref = fclon;
- cl.disc = dclon;
- return cl;
- } /* BigSurd.clone */
-
- /**
- * Add two surds of compatible discriminant.
- *
- * @param val
- * The value to be added to this.
- */
-
- public BigSurdVec add(final BigSurd val) {
- // zero plus somethings yields something
- if (signum() == 0) {
- return new BigSurdVec(val);
- } else if (val.signum() == 0) {
- return new BigSurdVec(this);
- } else {
- // let the ctor of BigSurdVec to the work
- return new BigSurdVec(this, val);
- }
- } /* BigSurd.add */
-
- /**
- * Multiply by another square root.
- *
- * @param val
- * a second number of this type.
- * @return the product of this with the val.
- * @since 2011-02-12
- */
- public BigSurd multiply(final BigSurd val) {
- return new BigSurd(pref.multiply(val.pref), disc.multiply(val.disc));
- } /* BigSurd.multiply */
-
- /**
- * Multiply by a rational number.
- *
- * @param val
- * the factor.
- * @return the product of this with the val.
- * @since 2011-02-15
- */
- public BigSurd multiply(final Rational val) {
- return new BigSurd(pref.multiply(val), disc);
- } /* BigSurd.multiply */
-
- /**
- * Multiply by a BigInteger.
- *
- * @param val
- * a second number.
- * @return the product of this with the value.
- * @since 2011-02-12
- */
- public BigSurd multiply(final BigInteger val) {
- return new BigSurd(pref.multiply(val), disc);
- } /* BigSurd.multiply */
-
- /**
- * Multiply by an integer.
- *
- * @param val
- * a second number.
- * @return the product of this with the value.
- * @since 2011-02-12
- */
- public BigSurd multiply(final int val) {
- final BigInteger tmp = new BigInteger("" + val);
- return multiply(tmp);
- } /* BigSurd.multiply */
-
- /**
- * Compute the square.
- *
- * @return this value squared.
- * @since 2011-02-12
- */
- public Rational sqr() {
- Rational res = pref.pow(2);
- res = res.multiply(disc);
- return res;
- } /* BigSurd.sqr */
-
- /**
- * Divide by another square root.
- *
- * @param val
- * A second number of this type.
- * @return The value of this/val
- * @throws Error
- * @since 2011-02-12
- */
- public BigSurd divide(final BigSurd val) throws Error {
- if (val.signum() == 0) {
- throw new ArithmeticException("Dividing " + toFancyString() + " through zero.");
- }
- return new BigSurd(pref.divide(val.pref), disc.divide(val.disc));
- } /* BigSurd.divide */
-
- private String toFancyString() {
- final BigSurd bs = this;
- final BigInteger denominator = pref.b;
- String s = "";
- if (denominator.compareTo(BigInteger.ONE) != 0) {
- s += "(";
- }
- if (bs.isBigInteger()) {
- s += bs.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2)).toBigInteger().toString();
- } else if (bs.isRational()) {
- s += bs.toRational().toString();
- } else {
- final BigInteger numerator = bs.pref.a;
- if (numerator.compareTo(BigInteger.ONE) != 0) {
- s += numerator.toString();
- s += "*";
- s += "(";
- }
- s += "2√";
- if (bs.disc.isInteger()) {
- s += bs.disc.toString();
- } else {
- s += "(" + bs.disc.toString() + ")";
- }
- if (numerator.compareTo(BigInteger.ONE) != 0) {
- s += ")";
- }
- }
- return s;
- }
-
- /**
- * Divide by an integer.
- *
- * @param val
- * a second number.
- * @return the value of this/val
- * @throws Error
- * @since 2011-02-12
- */
- public BigSurd divide(final BigInteger val) throws Error {
- if (val.signum() == 0) {
- throw new ArithmeticException("Dividing " + toFancyString() + " through zero.");
- }
- return new BigSurd(pref.divide(val), disc);
- } /* BigSurd.divide */
-
- /**
- * Divide by an integer.
- *
- * @param val
- * A second number.
- * @return The value of this/val
- * @throws Error
- * @since 2011-02-12
- */
- public BigSurd divide(final int val) throws Error {
- if (val == 0) {
- throw new ArithmeticException("Dividing " + toFancyString() + " through zero.");
- }
- return new BigSurd(pref.divide(val), disc);
- } /* BigSurd.divide */
-
- /**
- * Compute the negative.
- *
- * @return -this.
- * @since 2011-02-12
- */
- public BigSurd negate() {
- /*
- * This is trying to be quick, avoiding normalize(), by toggling
- * the sign in a clone()
- */
- final BigSurd n = clone();
- n.pref = n.pref.negate();
- return n;
- } /* BigSurd.negate */
-
- /**
- * Absolute value.
- *
- * @return The absolute (non-negative) value of this.
- * @since 2011-02-12
- */
- public BigSurd abs() {
- return new BigSurd(pref.abs(), disc);
- }
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * the other constant to compare with
- * @return -1, 0 or 1 if this number is numerically less than, equal to,
- * or greater than val.
- * @since 2011-02-12
- */
- @Override
- public int compareTo(final BigSurd val) {
- /*
- * Since we keep the discriminant positive, the rough estimate
- * comes from comparing the signs of the prefactors.
- */
- final int sig = signum();
- final int sigv = val.signum();
- if (sig < 0 && sigv >= 0) {
- return -1;
- }
- if (sig > 0 && sigv <= 0) {
- return 1;
- }
- if (sig == 0 && sigv == 0) {
- return 0;
- }
- if (sig == 0 && sigv > 0) {
- return -1;
- }
- if (sig == 0 && sigv < 0) {
- return 1;
- }
-
- /*
- * Work out the cases of equal sign. Compare absolute values by
- * comparison
- * of the squares which is forwarded to the comparison of the Rational
- * class.
- */
- final Rational this2 = sqr();
- final Rational val2 = val.sqr();
- final int c = this2.compareTo(val2);
- if (c == 0) {
- return 0;
- } else if (sig > 0 && c > 0 || sig < 0 && c < 0) {
- return 1;
- } else {
- return -1;
- }
- } /* BigSurd.compareTo */
-
- /**
- * Return a string in the format (number/denom)*()^(1/2).
- * If the discriminant equals 1, print just the prefactor.
- *
- * @return the human-readable version in base 10
- * @since 2011-02-12
- */
- @Override
- public String toString() {
- if (disc.compareTo(Rational.ONE) != 0 && disc.compareTo(Rational.ZERO) != 0) {
- return "(" + pref.toString() + ")*(" + disc.toString() + ")^(1/2)";
- } else {
- return pref.toString();
- }
- } /* BigSurd.toString */
-
- /**
- * Return a double value representation.
- *
- * @return The value with double precision.
- * @since 2011-02-12
- */
- public double doubleValue() {
- /*
- * First compute the square to prevent overflows if the two pieces of
- * the prefactor and the discriminant are of very different magnitude.
- */
- final Rational p2 = pref.pow(2).multiply(disc);
- System.out.println("dv sq " + p2.toString());
- final double res = p2.doubleValue();
- System.out.println("dv sq " + res);
- return pref.signum() >= 0 ? Math.sqrt(res) : -Math.sqrt(res);
- } /* BigSurd.doubleValue */
-
- /**
- * Return a float value representation.
- *
- * @return The value with single precision.
- * @since 2011-02-12
- */
- public float floatValue() {
- return (float) doubleValue();
- } /* BigSurd.floatValue */
-
- /**
- * True if the value is integer.
- * Equivalent to the indication whether a conversion to an integer
- * can be exact.
- *
- * @since 2011-02-12
- */
- public boolean isBigInteger() {
- return pref.isBigInteger() && (disc.signum() == 0 || disc.compareTo(Rational.ONE) == 0);
- } /* BigSurd.isBigInteger */
-
- /**
- * True if the value is rational.
- * Equivalent to the indication whether a conversion to a Rational can be
- * exact.
- *
- * @since 2011-02-12
- */
- public boolean isRational() {
- return disc.signum() == 0 || disc.compareTo(Rational.ONE) == 0;
- } /* BigSurd.isRational */
-
- /**
- * Convert to a rational value if possible
- *
- * @since 2012-02-15
- */
- public Rational toRational() {
- if (isRational()) {
- return pref;
- } else {
- throw new ArithmeticException("Undefined conversion " + toFancyString() + " to Rational.");
- }
- } /* BigSurd.toRational */
-
- /**
- * The sign: 1 if the number is >0, 0 if ==0, -1 if <0
- *
- * @return the signum of the value.
- * @since 2011-02-12
- */
- public int signum() {
- /*
- * Since the disc is kept positive, this is the same
- * as the sign of the prefactor. This works because a zero discriminant
- * is always copied over to the prefactor, not hidden.
- */
- return pref.signum();
- } /* BigSurd.signum */
-
- /**
- * Normalize to squarefree discriminant.
- *
- * @throws Error
- * @since 2011-02-12
- */
- protected void normalize() throws Error {
- /*
- * Move squares out of the numerator and denominator of the discriminant
- */
- if (disc.signum() != 0) {
- /*
- * square-free part of the numerator: numer = numC*some^2
- */
- final BigInteger numC = BigIntegerMath.core(disc.numer());
- /*
- * extract the perfect square of the numerator
- */
- BigInteger sq = disc.numer().divide(numC);
- /*
- * extract the associated square root
- */
- BigInteger sqf = BigIntegerMath.isqrt(sq);
-
- /*
- * move sqf over to the pre-factor
- */
- pref = pref.multiply(sqf);
-
- final BigInteger denC = BigIntegerMath.core(disc.denom());
- sq = disc.denom().divide(denC);
- sqf = BigIntegerMath.isqrt(sq);
- pref = pref.divide(sqf);
-
- disc = new Rational(numC, denC);
- } else {
- pref = Rational.ZERO;
- }
- } /* BigSurd.normalize */
-
- /**
- * Normalize to coprime numerator and denominator in prefactor and
- * discriminant
- *
- * @throws Error
- * @since 2011-02-12
- */
- protected void normalizeG() throws Error {
- /*
- * Is there a common factor between the numerator of the prefactor
- * and the denominator of the discriminant ?
- */
- BigInteger d = pref.numer().abs().gcd(disc.denom());
- if (d.compareTo(BigInteger.ONE) > 0) {
- pref = pref.divide(d);
- /*
- * instead of multiplying with the square of d, using two steps
- * offers a change to recognize the common factor..
- */
- disc = disc.multiply(d);
- disc = disc.multiply(d);
- }
- /*
- * Is there a common factor between the denominator of the prefactor
- * and the numerator of the discriminant ?
- */
- d = pref.denom().gcd(disc.numer());
- if (d.compareTo(BigInteger.ONE) > 0) {
- pref = pref.multiply(d);
- /*
- * instead of dividing through the square of d, using two steps
- * offers a change to recognize the common factor..
- */
- disc = disc.divide(d);
- disc = disc.divide(d);
- }
- } /* BigSurd.normalizeG */
-
- /**
- * Return the approximate floating point representation.
- *
- * @param mc
- * Description of the accuracy needed.
- * @return A representation with digits valid as described by mc
- * @since 2012-02-15
- */
- public BigDecimal BigDecimalValue(final MathContext mc) {
- /*
- * the relative error of the result equals the relative error of the
- * prefactor plus half of the relative error of the discriminant.
- * So adding 3 digits temporarily is sufficient.
- */
- final MathContext locmc = new MathContext(mc.getPrecision() + 3, mc.getRoundingMode());
- /*
- * first the square root of the discriminant
- */
- final BigDecimal sqrdis = BigDecimalMath.sqrt(disc.BigDecimalValue(locmc), locmc);
- /*
- * Then multiply by the prefactor. If sqrdis is a terminating decimal
- * fraction,
- * we prevent early truncation of the result by truncating later.
- */
- final BigDecimal res = sqrdis.multiply(pref.BigDecimalValue(mc));
- return BigDecimalMath.scalePrec(res, mc);
- } /* BigDecimalValue */
-
-} /* BigSurd */
diff --git a/core/src/main/java/org/nevec/rjm/BigSurdVec.java b/core/src/main/java/org/nevec/rjm/BigSurdVec.java
deleted file mode 100644
index ff7c7be0..00000000
--- a/core/src/main/java/org/nevec/rjm/BigSurdVec.java
+++ /dev/null
@@ -1,650 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-import it.cavallium.warppi.util.Utils;
-
-/**
- * A BigSurdVec represents an algebraic sum or differences of values which each
- * term an instance of BigSurd. This mainly means that sums or differences of
- * two BigSurd (or two BigSurdVec) can be represented (exactly) as a BigSurdVec.
- *
- * @since 2012-02-15
- * @author Richard J. Mathar
- */
-public class BigSurdVec implements Comparable {
- /**
- * The value of zero.
- */
- static public BigSurdVec ZERO = new BigSurdVec();
-
- /**
- * The value of one.
- */
- static public BigSurdVec ONE = new BigSurdVec(BigSurd.ONE);
-
- /**
- * Internal representation: Each term as a single BigSurd. The value zero is
- * represented by an empty vector.
- */
- Vector terms;
-
- /**
- * Default ctor, which represents the zero.
- *
- * @since 2012-02-15
- */
- public BigSurdVec() {
- terms = new Vector<>();
- } /* ctor */
-
- /**
- * ctor given the value of a BigSurd.
- *
- * @param a
- * The value to be represented by this vector.
- * @since 2012-02-15
- */
- public BigSurdVec(final BigSurd a) {
- terms = new Vector<>(1);
- terms.add(a);
- } /* ctor */
-
- /**
- * ctor given two values, which (when added) represent this number a+b.
- *
- * @param a
- * The value to be represented by the first term of the vector.
- * @param b
- * The value to be represented by the second term of the vector.
- * @since 2012-02-15
- */
- public BigSurdVec(final BigSurd a, final BigSurd b) {
- terms = new Vector<>(2);
- terms.add(a);
- terms.add(b);
- try {
- normalize();
- } catch (final Error e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- } /* ctor */
-
- /**
- * Combine terms that can be written as a single surd. This unites for
- * example the terms sqrt(90) and sqrt(10) to 4*sqrt(10).
- *
- * @throws Error
- *
- * @since 2012-02-15
- */
- protected void normalize() throws Error {
- /*
- * nothing to be done if at most one term
- */
- if (terms.size() <= 1) {
- return;
- }
-
- final Vector newter = new Vector<>();
- newter.add(terms.firstElement());
- /*
- * add j-th element to the existing vector and combine were possible
- */
- for (int j = 1; j < terms.size(); j++) {
- final BigSurd todo = terms.elementAt(j);
- boolean merged = false;
- for (int ex = 0; ex < newter.size(); ex++) {
- BigSurd v = newter.elementAt(ex);
- /*
- * try to merge terms[j] and newter[ex]. todo = r * v with r a
- * rational number is needed. Replaces v with v+todo = v*(1+r)
- * if this reduction works.
- */
- final BigSurd r = todo.divide(v);
- if (r.isRational()) {
- /* compute r+1 */
- final Rational newpref = r.toRational().add(1);
- /*
- * eliminate accidental zeros; overwrite with v*(1+r).
- */
- if (newpref.compareTo(Rational.ZERO) == 0) {
- newter.removeElementAt(ex);
- } else {
- v = v.multiply(newpref);
- newter.setElementAt(v, ex);
- }
- merged = true;
- break;
- }
- }
- /*
- * append if none of the existing elements matched
- */
- if (!merged) {
- newter.add(todo);
- }
- }
-
- /* overwrite old version */
- terms = newter;
- } /* normalize */
-
- /**
- * Compare algebraic value with oth. Returns -1, 0 or +1 depending on
- * whether this is smaller, equal to or larger than oth.
- *
- * @param oth
- * The value with which this is to be compared.
- * @return 0 or +-1.
- * @since 2012-02-15
- */
- @Override
- public int compareTo(final BigSurdVec oth) {
- BigSurdVec diff;
- try {
- diff = this.subtract(oth);
- return diff.signum();
- } catch (final Error e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- return 0;
- }
- } /* compareTo */
-
- /**
- * Sign function. Returns -1, 0 or +1 depending on whether this is smaller,
- * equal to or larger than zero.
- *
- * @return 0 or +-1.
- * @throws Error
- * @since 2012-02-15
- */
- public int signum() throws Error {
- /*
- * the case of zero is unique, because no (reduced) vector of surds
- * other than the one element 0 itself can add/subtract to zero.
- */
- if (terms.size() == 0) {
- return 0;
- }
-
- /*
- * if there is one term: forward to the signum function of BigSurd
- */
- if (terms.size() == 1) {
- return terms.firstElement().signum();
- }
-
- /*
- * if all terms have a common sign: take that one offsig is the index of
- * the first "offending" term in the sense that its sign doese not agree
- * with the term[0].
- */
- final int sig0 = terms.elementAt(0).signum();
- int offsig = 1;
- for (; offsig < terms.size(); offsig++) {
- if (terms.elementAt(offsig).signum() != sig0) {
- break;
- }
- }
- if (offsig >= terms.size()) {
- return sig0;
- }
-
- /*
- * if there are two terms (now known to have different sign): forward to
- * the comparison of the two elements as BigSurds
- */
- if (terms.size() == 2) {
- return terms.elementAt(0).compareTo(terms.elementAt(1).negate());
- }
-
- /*
- * if there are three terms, move the one with the offending sign to the
- * other side and square both sides (which looses the sign) to remove
- * all but one surds. The difference of the squared sides contains at
- * most two terms, which reduces to the case above. t(0)+t(offbar) <>
- * -t(offs)
- */
- if (terms.size() == 3) {
- BigSurdVec lhs;
- if (offsig == 2) {
- lhs = new BigSurdVec(terms.elementAt(0), terms.elementAt(1));
- } else {
- lhs = new BigSurdVec(terms.elementAt(0), terms.elementAt(2));
- }
- lhs = lhs.sqr();
- /*
- * Strange line: this line isn't used, but it's present in this
- * code!
- *
- *
- *
- * BigSurd rhs = new BigSurd(terms.elementAt(offsig).sqr(),
- * Rational.ONE);
- *
- *
- *
- */
- if (lhs.compareTo(lhs) > 0) {
- /*
- * dominating sign was t(0)+t(offbar)
- */
- return terms.elementAt(0).signum();
- } else {
- return terms.elementAt(offsig).signum();
- }
- }
-
- /*
- * for a larger number of terms: take a floating point representation
- * with a small but correct number of digits, and resume with the sign
- * of that one.
- */
- return floatValue() > 0. ? 1 : -1;
-
- } /* signum */
-
- /**
- * Construct an approximate floating point representation
- *
- * @param mc
- * The intended accuracy of the result.
- * @return A truncated version with the precision described by mc
- */
- public BigDecimal BigDecimalValue(final MathContext mc) {
- /*
- * simple cases with one term forwarded to the BigSurd class
- */
- if (terms.size() == 0) {
- return BigDecimal.ZERO;
- } else if (terms.size() == 1) {
- return terms.firstElement().BigDecimalValue(mc);
- }
-
- /*
- * To reduce cancellation errors, loop over increasing local precision
- * until we are stable to the required result. Keep the old (less
- * precise) estimate in res[0], and the newer, more precise in res[1].
- */
- final BigDecimal[] res = new BigDecimal[2];
- res[0] = BigDecimal.ZERO;
- for (int addpr = 1;; addpr += 3) {
- final MathContext locmc = new MathContext(mc.getPrecision() + addpr, mc.getRoundingMode());
- res[1] = BigDecimal.ZERO;
- for (final BigSurd j : terms) {
- res[1] = BigDecimalMath.addRound(res[1], j.BigDecimalValue(locmc));
- }
- if (addpr > 1) {
- final BigDecimal err = res[1].subtract(res[0]).abs();
- final int prec = BigDecimalMath.err2prec(res[1], err);
- if (prec > mc.getPrecision()) {
- break;
- }
- }
- res[0] = res[1];
- }
- return BigDecimalMath.scalePrec(res[1], mc);
-
- } /* BigDecimalValue */
-
- /**
- * Construct an approximate floating point representation
- *
- * @return A truncated version with the precision described by mc
- */
- public double doubleValue() {
- final BigDecimal bd = BigDecimalValue(MathContext.DECIMAL128);
- return bd.doubleValue();
- } /* doubleValue */
-
- /**
- * Construct an approximate floating point representation
- *
- * @return A truncated version with the precision described by mc
- */
- public double floatValue() {
- final BigDecimal bd = BigDecimalValue(MathContext.DECIMAL64);
- return bd.floatValue();
- } /* floatValue */
-
- /**
- * Add two vectors algebraically.
- *
- * @param val
- * The value to be added to this.
- * @return The new value representing this+val.
- * @throws Error
- */
- public BigSurdVec add(final BigSurdVec val) throws Error {
- final BigSurdVec sum = new BigSurdVec();
- /*
- * concatenate the vectors and eliminate common overlaps
- */
- for (final BigSurd term : terms) {
- if (term.compareTo(BigSurd.ZERO) != 0) {
- sum.terms.add(term);
- }
- }
- for (final BigSurd term : val.terms) {
- if (term.compareTo(BigSurd.ZERO) != 0) {
- sum.terms.add(term);
- }
- }
- sum.normalize();
- return sum;
- } /* add */
-
- /**
- * Add two vectors algebraically.
- *
- * @param val
- * The value to be added to this.
- * @return The new value representing this+val.
- * @throws Error
- */
- public BigSurdVec add(final BigSurd val) throws Error {
- final BigSurdVec sum = new BigSurdVec();
- /*
- * concatenate the vectors and eliminate common overlaps
- */
- sum.terms.addAll(terms);
- sum.terms.add(val);
- sum.normalize();
- return sum;
- } /* add */
-
- /**
- * Subtract another number.
- *
- * @param val
- * The value to be subtracted from this.
- * @return The new value representing this-val.
- * @throws Error
- */
- public BigSurdVec subtract(final BigSurdVec val) throws Error {
- final BigSurdVec sum = new BigSurdVec();
- /*
- * concatenate the vectors and eliminate common overlaps
- */
- sum.terms.addAll(terms);
- for (final BigSurd s : val.terms) {
- sum.terms.add(s.negate());
- }
- sum.normalize();
- return sum;
- } /* subtract */
-
- /**
- * Subtract another number.
- *
- * @param val
- * The value to be subtracted from this.
- * @return The new value representing this-val.
- * @throws Error
- */
- public BigSurdVec subtract(final BigSurd val) throws Error {
- final BigSurdVec sum = new BigSurdVec();
- /*
- * concatenate the vectors and eliminate common overlaps
- */
- sum.terms.addAll(terms);
- sum.terms.add(val.negate());
- sum.normalize();
- return sum;
- } /* subtract */
-
- /**
- * Compute the negative.
- *
- * @return -this.
- * @since 2012-02-15
- */
- public BigSurdVec negate() {
- /*
- * accumulate the negated elements of term one by one
- */
- final BigSurdVec resul = new BigSurdVec();
- for (final BigSurd s : terms) {
- resul.terms.add(s.negate());
- }
- /*
- * no normalization step here, because the negation of all terms does
- * not introduce new common factors
- */
- return resul;
- } /* negate */
-
- /**
- * Compute the square.
- *
- * @return this value squared.
- * @throws Error
- * @since 2012-02-15
- */
- public BigSurdVec sqr() throws Error {
- /*
- * Binomial expansion. First the sum of the terms squared, then 2 times
- * the mixed products.
- */
- final BigSurdVec resul = new BigSurdVec();
- for (int i = 0; i < terms.size(); i++) {
- resul.terms.add(new BigSurd(terms.elementAt(i).sqr(), Rational.ONE));
- }
- for (int i = 0; i < terms.size() - 1; i++) {
- for (int j = i + 1; j < terms.size(); j++) {
- resul.terms.add(terms.elementAt(i).multiply(terms.elementAt(j)).multiply(2));
- }
- }
- resul.normalize();
- return resul;
- } /* sqr */
-
- /**
- * Multiply by another square root.
- *
- * @param val
- * a second number of this type.
- * @return the product of this with the val.
- * @throws Error
- * @since 2011-02-12
- */
- public BigSurdVec multiply(final BigSurd val) throws Error {
- final BigSurdVec resul = new BigSurdVec();
- for (final BigSurd s : terms) {
- resul.terms.add(s.multiply(val));
- }
- resul.normalize();
- return resul;
- } /* multiply */
-
- public BigSurdVec multiply(final BigSurdVec val) throws Error {
- BigSurdVec resul = new BigSurdVec();
- for (final BigSurd s : terms) {
- resul.terms.add(s);
- }
- for (final BigSurd s : val.terms) {
- resul = resul.multiply(s);
- }
- return resul;
- } /* multiply */
-
- public BigSurdVec divide(final BigSurd val) throws Error {
- final BigSurdVec resul = new BigSurdVec();
- for (final BigSurd s : terms) {
- resul.terms.add(s.divide(val));
- }
- resul.normalize();
- return resul;
- } /* multiply */
-
- public BigSurdVec divide(final BigSurdVec val) throws Error {
- BigSurdVec resul = new BigSurdVec();
- resul.terms = terms;
- for (final BigSurd s : val.terms) {
- resul = resul.divide(s);
- }
- return resul;
- } /* divide */
-
- /**
- * True if the value is rational. Equivalent to the indication whether a
- * conversion to a Rational can be exact.
- *
- * @since 2011-02-12
- */
- public boolean isRational() {
- boolean val = false;
- for (final BigSurd s : terms) {
- val = s.isRational();
- if (val == false) {
- break;
- }
- }
- return val;
- } /* BigSurdVec.isRational */
-
- /**
- * True if the value is BigInteger. Equivalent to the indication whether a
- * conversion to a BigInteger can be exact.
- *
- * @since 2011-02-12
- */
- public boolean isBigInteger() {
- boolean val = false;
- for (final BigSurd s : terms) {
- val = s.isBigInteger();
- if (val == false) {
- break;
- }
- }
- return val;
- } /* BigSurdVec.isRational */
-
- /**
- * Convert to a rational value if possible
- *
- * @since 2012-02-15
- */
- public Rational toRational() {
- Rational rat = Rational.ZERO;
- if (isRational() == false) {
- throw new ArithmeticException("Undefined conversion " + toString() + " to Rational.");
- }
- for (final BigSurd s : terms) {
- rat = rat.add(s.pref);
- }
- return rat;
- } /* BigSurd.toRational */
-
- /**
- * Convert to a BigInteger value if possible
- *
- * @since 2012-02-15
- */
- public BigInteger toBigInteger() {
- BigDecimal tmp = BigDecimal.ZERO.setScale(Utils.scale, Utils.scaleMode);
- if (isBigInteger() == false) {
- throw new ArithmeticException("Undefined conversion " + toString() + " to Rational.");
- }
- for (final BigSurd s : terms) {
- tmp = BigDecimalMath.addRound(tmp, s.pref.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2)));
- }
- return tmp.toBigInteger();
- } /* BigSurd.toRational */
-
- /**
- * Convert to a BigDecimal value if possible
- *
- * @since 2012-02-15
- */
- public BigDecimal toBigDecimal() {
- BigDecimal tmp = BigDecimal.ZERO.setScale(Utils.scale, Utils.scaleMode);
- for (final BigSurd s : terms) {
- tmp = BigDecimalMath.addRound(tmp, s.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2)));
- }
- return tmp;
- } /* BigSurd.toBigDecimal */
-
- /**
- * Return a string in the format (number/denom)*()^(1/2). If the
- * discriminant equals 1, print just the prefactor.
- *
- * @return the human-readable version in base 10
- * @since 2012-02-16
- */
- @Override
- public String toString() {
- /*
- * simple cases with one term forwarded to the BigSurd class
- */
- if (terms.size() == 0) {
- return new String("0");
- } else {
- String s = new String();
- for (int t = 0; t < terms.size(); t++) {
- final BigSurd bs = terms.elementAt(t);
- if (bs.signum() > 0) {
- s += "+";
- }
- s += bs.toString();
- }
- return s;
- }
- } /* toString */
-
- public String toFancyString() {
- if (terms.size() == 0) {
- return new String("0");
- } else {
- BigInteger denominator = BigInteger.ONE;
- for (int i = 0; i < terms.size(); i++) {
- denominator = denominator.multiply(terms.elementAt(i).pref.b);
- }
- String s = "";
- if (denominator.compareTo(BigInteger.ONE) != 0) {
- s += "(";
- }
- for (int t = 0; t < terms.size(); t++) {
- final BigSurd bs = terms.elementAt(t);
- if (bs.signum() > 0 && t > 0) {
- s += "+";
- }
- if (bs.isBigInteger()) {
- s += bs.BigDecimalValue(new MathContext(Utils.scale, Utils.scaleMode2)).toBigInteger().toString();
- } else if (bs.isRational()) {
- s += bs.toRational().toString();
- } else {
- final BigInteger numerator = bs.pref.multiply(denominator).numer();
- if (numerator.compareTo(BigInteger.ONE) != 0) {
- s += numerator.toString();
- s += "*";
- // s += "("; Radice quadrata. non servono le parentesi.
- }
- s += "â’¶";
- if (bs.disc.isInteger()) {
- s += bs.disc.toString();
- } else {
- s += "(" + bs.disc.toString() + ")";
- }
- if (numerator.compareTo(BigInteger.ONE) != 0) {
- // s += ")"; Radice quadrata. non servono le parentesi.
- }
- }
- }
- if (denominator.compareTo(BigInteger.ONE) != 0) {
- s += ")";
- s += "/";
- s += denominator;
- }
- return s;
- }
- }
-
-} /* BigSurdVec */
diff --git a/core/src/main/java/org/nevec/rjm/Euler.java b/core/src/main/java/org/nevec/rjm/Euler.java
deleted file mode 100644
index c29a09cb..00000000
--- a/core/src/main/java/org/nevec/rjm/Euler.java
+++ /dev/null
@@ -1,73 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-/**
- * Euler numbers
- *
- * @see A000364 in the OEIS.
- * @since 2008-10-30
- * @author Richard J. Mathar
- */
-public class Euler {
- /*
- * The list of all Euler numbers as a vector, n=0,2,4,....
- */
- static protected Vector a = new Vector<>();
-
- /**
- * Ctor(). Fill the hash list initially with E_0 to E_3.
- */
- public Euler() {
- if (Euler.a.size() == 0) {
- Euler.a.add(BigInteger.ONE);
- Euler.a.add(BigInteger.ONE);
- Euler.a.add(new BigInteger("5"));
- Euler.a.add(new BigInteger("61"));
- }
- }
-
- /**
- * Compute a coefficient in the internal table.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the E_0 term.
- */
- protected void set(final int n) {
- while (n >= Euler.a.size()) {
- BigInteger val = BigInteger.ZERO;
- boolean sigPos = true;
- final int thisn = Euler.a.size();
- for (int i = thisn - 1; i > 0; i--) {
- BigInteger f = new BigInteger("" + Euler.a.elementAt(i).toString());
- f = f.multiply(BigIntegerMath.binomial(2 * thisn, 2 * i));
- if (sigPos) {
- val = val.add(f);
- } else {
- val = val.subtract(f);
- }
- sigPos = !sigPos;
- }
- if (thisn % 2 == 0) {
- val = val.subtract(BigInteger.ONE);
- } else {
- val = val.add(BigInteger.ONE);
- }
- Euler.a.add(val);
- }
- }
-
- /**
- * The Euler number at the index provided.
- *
- * @param n
- * the index, non-negative.
- * @return the E_0=E_1=1 , E_2=5, E_3=61 etc
- */
- public BigInteger at(final int n) {
- set(n);
- return Euler.a.elementAt(n);
- }
-
-} /* Euler */
diff --git a/core/src/main/java/org/nevec/rjm/EulerPhi.java b/core/src/main/java/org/nevec/rjm/EulerPhi.java
deleted file mode 100644
index 639b34b1..00000000
--- a/core/src/main/java/org/nevec/rjm/EulerPhi.java
+++ /dev/null
@@ -1,66 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-
-/**
- * Euler totient function.
- *
- * @see A000010 in the OEIS.
- * @since 2008-10-14
- * @since 2012-03-04 Adapted to new Ifactor representation.
- * @author Richard J. Mathar
- */
-public class EulerPhi {
- /**
- * Default constructor.
- * Does nothing().
- */
- public EulerPhi() {}
-
- /**
- * Compute phi(n).
- *
- * @param n
- * The positive argument of the function.
- * @return phi(n)
- */
- public BigInteger at(final int n) {
- return at(new BigInteger("" + n));
- } /* at */
-
- /**
- * Compute phi(n).
- *
- * @param n
- * The positive argument of the function.
- * @return phi(n)
- */
- public BigInteger at(final BigInteger n) {
- if (n.compareTo(BigInteger.ZERO) <= 0) {
- throw new ArithmeticException("negative argument " + n + " of EulerPhi");
- }
- final Ifactor prFact = new Ifactor(n);
- BigInteger phi = n;
- if (n.compareTo(BigInteger.ONE) > 0) {
- for (int i = 0; i < prFact.primeexp.size(); i += 2) {
- final BigInteger p = new BigInteger(prFact.primeexp.elementAt(i).toString());
- final BigInteger p_1 = p.subtract(BigInteger.ONE);
- phi = phi.multiply(p_1).divide(p);
- }
- }
- return phi;
- } /* at */
-
- /**
- * Test program.
- * It takes one argument n and prints the value phi(n).
- * java -cp . org.nevec.rjm.EulerPhi n
- *
- * @since 2006-08-14
- */
- public static void main(final String[] args) throws ArithmeticException {
- final EulerPhi a = new EulerPhi();
- final int n = new Integer(args[0]).intValue();
- System.out.println("phi(" + n + ") = " + a.at(n));
- }
-} /* EulerPhi */
diff --git a/core/src/main/java/org/nevec/rjm/Factorial.java b/core/src/main/java/org/nevec/rjm/Factorial.java
deleted file mode 100644
index 175bab0b..00000000
--- a/core/src/main/java/org/nevec/rjm/Factorial.java
+++ /dev/null
@@ -1,79 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-/**
- * Factorials.
- *
- * @since 2006-06-25
- * @since 2012-02-15 Storage of the values based on Ifactor, not BigInteger.
- * @author Richard J. Mathar
- */
-public class Factorial {
- /**
- * The list of all factorials as a vector.
- */
- static Vector a = new Vector<>();
-
- /**
- * ctor().
- * Initialize the vector of the factorials with 0!=1 and 1!=1.
- */
- public Factorial() {
- if (Factorial.a.size() == 0) {
- Factorial.a.add(Ifactor.ONE);
- Factorial.a.add(Ifactor.ONE);
- }
- } /* ctor */
-
- /**
- * Compute the factorial of the non-negative integer.
- *
- * @param n
- * the argument to the factorial, non-negative.
- * @return the factorial of n.
- */
- public BigInteger at(final int n) {
- /*
- * extend the internal list if needed.
- */
- growto(n);
- return Factorial.a.elementAt(n).n;
- } /* at */
-
- /**
- * Compute the factorial of the non-negative integer.
- *
- * @param n
- * the argument to the factorial, non-negative.
- * @return the factorial of n.
- */
- public Ifactor toIfactor(final int n) {
- /*
- * extend the internal list if needed.
- */
- growto(n);
- return Factorial.a.elementAt(n);
- } /* at */
-
- /**
- * Extend the internal table to cover up to n!
- *
- * @param n
- * The maximum factorial to be supported.
- * @since 2012-02-15
- */
- private void growto(final int n) {
- /*
- * extend the internal list if needed. Size to be 2 for n<=1, 3 for n<=2
- * etc.
- */
- while (Factorial.a.size() <= n) {
- final int lastn = Factorial.a.size() - 1;
- final Ifactor nextn = new Ifactor(lastn + 1);
- Factorial.a.add(Factorial.a.elementAt(lastn).multiply(nextn));
- }
- } /* growto */
-
-} /* Factorial */
diff --git a/core/src/main/java/org/nevec/rjm/Harmonic.java b/core/src/main/java/org/nevec/rjm/Harmonic.java
deleted file mode 100644
index 5058c3a2..00000000
--- a/core/src/main/java/org/nevec/rjm/Harmonic.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package org.nevec.rjm;
-
-/**
- * Harmonic numbers.
- * H(n) is the sum of the inverses of the integers from 1 to n.
- *
- * @since 2008-10-19
- * @author Richard J. Mathar
- */
-public class Harmonic {
- /**
- * ctor()
- * Does nothing.
- */
- public Harmonic() {}
-
- /**
- * The Harmonic number at the index specified
- *
- * @param n
- * the index, non-negative.
- * @return the H_1=1 for n=1, H_2=3/2 for n=2 etc.
- * For values of n less than 1, zero is returned.
- */
- public Rational at(final int n) {
- if (n < 1) {
- return new Rational(0, 1);
- } else {
- /*
- * start with 1 as the result
- */
- Rational a = new Rational(1, 1);
-
- /*
- * add 1/i for i=2..n
- */
- for (int i = 2; i <= n; i++) {
- a = a.add(new Rational(1, i));
- }
- return a;
- }
- }
-} /* Harmonic */
diff --git a/core/src/main/java/org/nevec/rjm/Ifactor.java b/core/src/main/java/org/nevec/rjm/Ifactor.java
deleted file mode 100644
index fe9948e3..00000000
--- a/core/src/main/java/org/nevec/rjm/Ifactor.java
+++ /dev/null
@@ -1,835 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Collections;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * Factored integers.
- * This class contains a non-negative integer with the prime factor
- * decomposition attached.
- *
- * @since 2006-08-14
- * @since 2012-02-14 The internal representation contains the bases, and becomes
- * sparser if few
- * prime factors are present.
- * @author Richard J. Mathar
- */
-public class Ifactor implements Cloneable, Comparable {
- /**
- * The standard representation of the number
- */
- public BigInteger n;
-
- /*
- * The bases and powers of the prime factorization.
- * representation n = primeexp[0]^primeexp[1]*primeexp[2]^primeexp[3]*...
- * The value 0 is represented by an empty vector, the value 1 by a vector of
- * length 1
- * with a single power of 0.
- */
- public Vector primeexp;
-
- final public static Ifactor ONE = new Ifactor(1);
-
- final public static Ifactor ZERO = new Ifactor(0);
-
- /**
- * Constructor given an integer.
- * constructor with an ordinary integer
- *
- * @param number
- * the standard representation of the integer
- */
- public Ifactor(int number) {
- n = new BigInteger("" + number);
- primeexp = new Vector<>();
- if (number > 1) {
- int primindx = 0;
- final Prime primes = new Prime();
- /*
- * Test division against all primes.
- */
- while (number > 1) {
- int ex = 0;
- /*
- * primindx=0 refers to 2, =1 to 3, =2 to 5, =3 to 7 etc
- */
- final int p = primes.at(primindx).intValue();
- while (number % p == 0) {
- ex++;
- number /= p;
- if (number == 1) {
- break;
- }
- }
- if (ex > 0) {
- primeexp.add(new Integer(p));
- primeexp.add(new Integer(ex));
- }
- primindx++;
- }
- } else if (number == 1) {
- primeexp.add(new Integer(1));
- primeexp.add(new Integer(0));
- }
- } /* Ifactor */
-
- /**
- * Constructor given a BigInteger .
- * Constructor with an ordinary integer, calling a prime factor
- * decomposition.
- *
- * @param number
- * the BigInteger representation of the integer
- */
- public Ifactor(BigInteger number) {
- n = number;
- primeexp = new Vector<>();
- if (number.compareTo(BigInteger.ONE) == 0) {
- primeexp.add(new Integer(1));
- primeexp.add(new Integer(0));
- } else {
- int primindx = 0;
- final Prime primes = new Prime();
- /*
- * Test for division against all primes.
- */
- while (number.compareTo(BigInteger.ONE) == 1) {
- int ex = 0;
- final BigInteger p = primes.at(primindx);
- while (number.remainder(p).compareTo(BigInteger.ZERO) == 0) {
- ex++;
- number = number.divide(p);
- if (number.compareTo(BigInteger.ONE) == 0) {
- break;
- }
- }
- if (ex > 0) {
- primeexp.add(new Integer(p.intValue()));
- primeexp.add(new Integer(ex));
- }
- primindx++;
- }
- }
- } /* Ifactor */
-
- /**
- * Constructor given a list of exponents of the prime factor decomposition.
- *
- * @param pows
- * the vector with the sorted list of exponents.
- * pows[0] is the exponent of 2, pows[1] the exponent of 3,
- * pows[2] the exponent of 5 etc.
- * Note that this list does not include the primes, but assumes a
- * continuous prime-smooth basis.
- */
- public Ifactor(final Vector pows) {
- primeexp = new Vector<>(2 * pows.size());
- if (pows.size() > 0) {
- n = BigInteger.ONE;
- final Prime primes = new Prime();
- /*
- * Build the full number by the product of all powers of the primes.
- */
- for (int primindx = 0; primindx < pows.size(); primindx++) {
- final int ex = pows.elementAt(primindx).intValue();
- final BigInteger p = primes.at(primindx);
- n = n.multiply(p.pow(ex));
- primeexp.add(new Integer(p.intValue()));
- primeexp.add(new Integer(ex));
- }
- } else {
- n = BigInteger.ZERO;
- }
- } /* Ifactor */
-
- /**
- * Copy constructor.
- *
- * @param oth
- * the value to be copied
- */
- public Ifactor(final Ifactor oth) {
- n = oth.n;
- primeexp = oth.primeexp;
- } /* Ifactor */
-
- /**
- * Deep copy.
- *
- * @since 2009-08-14
- */
- @Override
- public Ifactor clone() {
- /*
- * Line not used:
- *
- * Vector p = (Vector)primeexp.clone();
- *
- */
- final Ifactor cl = new Ifactor(0);
- cl.n = new BigInteger("" + n);
- return cl;
- } /* Ifactor.clone */
-
- /**
- * Comparison of two numbers.
- * The value of this method is in allowing the Vector<>.contains() calls
- * that use the value,
- * not the reference for comparison.
- *
- * @param oth
- * the number to compare this with.
- * @return true if both are the same numbers, false otherwise.
- */
- public boolean equals(final Ifactor oth) {
- return n.compareTo(oth.n) == 0;
- } /* Ifactor.equals */
-
- /**
- * Multiply with another positive integer.
- *
- * @param oth
- * the second factor.
- * @return the product of both numbers.
- */
- public Ifactor multiply(final BigInteger oth) {
- /*
- * the optimization is to factorize oth _before_ multiplying
- */
- return multiply(new Ifactor(oth));
- } /* Ifactor.multiply */
-
- /**
- * Multiply with another positive integer.
- *
- * @param oth
- * the second factor.
- * @return the product of both numbers.
- */
- public Ifactor multiply(final int oth) {
- /*
- * the optimization is to factorize oth _before_ multiplying
- */
- return multiply(new Ifactor(oth));
- } /* Ifactor.multiply */
-
- /**
- * Multiply with another positive integer.
- *
- * @param oth
- * the second factor.
- * @return the product of both numbers.
- */
- public Ifactor multiply(final Ifactor oth) {
- /*
- * This might be done similar to the lcm() implementation by adding
- * the powers of the components and calling the constructor with the
- * list of exponents. This here is the simplest implementation, but slow
- * because
- * it calls another prime factorization of the product:
- * return( new Ifactor(n.multiply(oth.n))) ;
- */
- return multGcdLcm(oth, 0);
- }
-
- /**
- * Lowest common multiple of this with oth.
- *
- * @param oth
- * the second parameter of lcm(this,oth)
- * @return the lowest common multiple of both numbers. Returns zero
- * if any of both arguments is zero.
- */
- public Ifactor lcm(final Ifactor oth) {
- return multGcdLcm(oth, 2);
- }
-
- /**
- * Greatest common divisor of this and oth.
- *
- * @param oth
- * the second parameter of gcd(this,oth)
- * @return the lowest common multiple of both numbers. Returns zero
- * if any of both arguments is zero.
- */
- public Ifactor gcd(final Ifactor oth) {
- return multGcdLcm(oth, 1);
- }
-
- /**
- * Multiply with another positive integer.
- *
- * @param oth
- * the second factor.
- * @param type
- * 0 to multiply, 1 for gcd, 2 for lcm
- * @return the product, gcd or lcm of both numbers.
- */
- protected Ifactor multGcdLcm(final Ifactor oth, final int type) {
- final Ifactor prod = new Ifactor(0);
- /*
- * skip the case where 0*something =0, falling thru to the empty
- * representation for 0
- */
- if (primeexp.size() != 0 && oth.primeexp.size() != 0) {
- /*
- * Cases of 1 times something return something.
- * Cases of lcm(1, something) return something.
- * Cases of gcd(1, something) return 1.
- */
- if (primeexp.firstElement().intValue() == 1 && type == 0) {
- return oth;
- } else if (primeexp.firstElement().intValue() == 1 && type == 2) {
- return oth;
- } else if (primeexp.firstElement().intValue() == 1 && type == 1) {
- return this;
- } else if (oth.primeexp.firstElement().intValue() == 1 && type == 0) {
- return this;
- } else if (oth.primeexp.firstElement().intValue() == 1 && type == 2) {
- return this;
- } else if (oth.primeexp.firstElement().intValue() == 1 && type == 1) {
- return oth;
- } else {
- int idxThis = 0;
- int idxOth = 0;
- switch (type) {
- case 0:
- prod.n = n.multiply(oth.n);
- break;
- case 1:
- prod.n = n.gcd(oth.n);
- break;
- case 2:
- /*
- * the awkward way, lcm = product divided by gcd
- */
- prod.n = n.multiply(oth.n).divide(n.gcd(oth.n));
- break;
- }
-
- /*
- * scan both representations left to right, increasing prime
- * powers
- */
- while (idxOth < oth.primeexp.size() || idxThis < primeexp.size()) {
- if (idxOth >= oth.primeexp.size()) {
- /*
- * exhausted the list in oth.primeexp; copy over the
- * remaining 'this'
- * if multiplying or lcm, discard if gcd.
- */
- if (type == 0 || type == 2) {
- prod.primeexp.add(primeexp.elementAt(idxThis));
- prod.primeexp.add(primeexp.elementAt(idxThis + 1));
- }
- idxThis += 2;
- } else if (idxThis >= primeexp.size()) {
- /*
- * exhausted the list in primeexp; copy over the
- * remaining 'oth'
- */
- if (type == 0 || type == 2) {
- prod.primeexp.add(oth.primeexp.elementAt(idxOth));
- prod.primeexp.add(oth.primeexp.elementAt(idxOth + 1));
- }
- idxOth += 2;
- } else {
- Integer p;
- int ex;
- switch (primeexp.elementAt(idxThis).compareTo(oth.primeexp.elementAt(idxOth))) {
- case 0:
- /* same prime bases p in both factors */
- p = primeexp.elementAt(idxThis);
- switch (type) {
- case 0:
- /* product means adding exponents */
- ex = primeexp.elementAt(idxThis + 1).intValue() + oth.primeexp.elementAt(idxOth + 1).intValue();
- break;
- case 1:
- /* gcd means minimum of exponents */
- ex = Math.min(primeexp.elementAt(idxThis + 1).intValue(), oth.primeexp.elementAt(idxOth + 1).intValue());
- break;
- default:
- /* lcm means maximum of exponents */
- ex = Math.max(primeexp.elementAt(idxThis + 1).intValue(), oth.primeexp.elementAt(idxOth + 1).intValue());
- break;
- }
- prod.primeexp.add(p);
- prod.primeexp.add(new Integer(ex));
- idxOth += 2;
- idxThis += 2;
- break;
- case 1:
- /*
- * this prime base bigger than the other and
- * taken later
- */
- if (type == 0 || type == 2) {
- prod.primeexp.add(oth.primeexp.elementAt(idxOth));
- prod.primeexp.add(oth.primeexp.elementAt(idxOth + 1));
- }
- idxOth += 2;
- break;
- default:
- /*
- * this prime base smaller than the other and
- * taken now
- */
- if (type == 0 || type == 2) {
- prod.primeexp.add(primeexp.elementAt(idxThis));
- prod.primeexp.add(primeexp.elementAt(idxThis + 1));
- }
- idxThis += 2;
- }
- }
- }
- }
- }
- return prod;
- } /* Ifactor.multGcdLcm */
-
- /**
- * Integer division through another positive integer.
- *
- * @param oth
- * the denominator.
- * @return the division of this through the oth, discarding the remainder.
- */
- public Ifactor divide(final Ifactor oth) {
- /*
- * todo: it'd probably be faster to cancel the gcd(this,oth) first in
- * the prime power
- * representation, which would avoid a more strenous factorization of
- * the integer ratio
- */
- return new Ifactor(n.divide(oth.n));
- } /* Ifactor.divide */
-
- /**
- * Summation with another positive integer
- *
- * @param oth
- * the other term.
- * @return the sum of both numbers
- */
- public Ifactor add(final BigInteger oth) {
- /*
- * avoid refactorization if oth is zero...
- */
- if (oth.compareTo(BigInteger.ZERO) != 0) {
- return new Ifactor(n.add(oth));
- } else {
- return this;
- }
- } /* Ifactor.add */
-
- /**
- * Exponentiation with a positive integer.
- *
- * @param exponent
- * the non-negative exponent
- * @return n^exponent. If exponent=0, the result is 1.
- */
- public Ifactor pow(final int exponent) throws ArithmeticException {
- /*
- * three simple cases first
- */
- if (exponent < 0) {
- throw new ArithmeticException("Cannot raise " + toString() + " to negative " + exponent);
- } else if (exponent == 0) {
- return new Ifactor(1);
- } else if (exponent == 1) {
- return this;
- }
-
- /*
- * general case, the vector with the prime factor powers, which are
- * component-wise
- * exponentiation of the individual prime factor powers.
- */
- final Ifactor pows = new Ifactor(0);
- for (int i = 0; i < primeexp.size(); i += 2) {
- final Integer p = primeexp.elementAt(i);
- final int ex = primeexp.elementAt(i + 1).intValue();
- pows.primeexp.add(p);
- pows.primeexp.add(new Integer(ex * exponent));
- }
- return pows;
- } /* Ifactor.pow */
-
- /**
- * Pulling the r-th root.
- *
- * @param r
- * the positive or negative (nonzero) root.
- * @return n^(1/r).
- * The return value falls into the Ifactor class if r is positive,
- * but if r is negative
- * a Rational type is needed.
- * @throws Error
- * @since 2009-05-18
- */
- public Rational root(final int r) throws ArithmeticException, Error {
- if (r == 0) {
- throw new ArithmeticException("Cannot pull zeroth root of " + toString());
- } else if (r < 0) {
- /*
- * a^(-1/b)= 1/(a^(1/b))
- */
- final Rational invRoot = root(-r);
- return Rational.ONE.divide(invRoot);
- } else {
- final BigInteger pows = BigInteger.ONE;
- for (int i = 0; i < primeexp.size(); i += 2) {
- /*
- * all exponents must be multiples of r to succeed (that is, to
- * stay in the range of rational results).
- */
- final int ex = primeexp.elementAt(i + 1).intValue();
- if (ex % r != 0) {
- throw new ArithmeticException("Cannot pull " + r + "th root of " + toString());
- }
-
- pows.multiply(new BigInteger("" + primeexp.elementAt(i)).pow(ex / r));
- }
- /*
- * convert result to a Rational; unfortunately this will loose the
- * prime factorization
- */
- return new Rational(pows);
- }
- } /* Ifactor.root */
-
- /**
- * The set of positive divisors.
- *
- * @return the vector of divisors of the absolute value, sorted.
- * @since 2010-08-27
- */
- public Vector divisors() {
- /*
- * Recursive approach: the divisors of p1^e1*p2^e2*..*py^ey*pz^ez are
- * the divisors that don't contain the factor pz, and the
- * the divisors that contain any power of pz between 1 and up to ez
- * multiplied
- * by 1 or by a product that contains the factors p1..py.
- */
- final Vector d = new Vector<>();
- if (n.compareTo(BigInteger.ZERO) == 0) {
- return d;
- }
- d.add(BigInteger.ONE);
- if (n.compareTo(BigInteger.ONE) > 0) {
- /* Computes sigmaIncopml(p1^e*p2^e2...*py^ey) */
- final Ifactor dp = dropPrime();
-
- /* get ez */
- final int ez = primeexp.lastElement().intValue();
-
- final Vector partd = dp.divisors();
-
- /* obtain pz by lookup in the prime list */
- final BigInteger pz = new BigInteger(primeexp.elementAt(primeexp.size() - 2).toString());
-
- /*
- * the output contains all products of the form partd[]*pz^ez, ez>0,
- * and with the exception of the 1, all these are appended.
- */
- for (int i = 1; i < partd.size(); i++) {
- d.add(partd.elementAt(i));
- }
- for (int e = 1; e <= ez; e++) {
- final BigInteger pzez = pz.pow(e);
- for (int i = 0; i < partd.size(); i++) {
- d.add(partd.elementAt(i).multiply(pzez));
- }
- }
- }
- Collections.sort(d);
- return d;
- } /* Ifactor.divisors */
-
- /**
- * Sum of the divisors of the number.
- *
- * @return the sum of all divisors of the number, 1+....+n.
- */
- public Ifactor sigma() {
- return sigma(1);
- } /* Ifactor.sigma */
-
- /**
- * Sum of the k-th powers of divisors of the number.
- *
- * @return the sum of all divisors of the number, 1^k+....+n^k.
- */
- public Ifactor sigma(final int k) {
- /*
- * the question is whether keeping a factorization is worth the effort
- * or whether one should simply multiply these to return a BigInteger...
- */
- if (n.compareTo(BigInteger.ONE) == 0) {
- return Ifactor.ONE;
- } else if (n.compareTo(BigInteger.ZERO) == 0) {
- return Ifactor.ZERO;
- } else {
- /*
- * multiplicative: sigma_k(p^e) = [p^(k*(e+1))-1]/[p^k-1]
- * sigma_0(p^e) = e+1.
- */
- Ifactor resul = Ifactor.ONE;
- for (int i = 0; i < primeexp.size(); i += 2) {
- final int ex = primeexp.elementAt(i + 1).intValue();
- if (k == 0) {
- resul = resul.multiply(ex + 1);
- } else {
- final Integer p = primeexp.elementAt(i);
- final BigInteger num = new BigInteger(p.toString()).pow(k * (ex + 1)).subtract(BigInteger.ONE);
- final BigInteger deno = new BigInteger(p.toString()).pow(k).subtract(BigInteger.ONE);
- /*
- * This division is of course exact, no remainder
- * The costly prime factorization is hidden here.
- */
- final Ifactor f = new Ifactor(num.divide(deno));
- resul = resul.multiply(f);
- }
- }
- return resul;
- }
- } /* Ifactor.sigma */
-
- /**
- * Divide through the highest possible power of the highest prime.
- * If the current number is the prime factor product p1^e1 * p2*e2*
- * p3^e3*...*py^ey * pz^ez,
- * the value returned has the final factor pz^ez eliminated, which gives
- * p1^e1 * p2*e2* p3^e3*...*py^ey.
- *
- * @return the new integer obtained by removing the highest prime power.
- * If this here represents 0 or 1, it is returned without change.
- * @since 2006-08-20
- */
- public Ifactor dropPrime() {
- /*
- * the cases n==1 or n ==0
- */
- if (n.compareTo(BigInteger.ONE) <= 0) {
- return this;
- }
-
- /*
- * The cases n>1
- * Start empty. Copy all but the last factor over to the result
- * the vector with the new prime factor powers, which contain the
- * old prime factor powers up to but not including the last one.
- */
- final Ifactor pows = new Ifactor(0);
- pows.n = BigInteger.ONE;
- for (int i = 0; i < primeexp.size() - 2; i += 2) {
- pows.primeexp.add(primeexp.elementAt(i));
- pows.primeexp.add(primeexp.elementAt(i + 1));
- final BigInteger p = new BigInteger(primeexp.elementAt(i).toString());
- final int ex = primeexp.elementAt(i + 1).intValue();
- pows.n = pows.n.multiply(p.pow(ex));
- }
- return pows;
- } /* Ifactor.dropPrime */
-
- /**
- * Test whether this is a square of an integer (perfect square).
- *
- * @return true if this is an integer squared (including 0), else false
- */
- public boolean issquare() {
- /*
- * check the exponents, located at the odd-indexed positions
- */
- for (int i = 1; i < primeexp.size(); i += 2) {
- if (primeexp.elementAt(i).intValue() % 2 != 0) {
- return false;
- }
- }
- return true;
- } /* Ifactor.issquare */
-
- /**
- * The sum of the prime factor exponents, with multiplicity.
- *
- * @return the sum over the primeexp numbers
- */
- public int bigomega() {
- int resul = 0;
- for (int i = 1; i < primeexp.size(); i += 2) {
- resul += primeexp.elementAt(i).intValue();
- }
- return resul;
- } /* Ifactor.bigomega */
-
- /**
- * The sum of the prime factor exponents, without multiplicity.
- *
- * @return the number of distinct prime factors.
- * @since 2008-10-16
- */
- public int omega() {
- return primeexp.size() / 2;
- } /* Ifactor.omega */
-
- /**
- * The square-free part.
- *
- * @return the minimum m such that m times this number is a square.
- * @since 2008-10-16
- */
- public BigInteger core() {
- BigInteger resul = BigInteger.ONE;
- for (int i = 0; i < primeexp.size(); i += 2) {
- if (primeexp.elementAt(i + 1).intValue() % 2 != 0) {
- resul = resul.multiply(new BigInteger(primeexp.elementAt(i).toString()));
- }
- }
- return resul;
- } /* Ifactor.core */
-
- /**
- * The Moebius function.
- * 1 if n=1, else, if k is the number of distinct prime factors, return
- * (-1)^k,
- * else, if k has repeated prime factors, return 0.
- *
- * @return the moebius function.
- */
- public int moebius() {
- if (n.compareTo(BigInteger.ONE) <= 0) {
- return 1;
- }
- /* accumulate number of different primes in k */
- int k = 1;
- for (int i = 0; i < primeexp.size(); i += 2) {
- final int e = primeexp.elementAt(i + 1).intValue();
- if (e > 1) {
- return 0;
- } else if (e == 1) {
- /* accumulates (-1)^k */
- k *= -1;
- }
-
- }
- return k;
- } /* Ifactor.moebius */
-
- /**
- * Maximum of two values.
- *
- * @param oth
- * the number to compare this with.
- * @return the larger of the two values.
- */
- public Ifactor max(final Ifactor oth) {
- if (n.compareTo(oth.n) >= 0) {
- return this;
- } else {
- return oth;
- }
- } /* Ifactor.max */
-
- /**
- * Minimum of two values.
- *
- * @param oth
- * the number to compare this with.
- * @return the smaller of the two values.
- */
- public Ifactor min(final Ifactor oth) {
- if (n.compareTo(oth.n) <= 0) {
- return this;
- } else {
- return oth;
- }
- } /* Ifactor.min */
-
- /**
- * Maximum of a list of values.
- *
- * @param set
- * list of numbers.
- * @return the largest in the list.
- */
- public static Ifactor max(final Vector set) {
- Ifactor resul = set.elementAt(0);
- for (int i = 1; i < set.size(); i++) {
- resul = resul.max(set.elementAt(i));
- }
- return resul;
- } /* Ifactor.max */
-
- /**
- * Minimum of a list of values.
- *
- * @param set
- * list of numbers.
- * @return the smallest in the list.
- */
- public static Ifactor min(final Vector set) {
- Ifactor resul = set.elementAt(0);
- for (int i = 1; i < set.size(); i++) {
- resul = resul.min(set.elementAt(i));
- }
- return resul;
- } /* Ifactor.min */
-
- /**
- * Compare value against another Ifactor
- *
- * @param oth
- * The value to be compared agains.
- * @return 1, 0 or -1 according to being larger, equal to or smaller than
- * oth.
- * @since 2012-02-15
- */
- @Override
- public int compareTo(final Ifactor oth) {
- return n.compareTo(oth.n);
- } /* compareTo */
-
- /**
- * Convert to printable format
- *
- * @return a string of the form n:prime^pow*prime^pow*prime^pow...
- */
- @Override
- public String toString() {
- String resul = new String(n.toString() + ":");
- if (n.compareTo(BigInteger.ONE) == 0) {
- resul += "1";
- } else {
- boolean firstMul = true;
- for (int i = 0; i < primeexp.size(); i += 2) {
- if (!firstMul) {
- resul += "*";
- }
- if (primeexp.elementAt(i + 1).intValue() > 1) {
- resul += primeexp.elementAt(i).toString() + "^" + primeexp.elementAt(i + 1).toString();
- } else {
- resul += primeexp.elementAt(i).toString();
- }
- firstMul = false;
- }
- }
- return resul;
- } /* Ifactor.toString */
-
- /**
- * Test program.
- * It takes a single argument n and prints the integer factorizaton.
- * java -cp . org.nevec.rjm.Ifactor n
- */
- public static void main(final String[] args) throws Exception {
- final BigInteger n = new BigInteger(args[0]);
- System.out.println(new Ifactor(n));
- } /* Ifactor.main */
-} /* Ifactor */
diff --git a/core/src/main/java/org/nevec/rjm/PartitionsP.java b/core/src/main/java/org/nevec/rjm/PartitionsP.java
deleted file mode 100644
index 1af7559e..00000000
--- a/core/src/main/java/org/nevec/rjm/PartitionsP.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-/**
- * Number of partitions.
- *
- * @since 2008-10-15
- * @author Richard J. Mathar
- */
-public class PartitionsP {
- /**
- * The list of all partitions as a vector.
- */
- static protected Vector a = new Vector<>();
-
- /**
- * The maximum integer covered by the high end of the list.
- */
- static protected BigInteger nMax = new BigInteger("-1");
-
- /**
- * Default constructor initializing a list of partitions up to 7.
- */
- public PartitionsP() {
- if (PartitionsP.a.size() == 0) {
- PartitionsP.a.add(new BigInteger("" + 1));
- PartitionsP.a.add(new BigInteger("" + 1));
- PartitionsP.a.add(new BigInteger("" + 2));
- PartitionsP.a.add(new BigInteger("" + 3));
- PartitionsP.a.add(new BigInteger("" + 5));
- PartitionsP.a.add(new BigInteger("" + 7));
- }
- PartitionsP.nMax = new BigInteger("" + (PartitionsP.a.size() - 1));
- } /* ctor */
-
- /**
- * return the number of partitions of i
- *
- * @param i
- * the zero-based index into the list of partitions
- * @return the ith partition number. This is 1 if i=0 or 1, 2 if i=2 and so
- * forth.
- */
- public BigInteger at(final int i) {
- /*
- * If the current list is too small, increase in intervals
- * of 3 until the list has at least i elements.
- */
- while (i > PartitionsP.nMax.intValue()) {
- growto(PartitionsP.nMax.add(new BigInteger("" + 3)));
- }
- return PartitionsP.a.elementAt(i);
- } /* at */
-
- /**
- * extend the list of known partitions up to n
- *
- * @param n
- * the maximum integer hashed after the call.
- */
- private void growto(final BigInteger n) {
- while (PartitionsP.a.size() <= n.intValue()) {
- BigInteger per = new BigInteger("0");
- final BigInteger cursiz = new BigInteger("" + PartitionsP.a.size());
- for (int k = 0; k < PartitionsP.a.size(); k++) {
- final BigInteger tmp = PartitionsP.a.elementAt(k).multiply(BigIntegerMath.sigma(PartitionsP.a.size() - k));
- per = per.add(tmp);
- }
- PartitionsP.a.add(per.divide(cursiz));
- }
- PartitionsP.nMax = new BigInteger("" + (PartitionsP.a.size() - 1));
- } /* growto */
-
- /**
- * Test program.
- * It takes one integer argument n and prints P(n).
- * java -cp . org.nevec.rjm.PartitionsP n
- *
- * @since 2008-10-15
- */
- public static void main(final String[] args) throws Exception {
- final PartitionsP a = new PartitionsP();
- final int n = new Integer(args[0]).intValue();
- System.out.println("P(" + n + ")=" + a.at(n));
- }
-}
diff --git a/core/src/main/java/org/nevec/rjm/Prime.java b/core/src/main/java/org/nevec/rjm/Prime.java
deleted file mode 100644
index 2b1111a9..00000000
--- a/core/src/main/java/org/nevec/rjm/Prime.java
+++ /dev/null
@@ -1,321 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Vector;
-
-/**
- * Prime numbers.
- * The implementation is a very basic computation of the set of all primes
- * on demand, growing infinitely without any defined upper limit.
- * The effects of such scheme are (i) the lookup-times become shorter after
- * a while as more and more primes have been used and stored. The applications
- * appear to become faster. (ii) Using the implementation for factorizations
- * may easily require all available memory and stall finally, because indeed
- * a dense list of primes with growing upper bound is kept without any hashing
- * or lagging scheme.
- *
- * @since 2006-08-11
- * @author Richard J. Mathar
- */
-public class Prime {
- /**
- * The list of all numbers as a vector.
- */
- static Vector a = new Vector<>();
-
- /**
- * The maximum integer covered by the high end of the list.
- */
- static protected BigInteger nMax = new BigInteger("-1");
-
- /**
- * Default constructor initializing a list of primes up to 17.
- * 17 is enough to call the Miller-Rabin tests on the first 7 primes without
- * further
- * action.
- */
- public Prime() {
- if (Prime.a.size() == 0) {
- Prime.a.add(new BigInteger("" + 2));
- Prime.a.add(new BigInteger("" + 3));
- Prime.a.add(new BigInteger("" + 5));
- Prime.a.add(new BigInteger("" + 7));
- Prime.a.add(new BigInteger("" + 11));
- Prime.a.add(new BigInteger("" + 13));
- Prime.a.add(new BigInteger("" + 17));
- }
- Prime.nMax = Prime.a.lastElement();
- }
-
- /**
- * Test if a number is a prime.
- *
- * @param n
- * the integer to be tested for primality
- * @return true if prime, false if not
- */
- public boolean contains(final BigInteger n) {
- /*
- * not documented
- * return ( n.isProbablePrime() ) ;
- */
- switch (millerRabin(n)) {
- case -1:
- return false;
- case 1:
- return true;
- }
- growto(n);
- return Prime.a.contains(n);
- }
-
- /**
- * Test whether a number n is a strong pseudoprime to base a.
- *
- * @param n
- * the integer to be tested for primality
- * @param a
- * the base
- * @return true if the test is passed, so n may be a prime.
- * false if the test is not passed, so n is not a prime.
- * @since 2010-02-25
- */
- public boolean isSPP(final BigInteger n, final BigInteger a) {
- final BigInteger two = new BigInteger("" + 2);
-
- /*
- * numbers less than 2 are not prime
- */
- if (n.compareTo(two) == -1) {
- return false;
- } else if (n.compareTo(two) == 0) {
- return true;
- } else if (n.remainder(two).compareTo(BigInteger.ZERO) == 0) {
- return false;
- } else {
- /*
- * q= n- 1 = d *2^s with d odd
- */
- final BigInteger q = n.subtract(BigInteger.ONE);
- final int s = q.getLowestSetBit();
- final BigInteger d = q.shiftRight(s);
-
- /*
- * test whether a^d = 1 (mod n)
- */
- if (a.modPow(d, n).compareTo(BigInteger.ONE) == 0) {
- return true;
- }
-
- /*
- * test whether a^(d*2^r) = -1 (mod n), 0<=r= Prime.a.size()) {
- growto(Prime.nMax.add(new BigInteger("" + 5)));
- }
- return Prime.a.elementAt(i);
- }
-
- /**
- * return the count of primes <= n
- *
- * @param n
- * the upper limit of the scan
- * @return the ith prime. This is 2 if i=0, 3 if i=1 and so forth.
- */
- public BigInteger pi(final BigInteger n) {
- /*
- * If the current list is too small, increase in intervals
- * of 5 until the list has at least i elements.
- */
- growto(n);
- BigInteger r = new BigInteger("0");
- for (int i = 0; i < Prime.a.size(); i++) {
- if (Prime.a.elementAt(i).compareTo(n) <= 0) {
- r = r.add(BigInteger.ONE);
- }
- }
- return r;
- }
-
- /**
- * return the smallest prime larger than n
- *
- * @param n
- * lower limit of the search
- * @return the next larger prime.
- * @since 2008-10-16
- */
- public BigInteger nextprime(final BigInteger n) {
- /* if n <=1, return 2 */
- if (n.compareTo(BigInteger.ONE) <= 0) {
- return Prime.a.elementAt(0);
- }
-
- /*
- * If the currently largest element in the list is too small, increase
- * in intervals
- * of 5 until the list has at least i elements.
- */
- while (Prime.a.lastElement().compareTo(n) <= 0) {
- growto(Prime.nMax.add(new BigInteger("" + 5)));
- }
- for (int i = 0; i < Prime.a.size(); i++) {
- if (Prime.a.elementAt(i).compareTo(n) == 1) {
- return Prime.a.elementAt(i);
- }
- }
- return Prime.a.lastElement();
- }
-
- /**
- * return the largest prime smaller than n
- *
- * @param n
- * upper limit of the search
- * @return the next smaller prime.
- * @since 2008-10-17
- */
- public BigInteger prevprime(final BigInteger n) {
- /* if n <=2, return 0 */
- if (n.compareTo(BigInteger.ONE) <= 0) {
- return BigInteger.ZERO;
- }
-
- /*
- * If the currently largest element in the list is too small, increase
- * in intervals
- * of 5 until the list has at least i elements.
- */
- while (Prime.a.lastElement().compareTo(n) < 0) {
- growto(Prime.nMax.add(new BigInteger("" + 5)));
- }
-
- for (int i = 0; i < Prime.a.size(); i++) {
- if (Prime.a.elementAt(i).compareTo(n) >= 0) {
- return Prime.a.elementAt(i - 1);
- }
- }
- return Prime.a.lastElement();
- }
-
- /**
- * extend the list of known primes up to n
- *
- * @param n
- * the maximum integer known to be prime or not prime after the
- * call.
- */
- protected void growto(final BigInteger n) {
- while (Prime.nMax.compareTo(n) == -1) {
- Prime.nMax = Prime.nMax.add(BigInteger.ONE);
- boolean isp = true;
- for (int p = 0; p < Prime.a.size(); p++) {
- /*
- * Test the list of known primes only up to sqrt(n)
- */
- if (Prime.a.get(p).multiply(Prime.a.get(p)).compareTo(Prime.nMax) == 1) {
- break;
- }
-
- /*
- * The next case means that the p'th number in the list of known
- * primes divides
- * nMax and nMax cannot be a prime.
- */
- if (Prime.nMax.remainder(Prime.a.get(p)).compareTo(BigInteger.ZERO) == 0) {
- isp = false;
- break;
- }
- }
- if (isp) {
- Prime.a.add(Prime.nMax);
- }
- }
- }
-
- /**
- * Test program.
- * Usage: java -cp . org.nevec.rjm.Prime n
- * This takes a single argument (n) and prints prime(n), the previous and
- * next prime, and pi(n).
- *
- * @since 2006-08-14
- */
- public static void main(final String[] args) throws Exception {
- final Prime a = new Prime();
- final int n = new Integer(args[0]).intValue();
- if (n >= 1) {
- if (n >= 2) {
- System.out.println("prime(" + (n - 1) + ") = " + a.at(n - 1));
- }
- System.out.println("prime(" + n + ") = " + a.at(n));
- System.out.println("prime(" + (n + 1) + ") = " + a.at(n + 1));
- System.out.println("pi(" + n + ") = " + a.pi(new BigInteger("" + n)));
- }
- }
-} /* Prime */
diff --git a/core/src/main/java/org/nevec/rjm/RatPoly.java b/core/src/main/java/org/nevec/rjm/RatPoly.java
deleted file mode 100644
index 6bb27552..00000000
--- a/core/src/main/java/org/nevec/rjm/RatPoly.java
+++ /dev/null
@@ -1,1045 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.math.RoundingMode;
-import java.util.Random;
-import java.util.Scanner;
-import java.util.Vector;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * A one-parameter polynomial with rational coefficients.
- * Alternatively to be interpreted as a sequence which has the polynomial as an
- * (approximate)
- * generating function.
- *
- * @since 2006-06-25
- * @author Richard J. Mathar
- */
-class RatPoly {
- /**
- * The list of all coefficients, ascending exponents. Starting with a0, then
- * a1, representing
- * a value a0+a1*x+a2*x^2+a3*x^3+...
- */
- protected Vector a;
-
- /**
- * Default ctor.
- * Initializes the zero-valued polynomial x=0.
- */
- public RatPoly() {
- a = new Vector<>();
- } /* ctor */
-
- /**
- * Constructor with an explicit list of coefficients.
- *
- * @param L
- * the coefficients a0, a1, a2, a3,.., A deep copy of the these
- * is created.
- */
- public RatPoly(final Vector L) {
- a = new Vector<>();
- for (int i = 0; i < L.size(); i++) {
- a.add(L.elementAt(i).clone());
- }
- simplify();
- } /* ctor */
-
- /**
- * Constructor with a comma-separated list as the list of coefficients.
- *
- * @param L
- * the string of the form a0,a1,a2,a3 with the coefficients
- */
- public RatPoly(final String L) throws NumberFormatException {
- a = new Vector<>();
- final Scanner sc = new Scanner(L);
- sc.useDelimiter(",");
- while (sc.hasNext()) {
- final String tok = sc.next();
- a.add(new Rational(tok));
- }
- simplify();
- sc.close();
- } /* ctor */
-
- /**
- * Constructor from a hypergeometric series.
- *
- * @param A
- * the list of values in the numerator of AFB
- * @param B
- * the list of values in the denominator of AFB
- * @param nmax
- * the order of the truncated polynomial representation
- * @throws Error
- * @since 2008-11-13
- */
- public RatPoly(final Vector A, final Vector B, final int nmax) throws Error {
- /*
- * To allow common initialization with the signature below,
- * the main body is assembled in a separate function.
- */
- init(A, B, nmax);
- }
-
- /**
- * Constructor from a hypergeometric series.
- *
- * @param A
- * the list of values in the numerator of AFB.
- * At least one of these values must be a negative integer, which
- * implicitly determines
- * the order of the new polynomial.
- * @param B
- * the list of values in the denominator of AFB
- * @throws Error
- * @since 2009-08-05
- */
- public RatPoly(final Vector A, final Vector B) throws Error {
- BigInteger Nmax = BigInteger.ONE.negate();
- for (int j = 0; j < A.size(); j++) {
- if (A.elementAt(j).compareTo(BigInteger.ZERO) <= 0) {
- if (Nmax.compareTo(BigInteger.ZERO) < 0) {
- Nmax = A.elementAt(j).negate();
- } else {
- Nmax = Nmax.min(A.elementAt(j).negate());
- }
- }
- }
- if (Nmax.compareTo(BigInteger.ZERO) < 0) {
- throw new ArithmeticException("Infinite Number of Terms in Series " + Nmax.toString());
- }
-
- final int nmax = Nmax.intValue() - 1;
- init(A, B, nmax);
- } /* ctor */
-
- /**
- * Constructor from a hypergeometric series.
- *
- * @param A
- * the list of values in the numerator of AFB
- * @param B
- * the list of values in the denominator of AFB
- * @param nmax
- * the order of the truncated polynomial representation
- * @throws Error
- * @since 2008-11-13
- */
- protected void init(final Vector A, final Vector B, final int nmax) throws Error {
- a = new Vector<>();
- final Factorial f = new Factorial();
- for (int n = 0; n <= nmax; n++) {
- Rational c = new Rational(1, 1);
- for (int j = 0; j < A.size(); j++) {
- final Rational aEl = new Rational(A.elementAt(j));
- c = c.multiply(aEl.Pochhammer(n));
- }
- for (int j = 0; j < B.size(); j++) {
- final Rational bEl = new Rational(B.elementAt(j));
- c = c.divide(bEl.Pochhammer(n));
- }
- c = c.divide(f.at(n));
- a.add(c);
- }
- simplify();
- } /* init */
-
- /**
- * Create a copy of this.
- *
- * @since 2008-11-07
- */
- @Override
- @SuppressWarnings("unchecked")
- public RatPoly clone() {
- final RatPoly clo = new RatPoly();
- clo.a = (Vector) a.clone();
- return clo;
- } /* clone */
-
- /**
- * Retrieve a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * @return the polynomial coefficient in front of x^n.
- */
- public Rational at(final int n) {
- if (n < a.size()) {
- return a.elementAt(n);
- } else {
- return new Rational(0, 1);
- }
- } /* at */
-
- /**
- * Horner scheme to find the function value at the argument x
- *
- * @param x
- * The argument of the polynomial
- * @param mc
- * The context determining the precision of the value returned.
- * @since 2008-10-26
- */
- public BigComplex valueOf(final BigComplex x, final MathContext mc) {
- /* result is initialized to zero */
- BigComplex f = new BigComplex();
- for (int i = degree(); i >= 0; i--) {
- f = f.multiply(x, mc).add(a.elementAt(i).BigDecimalValue(mc));
- }
- return f;
- } /* valueOf */
-
- /**
- * Horner scheme to find the function value at the argument x
- *
- * @param x
- * The argument of the polynomial
- * @since 2008-11-13
- */
- public Rational valueOf(final Rational x) {
- /* result is initialized to zero */
- Rational f = new Rational(0, 1);
- for (int i = degree(); i >= 0; i--) {
- f = f.multiply(x).add(a.elementAt(i));
- }
- return f;
- } /* valueOf */
-
- /**
- * Horner scheme to find the function value at the argument x
- *
- * @param x
- * The argument of the polynomial
- * @since 2008-11-13
- */
- public Rational valueOf(final int x) {
- return valueOf(new Rational(x, 1));
- } /* valueOf */
-
- /**
- * Horner scheme to evaluate the function at the argument x
- *
- * @param x
- * The argument of the polynomial
- * @since 2010-08-27
- */
- public Rational valueOf(final BigInteger x) {
- return valueOf(new Rational(x));
- } /* valueOf */
-
- /*
- * Set a polynomial coefficient.
- *
- * @param n the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this coefficient,
- * the intermediate coefficients are implicitly set to zero.
- *
- * @param value the new value of the coefficient.
- */
- public void set(final int n, final Rational value) {
- if (n < a.size()) {
- a.set(n, value);
- } else {
- /*
- * fill intermediate powers with coefficients of zero
- */
- while (a.size() < n) {
- a.add(new Rational(0, 1));
- }
- a.add(value);
- }
- } /* set */
-
- /**
- * Set a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this
- * coefficient,
- * the intermediate coefficients are implicitly set to zero.
- * @param value
- * the new value of the coefficient.
- */
- public void set(final int n, final BigInteger value) {
- final Rational val2 = new Rational(value, BigInteger.ONE);
- set(n, val2);
- } /* set */
-
- /**
- * Set a polynomial coefficient.
- *
- * @param n
- * the zero-based index of the coefficient. n=0 for the constant
- * term.
- * If the polynomial has not yet the degree to need this
- * coefficient,
- * the intermediate coefficients are implicitly set to zero.
- * @param value
- * the new value of the coefficient.
- */
- public void set(final int n, final int value) {
- final Rational val2 = new Rational(value, 1);
- set(n, val2);
- } /* set */
-
- /*
- * Set to the taylor series of exp(x) up to degree nmax.
- *
- * @param nmax the maximum polynomial degree
- */
- public void setExp(final int nmax) {
- a.clear();
- final Factorial factorial = new Factorial();
- for (int n = 0; n <= nmax; n++) {
- set(n, new Rational(BigInteger.ONE, factorial.at(n)));
- }
- } /* setExp */
-
- /**
- * Set to the taylor series representing 0+x.
- */
- public void setx() {
- a.clear();
- /* coefficient 0/1=0 */
- a.add(new Rational(0, 1));
- /* coefficient 1/1=1 */
- a.add(new Rational(1, 1));
- } /* setx */
-
- /**
- * Count of coefficients. One more than the degree of the polynomial.
- *
- * @return the number of polynomial coefficients.
- */
- public int size() {
- return a.size();
- } /* size */
-
- /**
- * Polynomial degree.
- *
- * @return the polynomial degree.
- */
- public int degree() {
- return a.size() - 1;
- } /* degree */
-
- /**
- * Lower Polynomial degree.
- *
- * @return The smallest exponent n such that [x^n] of the polynomial is
- * nonzero.
- * If the polynmial is identical zero, the result is (still) 0.
- * @since 2010-08-27
- */
- public int ldegree() {
- for (int n = 0; n < a.size(); n++) {
- if (a.elementAt(n).compareTo(BigInteger.ZERO) != 0) {
- return n;
- }
- }
- return 0;
- } /* ldegree */
-
- /**
- * Multiply by a constant factor.
- *
- * @param val
- * the factor
- * @return the product of this with the factor.
- * All coefficients of this have been multiplied individually by the
- * factor.
- */
- public RatPoly multiply(final Rational val) {
- final RatPoly resul = new RatPoly();
- if (val.compareTo(BigInteger.ZERO) != 0) {
- for (int n = 0; n < a.size(); n++) {
- resul.set(n, a.elementAt(n).multiply(val));
- }
- }
- return resul;
- } /* multiply */
-
- /**
- * Multiply by a constant factor.
- *
- * @param val
- * the factor
- * @return the product of this with the factor.
- * All coefficients of this have been multiplied individually by the
- * factor.
- * @since 2010-08-27
- */
- public RatPoly multiply(final BigInteger val) {
- final RatPoly resul = new RatPoly();
- if (val.compareTo(BigInteger.ZERO) != 0) {
- for (int n = 0; n < a.size(); n++) {
- resul.set(n, a.elementAt(n).multiply(val));
- }
- }
- return resul;
- } /* multiply */
-
- /**
- * Multiply by another polynomial
- *
- * @param val
- * the other polynomial
- * @return the product of this with the other polynomial
- */
- public RatPoly multiply(final RatPoly val) {
- final RatPoly resul = new RatPoly();
- /*
- * the degree of the result is the sum of the two degrees.
- */
- final int nmax = degree() + val.degree();
- for (int n = 0; n <= nmax; n++) {
- Rational coef = new Rational(0, 1);
- for (int nleft = 0; nleft <= n; nleft++) {
- coef = coef.add(at(nleft).multiply(val.at(n - nleft)));
- }
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* multiply */
-
- /**
- * Raise to a positive power.
- *
- * @param n
- * The non-negative exponent of the power
- * @return The n-th power of this.
- */
- public RatPoly pow(final int n) throws ArithmeticException {
- RatPoly resul = new RatPoly("1");
- if (n < 0) {
- throw new ArithmeticException("negative polynomial power " + n);
- } else {
- /*
- * this ought probably be done with some binary representation
- * of the power and a smaller number of multiplications.
- */
- for (int i = 1; i <= n; i++) {
- resul = resul.multiply(this);
- }
- resul.simplify();
- return resul;
- }
- } /* pow */
-
- /**
- * Raise to a rational power.
- * The result is the taylor expansion of this, truncated at the first
- * term that remains undetermined based on the current number of
- * coefficients.
- *
- * @param r
- * the exponent of the power
- * @return This^r .
- * @throws Error
- * @since 2009-05-18
- */
- public RatPoly pow(final Rational r) throws ArithmeticException, Error {
- /*
- * split (a0+a1*x+a2*x^2+...)^r = a0^r*(1+a1/a0*r+a2/a0*r^2+..)^r
- */
- Rational f = at(0);
- f = f.pow(r);
-
- /*
- * scale the polynomial by division through the expansion coefficient of
- * the absolute term
- */
- final RatPoly red = divide(a.elementAt(0));
-
- /*
- * and remove the leading term (now equal to 1)
- */
- red.set(0, 0);
-
- /*
- * Binomial expansion of the rest. sum_{l=0..infinity}
- * binomial(r,l)*red^l
- */
- RatPoly resul = new RatPoly("1");
-
- final int d = degree();
- for (int l = 1; l <= d; l++) {
- final Rational b = Rational.binomial(r, l);
- resul = resul.add(red.pow(l).multiply(b));
- }
- return resul.multiply(f);
- } /* pow */
-
- /**
- * Add another polynomial
- *
- * @param val
- * The other polynomial
- * @return The sum of this and the other polynomial
- * @since 2008-10-25
- */
- public RatPoly add(final RatPoly val) {
- final RatPoly resul = new RatPoly();
- /*
- * the degree of the result is the larger of the two degrees (before
- * simplify() at least).
- */
- final int nmax = degree() > val.degree() ? degree() : val.degree();
- for (int n = 0; n <= nmax; n++) {
- final Rational coef = at(n).add(val.at(n));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* add */
-
- /**
- * Subtract another polynomial
- *
- * @param val
- * The other polynomial
- * @return The difference between this and the other polynomial
- * @since 2008-10-25
- */
- public RatPoly subtract(final RatPoly val) {
- final RatPoly resul = new RatPoly();
- /*
- * the degree of the result is the larger of the two degrees (before
- * simplify() at least).
- */
- final int nmax = degree() > val.degree() ? degree() : val.degree();
- for (int n = 0; n <= nmax; n++) {
- final Rational coef = at(n).subtract(val.at(n));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* subtract */
-
- /**
- * Divide by a constant.
- *
- * @param val
- * the constant through which the coefficients will be divided.
- * @return the Taylor expansion of this/val .
- * @throws Error
- * @since 2009-05-18
- */
- public RatPoly divide(final Rational val) throws Error {
- if (val.compareTo(Rational.ZERO) != 0) {
- final RatPoly resul = new RatPoly();
- for (int n = 0; n < a.size(); n++) {
- resul.set(n, a.elementAt(n).divide(val));
- }
- return resul;
- } else {
- throw new ArithmeticException("Cannot divide " + toPString() + " through zero.");
- }
- } /* divide */
-
- /**
- * Divide by another polynomial.
- *
- * @param val
- * the other polynomial
- * @param nmax
- * the maximum degree of the Taylor expansion of the result.
- * @return the Taylor expansion of this/val up to degree nmax.
- * @throws Error
- */
- public RatPoly divide(final RatPoly val, final int nmax) throws Error {
- final RatPoly num = this;
- final RatPoly denom = val;
-
- /*
- * divide by a common smallest power/degree
- */
- while (num.at(0).compareTo(BigInteger.ZERO) == 0 && denom.at(0).compareTo(BigInteger.ZERO) == 0) {
- num.a.remove(0);
- denom.a.remove(0);
- if (num.size() <= 1 || denom.size() <= 1) {
- break;
- }
- }
-
- final RatPoly resul = new RatPoly();
- /*
- * todo: If the polynomial division is exact, we could leave
- * the loop earlier, indeed
- */
- for (int n = 0; n <= nmax; n++) {
- Rational coef = num.at(n);
- for (int nres = 0; nres < n; nres++) {
- coef = coef.subtract(resul.at(nres).multiply(denom.at(n - nres)));
- }
- coef = coef.divide(denom.at(0));
- resul.set(n, coef);
- }
- resul.simplify();
- return resul;
- } /* divide */
-
- /**
- * Divide by another polynomial.
- *
- * @param val
- * the other polynomial
- * @return A vector with [0] containg the polynomial of degree which is the
- * difference of thisdegree and the degree of val. [1] the remainder
- * polynomial.
- * This = returnvalue[0] + returnvalue[1]/val .
- * @throws Error
- * @since 2012-03-01
- */
- public RatPoly[] divideAndRemainder(final RatPoly val) throws Error {
- final RatPoly[] ret = new RatPoly[2];
- /*
- * remove any high-order zeros
- */
- final RatPoly valSimpl = val.clone();
- valSimpl.simplify();
- final RatPoly thisSimpl = clone();
- thisSimpl.simplify();
-
- /*
- * catch the case with val equal to zero
- */
- if (valSimpl.degree() == 0 && valSimpl.a.firstElement().compareTo(Rational.ZERO) == 0) {
- throw new ArithmeticException("Division through zero polynomial");
- }
- /*
- * degree of this smaller than degree of val: remainder is this
- */
- if (thisSimpl.degree() < valSimpl.degree()) {
- /*
- * leading polynomial equals zero
- */
- ret[0] = new RatPoly();
- ret[1] = thisSimpl;
- } else {
- /*
- * long division. Highest degree by dividing the highest degree
- * of this thru val.
- */
- ret[0] = new RatPoly();
- ret[0].set(thisSimpl.degree() - valSimpl.degree(), thisSimpl.a.lastElement().divide(valSimpl.a.lastElement()));
-
- /*
- * recurrences: build this - val*(1-termresult) and feed this
- * into another round of division. Have intermediate
- * ret[0]+ret[1]/val.
- */
- ret[1] = thisSimpl.subtract(ret[0].multiply(valSimpl));
-
- /*
- * any remainder left ?
- */
- if (ret[1].degree() < valSimpl.degree()) {
- ;
- } else {
- final RatPoly rem[] = ret[1].divideAndRemainder(val);
- ret[0] = ret[0].add(rem[0]);
- ret[1] = rem[1];
- }
- }
- return ret;
- } /* divideAndRemainder */
-
- /**
- * Print as a comma-separated list of coefficients.
- *
- * @return The representation a0,a1,a2,a3,...
- * This is a sort of opposite of the ctor that takes a string as an
- * argument.
- * @since 2008-10-25
- */
- @Override
- public String toString() {
- String str = new String();
- for (int n = 0; n < a.size(); n++) {
- if (n == 0) {
- str += a.elementAt(n).toString();
- } else {
- str += "," + a.elementAt(n).toString();
- }
- }
- /*
- * print at least a sole zero
- */
- if (str.length() == 0) {
- str = "0";
- }
- return str;
- } /* toString */
-
- /**
- * Print as a polyomial in x.
- *
- * @return To representation a0+a1*x+a2*x^2+...
- * This does not print the terms with coefficients equal to zero.
- * @since 2008-10-26
- */
- public String toPString() {
- String str = new String();
- for (int n = 0; n < a.size(); n++) {
- final BigInteger num = a.elementAt(n).a;
- if (num.compareTo(BigInteger.ZERO) != 0) {
- str += " ";
- if (num.compareTo(BigInteger.ZERO) > 0) {
- str += "+";
- }
- str += a.elementAt(n).toString();
- if (n > 0) {
- str += "*x";
- if (n > 1) {
- str += "^" + n;
- }
- }
- }
- }
- /*
- * print at least a sole zero
- */
- if (str.length() == 0) {
- str = "0";
- }
- return str;
- } /* toPString */
-
- /**
- * Simplify the representation.
- * Trailing values with zero coefficients (at high powers) are deleted.
- * This modifies the polynomial on the stop (does not return another
- * instance)
- */
- private void simplify() {
- int n = a.size() - 1;
- if (n >= 0) {
- while (a.elementAt(n).compareTo(BigInteger.ZERO) == 0) {
- a.remove(n);
- if (--n < 0) {
- break;
- }
- }
- }
- } /* simplify */
-
- /**
- * First derivative.
- *
- * @return The first derivative with respect to the indeterminate variable.
- * @since 2008-10-26
- */
- public RatPoly derive() {
- if (a.size() <= 1) {
- /*
- * derivative of the constant is just zero
- */
- return new RatPoly();
- } else {
- final RatPoly d = new RatPoly();
- for (int i = 1; i <= degree(); i++) {
- final Rational c = a.elementAt(i).multiply(i);
- d.set(i - 1, c);
- }
- return d;
- }
- } /* derive */
-
- /**
- * Scale coefficients such that the coefficient in front of the maximum
- * degree is unity.
- *
- * @return The scaled polynomial
- * @throws Error
- * @since 2008-10-26
- */
- public RatPoly monic() throws Error {
- final RatPoly m = new RatPoly();
- final int d = degree();
- for (int i = 0; i <= d; i++) {
- final Rational c = a.elementAt(i).divide(a.elementAt(d));
- m.set(i, c);
- }
- return m;
- } /* monic */
-
- /**
- * Mobius transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the Mobius transform of the
- * original sequence.
- * @since 2008-12-02
- */
- public RatPoly mobiusT(final int maxdeg) {
- /*
- * Start with the polynomial 0
- */
- final RatPoly r = new RatPoly();
- for (int i = 1; i <= maxdeg; i++) {
- Rational c = new Rational();
- for (int d = 1; d <= i && d < a.size(); d++) {
- if (i % d == 0) {
- final Ifactor m = new Ifactor(i / d);
- c = c.add(a.elementAt(d).multiply(m.moebius()));
- }
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* mobiusT */
-
- /**
- * Inverse Mobius transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the inverse Mobius transform of
- * the original sequence.
- * @since 2008-12-02
- */
- public RatPoly mobiusTInv(final int maxdeg) {
- /*
- * Start with the polynomial 0
- */
- final RatPoly r = new RatPoly();
- for (int i = 1; i <= maxdeg; i++) {
- Rational c = new Rational();
- for (int d = 1; d <= i && d < a.size(); d++) {
- if (i % d == 0) {
- c = c.add(a.elementAt(d));
- }
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* mobiusTInv */
-
- /**
- * Binomial transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the binomial transform of the
- * original sequence.
- * @since 2008-10-26
- */
- public RatPoly binomialT(final int maxdeg) {
- final RatPoly r = new RatPoly();
- for (int i = 0; i <= maxdeg; i++) {
- Rational c = new Rational(0, 1);
- for (int j = 0; j <= i && j < a.size(); j++) {
- c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* binomialT */
-
- /**
- * Inverse Binomial transform.
- *
- * @param maxdeg
- * the maximum polynomial degree of the result
- * @return the sequence of coefficients is the inverse binomial transform of
- * the original sequence.
- * @since 2008-10-26
- */
- public RatPoly binomialTInv(final int maxdeg) {
- final RatPoly r = new RatPoly();
- for (int i = 0; i <= maxdeg; i++) {
- Rational c = new Rational(0, 1);
- for (int j = 0; j <= i && j < a.size(); j++) {
- if ((j + i) % 2 != 0) {
- c = c.subtract(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- } else {
- c = c.add(a.elementAt(j).multiply(BigIntegerMath.binomial(i, j)));
- }
- }
- r.set(i, c);
- }
- r.simplify();
- return r;
- } /* binomialTInv */
-
- /**
- * Truncate polynomial degree.
- *
- * @param newdeg
- * The maximum degree of the result.
- * @return The polynomial with all coefficients beyond deg set to zero.
- * If newdeg =3, for example the polynomial returned has at most
- * degree 3.
- * If newdeg is larger than the degree of this, zeros (at the higher
- * orders of x)
- * are appended. That polynomial would have formal degree larger
- * than this.
- * @since 2008-10-26
- */
- public RatPoly trunc(final int newdeg) {
- final RatPoly t = new RatPoly();
- for (int i = 0; i <= newdeg; i++) {
- t.set(i, at(i));
- }
- t.simplify();
- return t;
- } /* trunc */
-
- /**
- * Generate the roots of the polynomial in floating point arithmetic.
- *
- * @see Durand
- * Kerner method
- * @param the
- * number of floating point digits
- * @throws Error
- * @since 2008-10-26
- */
- public Vector roots(final int digits) throws Error {
- final RatPoly mon = monic();
-
- final Random rand = new Random();
- final MathContext mc = new MathContext(digits + 3, RoundingMode.DOWN);
-
- Vector res = new Vector<>();
-
- final int d = mon.degree();
- double randRad = 0.;
- for (int i = 0; i <= d; i++) {
- /* scale coefficient at maximum degree */
- final double absi = Math.abs(mon.at(i).doubleValue());
- if (absi > randRad) {
- randRad = absi;
- }
- }
- randRad += 1.0;
-
- /*
- * initial values randomly in radius 1+randRad
- */
- for (int i = 0; i < d; i++) {
- final double rad = randRad * rand.nextDouble();
- final double phi = 2.0 * 3.14159 * rand.nextDouble();
- res.add(i, new BigComplex(rad * Math.cos(phi), rad * Math.sin(phi)));
- }
-
- /*
- * iterate until convr indicates that all values changed by less than
- * the digits
- * precision indicates.
- */
- boolean convr = false;
- for (; !convr;)// ORIGINAL LINE: for(int itr =0 ; ! convr ; itr++)
- {
- convr = true;
- final Vector resPlus = new Vector<>();
- for (int v = 0; v < d; v++) {
- /*
- * evaluate f(x)/(x-root1)/(x-root2)/... (x-rootdegr), Newton
- * method
- */
- BigComplex thisx = res.elementAt(v);
- BigComplex nv = mon.valueOf(thisx, mc);
- for (int j = 0; j < d; j++) {
- if (j != v) {
- nv = nv.divide(thisx.subtract(res.elementAt(j)), mc);
- }
- }
-
- /* is this value converged ? */
- if (nv.abs(mc).doubleValue() > thisx.abs(mc).doubleValue() * Math.pow(10.0, -digits)) {
- convr = false;
- }
-
- thisx = thisx.subtract(nv);
-
- /* If unstable, start over */
- if (thisx.abs(MathContext.DECIMAL32).doubleValue() > randRad) {
- return roots(digits);
- }
-
- resPlus.add(thisx);
- }
- res = resPlus;
-
- }
- return res;
- } /* roots */
-
- /**
- * Generate the integer roots of the polynomial.
- *
- * @return The vector of integer roots, with multiplicity.
- * The shows alternatingly first a root then its multiplicty, then
- * another root and multiplicty etc.
- * @since 2008-10-26
- */
- public Vector iroots() {
- /* The vector of the roots */
- final Vector res = new Vector<>();
-
- final int lowd = ldegree();
- if (lowd == 0 && a.elementAt(0).compareTo(BigInteger.ZERO) == 0) {
- /*
- * Case of polynomial identical to zero:
- * reported as a simple root of value 0.
- */
- res.add(BigInteger.ZERO);
- res.add(BigInteger.ONE);
- return res;
- }
-
- /*
- * multiply all coefs with the lcm() to get an integer polynomial
- * start with denominator of first non-zero coefficient.
- */
- BigInteger lcmDeno = a.elementAt(lowd).b;
- for (int i = lowd + 1; i < degree(); i++) {
- lcmDeno = BigIntegerMath.lcm(lcmDeno, a.elementAt(i).b);
- }
-
- /*
- * and eventually get the integer polynomial by ignoring the
- * denominators
- */
- final Vector ipo = new Vector<>();
- for (int i = 0; i < a.size(); i++) {
- final BigInteger d = a.elementAt(i).a.multiply(lcmDeno).divide(a.elementAt(i).b);
- ipo.add(d);
- }
-
- final BigIntegerPoly p = new BigIntegerPoly(ipo);
- /*
- * collect the integer roots (multiple roots only once). Since we
- * removed the zero already above, cand does not contain zeros.
- */
- final Vector cand = p.iroots();
- for (int i = 0; i < cand.size(); i++) {
- final BigInteger r = cand.elementAt(i);
- final int deg = p.rootDeg(r);
- res.add(r);
- res.add(new BigInteger("" + deg));
- }
-
- return res;
- } /* iroots */
-
-} /* RatPoly */
diff --git a/core/src/main/java/org/nevec/rjm/Rational.java b/core/src/main/java/org/nevec/rjm/Rational.java
deleted file mode 100644
index f11574a8..00000000
--- a/core/src/main/java/org/nevec/rjm/Rational.java
+++ /dev/null
@@ -1,900 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.MathContext;
-import java.math.RoundingMode;
-
-import it.cavallium.warppi.util.Error;
-import it.cavallium.warppi.util.Errors;
-
-/**
- * Fractions (rational numbers). They are divisions of two BigInteger numbers,
- * reduced to coprime numerator and denominator.
- *
- * @since 2006-06-25
- * @author Richard J. Mathar
- */
-public class Rational implements Cloneable, Comparable {
- /**
- * numerator
- */
- BigInteger a;
-
- /**
- * denominator, always larger than zero.
- */
- BigInteger b;
-
- /**
- * The maximum and minimum value of a standard Java integer, 2^31.
- *
- * @since 2009-05-18
- */
- static public BigInteger MAX_INT = new BigInteger("2147483647");
- static public BigInteger MIN_INT = new BigInteger("-2147483648");
-
- /**
- * The constant 1.
- */
- public static Rational ONE = new Rational(1, 1);
- /**
- * The constant 0.
- */
- static public Rational ZERO = new Rational();
-
- /**
- * The constant 1/2
- *
- * @since 2010-05-25
- */
- static public Rational HALF = new Rational(1, 2);
-
- /**
- * Default ctor, which represents the zero.
- *
- * @since 2007-11-17
- */
- public Rational() {
- a = BigInteger.ZERO;
- b = BigInteger.ONE;
- }
-
- /**
- * ctor from a numerator and denominator.
- *
- * @param a
- * the numerator.
- * @param b
- * the denominator.
- */
- public Rational(final BigInteger a, final BigInteger b) {
- this.a = a;
- this.b = b;
- normalize();
- }
-
- /**
- * ctor from a numerator.
- *
- * @param a
- * the BigInteger.
- */
- public Rational(final BigInteger a) {
- this.a = a;
- b = new BigInteger("1");
- }
-
- /**
- * ctor from a numerator and denominator.
- *
- * @param a
- * the numerator.
- * @param b
- * the denominator.
- */
- public Rational(final int a, final int b) {
- this(new BigInteger("" + a), new BigInteger("" + b));
- }
-
- /**
- * ctor from an integer.
- *
- * @param n
- * the integer to be represented by the new instance.
- * @since 2010-07-18
- */
- public Rational(final int n) {
- this(n, 1);
- }
-
- /**
- * ctor from a string representation.
- *
- * @param str
- * the string. This either has a slash in it, separating two
- * integers, or, if there is no slash, is representing the
- * numerator with implicit denominator equal to 1. Warning: this
- * does not yet test for a denominator equal to zero
- */
- public Rational(final String str) {
- this(str, 10);
- }
-
- /**
- * ctor from a string representation in a specified base.
- *
- * @param str
- * the string. This either has a slash in it, separating two
- * integers, or, if there is no slash, is just representing the
- * numerator.
- * @param radix
- * the number base for numerator and denominator Warning: this
- * does not yet test for a denominator equal to zero
- */
- public Rational(final String str, final int radix) {
- final int hasslah = str.indexOf("/");
- if (hasslah == -1) {
- a = new BigInteger(str, radix);
- b = new BigInteger("1", radix);
- /* no normalization necessary here */
- } else {
- /*
- * create numerator and denominator separately
- */
- a = new BigInteger(str.substring(0, hasslah), radix);
- b = new BigInteger(str.substring(hasslah + 1), radix);
- normalize();
- }
- }
-
- /**
- * Create a copy.
- *
- * @since 2008-11-07
- */
- @Override
- public Rational clone() {
- /*
- * protected access means this does not work return new
- * Rational(a.clone(), b.clone()) ;
- */
- final BigInteger aclon = new BigInteger("" + a);
- final BigInteger bclon = new BigInteger("" + b);
- return new Rational(aclon, bclon);
- } /* Rational.clone */
-
- /**
- * Multiply by another fraction.
- *
- * @param val
- * a second rational number.
- * @return the product of this with the val.
- */
- public Rational multiply(final Rational val) {
- final BigInteger num = a.multiply(val.a);
- final BigInteger deno = b.multiply(val.b);
- /*
- * Normalization to an coprime format will be done inside the ctor() and
- * is not duplicated here.
- */
- return new Rational(num, deno);
- } /* Rational.multiply */
-
- /**
- * Multiply by a BigInteger.
- *
- * @param val
- * a second number.
- * @return the product of this with the value.
- */
- public Rational multiply(final BigInteger val) {
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return multiply(val2);
- } /* Rational.multiply */
-
- /**
- * Multiply by an integer.
- *
- * @param val
- * a second number.
- * @return the product of this with the value.
- */
- public Rational multiply(final int val) {
- final BigInteger tmp = new BigInteger("" + val);
- return multiply(tmp);
- } /* Rational.multiply */
-
- /**
- * Power to an integer.
- *
- * @param exponent
- * the exponent.
- * @return this value raised to the power given by the exponent. If the
- * exponent is 0, the value 1 is returned.
- */
- public Rational pow(final int exponent) {
- if (exponent == 0) {
- return new Rational(1, 1);
- }
-
- final BigInteger num = a.pow(Math.abs(exponent));
- final BigInteger deno = b.pow(Math.abs(exponent));
- if (exponent > 0) {
- return new Rational(num, deno);
- } else {
- return new Rational(deno, num);
- }
- } /* Rational.pow */
-
- /**
- * Power to an integer.
- *
- * @param exponent
- * the exponent.
- * @return this value raised to the power given by the exponent. If the
- * exponent is 0, the value 1 is returned.
- * @throws Error
- * @since 2009-05-18
- */
- public Rational pow(final BigInteger exponent) throws Error {
- /* test for overflow */
- if (exponent.compareTo(Rational.MAX_INT) == 1) {
- throw new Error(Errors.NUMBER_TOO_LARGE);
- }
- if (exponent.compareTo(Rational.MIN_INT) == -1) {
- throw new Error(Errors.NUMBER_TOO_SMALL);
- }
-
- /* promote to the simpler interface above */
- return pow(exponent.intValue());
- } /* Rational.pow */
-
- /**
- * r-th root.
- *
- * @param r
- * the inverse of the exponent. 2 for the square root, 3 for the
- * third root etc
- * @return this value raised to the inverse power given by the root
- * argument, this^(1/r).
- * @throws Error
- * @since 2009-05-18
- */
- public Rational root(final BigInteger r) throws Error {
- /* test for overflow */
- if (r.compareTo(Rational.MAX_INT) == 1) {
- throw new Error(Errors.NUMBER_TOO_LARGE);
- }
- if (r.compareTo(Rational.MIN_INT) == -1) {
- throw new Error(Errors.NUMBER_TOO_SMALL);
- }
-
- final int rthroot = r.intValue();
- /* cannot pull root of a negative value with even-valued root */
- if (compareTo(Rational.ZERO) == -1 && rthroot % 2 == 0) {
- throw new Error(Errors.NEGATIVE_PARAMETER);
- }
-
- /*
- * extract a sign such that we calculate |n|^(1/r), still r carrying any
- * sign
- */
- final boolean flipsign = compareTo(Rational.ZERO) == -1 && rthroot % 2 != 0 ? true : false;
-
- /*
- * delegate the main work to ifactor#root()
- */
- final Ifactor num = new Ifactor(a.abs());
- final Ifactor deno = new Ifactor(b);
- final Rational resul = num.root(rthroot).divide(deno.root(rthroot));
- if (flipsign) {
- return resul.negate();
- } else {
- return resul;
- }
- } /* Rational.root */
-
- /**
- * Raise to a rational power.
- *
- * @param exponent
- * The exponent.
- * @return This value raised to the power given by the exponent. If the
- * exponent is 0, the value 1 is returned.
- * @throws Error
- * @since 2009-05-18
- */
- public Rational pow(final Rational exponent) throws Error {
- if (exponent.a.compareTo(BigInteger.ZERO) == 0) {
- return new Rational(1, 1);
- }
-
- /*
- * calculate (a/b)^(exponent.a/exponent.b) as
- * ((a/b)^exponent.a)^(1/exponent.b) = tmp^(1/exponent.b)
- */
- final Rational tmp = pow(exponent.a);
- return tmp.root(exponent.b);
- } /* Rational.pow */
-
- /**
- * Divide by another fraction.
- *
- * @param val
- * A second rational number.
- * @return The value of this/val
- * @throws Error
- */
- public Rational divide(final Rational val) throws Error {
- if (val.compareTo(Rational.ZERO) == 0) {
- throw new Error(Errors.DIVISION_BY_ZERO);
- }
- final BigInteger num = a.multiply(val.b);
- final BigInteger deno = b.multiply(val.a);
- /*
- * Reduction to a coprime format is done inside the ctor, and not
- * repeated here.
- */
- return new Rational(num, deno);
- } /* Rational.divide */
-
- /**
- * Divide by an integer.
- *
- * @param val
- * a second number.
- * @return the value of this/val
- * @throws Error
- */
- public Rational divide(final BigInteger val) throws Error {
- if (val.compareTo(BigInteger.ZERO) == 0) {
- throw new Error(Errors.DIVISION_BY_ZERO);
- }
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return divide(val2);
- } /* Rational.divide */
-
- /**
- * Divide by an integer.
- *
- * @param val
- * A second number.
- * @return The value of this/val
- * @throws Error
- */
- public Rational divide(final int val) throws Error {
- if (val == 0) {
- throw new Error(Errors.DIVISION_BY_ZERO);
- }
- final Rational val2 = new Rational(val, 1);
- return divide(val2);
- } /* Rational.divide */
-
- /**
- * Add another fraction.
- *
- * @param val
- * The number to be added
- * @return this+val.
- */
- public Rational add(final Rational val) {
- final BigInteger num = a.multiply(val.b).add(b.multiply(val.a));
- final BigInteger deno = b.multiply(val.b);
- return new Rational(num, deno);
- } /* Rational.add */
-
- /**
- * Add another integer.
- *
- * @param val
- * The number to be added
- * @return this+val.
- */
- public Rational add(final BigInteger val) {
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return add(val2);
- } /* Rational.add */
-
- /**
- * Add another integer.
- *
- * @param val
- * The number to be added
- * @return this+val.
- * @since May 26 2010
- */
- public Rational add(final int val) {
- final BigInteger val2 = a.add(b.multiply(new BigInteger("" + val)));
- return new Rational(val2, b);
- } /* Rational.add */
-
- /**
- * Compute the negative.
- *
- * @return -this.
- */
- public Rational negate() {
- return new Rational(a.negate(), b);
- } /* Rational.negate */
-
- /**
- * Subtract another fraction.
- *
- * @param val
- * the number to be subtracted from this
- * @return this - val.
- */
- public Rational subtract(final Rational val) {
- final Rational val2 = val.negate();
- return add(val2);
- } /* Rational.subtract */
-
- /**
- * Subtract an integer.
- *
- * @param val
- * the number to be subtracted from this
- * @return this - val.
- */
- public Rational subtract(final BigInteger val) {
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return subtract(val2);
- } /* Rational.subtract */
-
- /**
- * Subtract an integer.
- *
- * @param val
- * the number to be subtracted from this
- * @return this - val.
- */
- public Rational subtract(final int val) {
- final Rational val2 = new Rational(val, 1);
- return subtract(val2);
- } /* Rational.subtract */
-
- /**
- * binomial (n choose m).
- *
- * @param n
- * the numerator. Equals the size of the set to choose from.
- * @param m
- * the denominator. Equals the number of elements to select.
- * @return the binomial coefficient.
- * @since 2006-06-27
- * @author Richard J. Mathar
- * @throws Error
- */
- public static Rational binomial(final Rational n, final BigInteger m) throws Error {
- if (m.compareTo(BigInteger.ZERO) == 0) {
- return Rational.ONE;
- }
- Rational bin = n;
- for (BigInteger i = new BigInteger("2"); i.compareTo(m) != 1; i = i.add(BigInteger.ONE)) {
- bin = bin.multiply(n.subtract(i.subtract(BigInteger.ONE))).divide(i);
- }
- return bin;
- } /* Rational.binomial */
-
- /**
- * binomial (n choose m).
- *
- * @param n
- * the numerator. Equals the size of the set to choose from.
- * @param m
- * the denominator. Equals the number of elements to select.
- * @return the binomial coefficient.
- * @since 2009-05-19
- * @author Richard J. Mathar
- * @throws Error
- */
- public static Rational binomial(final Rational n, final int m) throws Error {
- if (m == 0) {
- return Rational.ONE;
- }
- Rational bin = n;
- for (int i = 2; i <= m; i++) {
- bin = bin.multiply(n.subtract(i - 1)).divide(i);
- }
- return bin;
- } /* Rational.binomial */
-
- /**
- * Hankel's symbol (n,k)
- *
- * @param n
- * the first parameter.
- * @param k
- * the second parameter, greater or equal to 0.
- * @return Gamma(n+k+1/2)/k!/GAMMA(n-k+1/2)
- * @since 2010-07-18
- * @author Richard J. Mathar
- * @throws Error
- */
- public static Rational hankelSymb(final Rational n, final int k) throws Error {
- if (k == 0) {
- return Rational.ONE;
- } else if (k < 0) {
- throw new Error(Errors.NEGATIVE_PARAMETER);
- }
- Rational nkhalf = n.subtract(k).add(Rational.HALF);
- nkhalf = nkhalf.Pochhammer(2 * k);
- final Factorial f = new Factorial();
- return nkhalf.divide(f.at(k));
- } /* Rational.binomial */
-
- /**
- * Get the numerator.
- *
- * @return The numerator of the reduced fraction.
- */
- public BigInteger numer() {
- return a;
- }
-
- /**
- * Get the denominator.
- *
- * @return The denominator of the reduced fraction.
- */
- public BigInteger denom() {
- return b;
- }
-
- /**
- * Absolute value.
- *
- * @return The absolute (non-negative) value of this.
- */
- public Rational abs() {
- return new Rational(a.abs(), b.abs());
- }
-
- /**
- * floor(): the nearest integer not greater than this.
- *
- * @return The integer rounded towards negative infinity.
- */
- public BigInteger floor() {
- /*
- * is already integer: return the numerator
- */
- if (b.compareTo(BigInteger.ONE) == 0) {
- return a;
- } else if (a.compareTo(BigInteger.ZERO) > 0) {
- return a.divide(b);
- } else {
- return a.divide(b).subtract(BigInteger.ONE);
- }
- } /* Rational.floor */
-
- /**
- * ceil(): the nearest integer not smaller than this.
- *
- * @return The integer rounded towards positive infinity.
- * @since 2010-05-26
- */
- public BigInteger ceil() {
- /*
- * is already integer: return the numerator
- */
- if (b.compareTo(BigInteger.ONE) == 0) {
- return a;
- } else if (a.compareTo(BigInteger.ZERO) > 0) {
- return a.divide(b).add(BigInteger.ONE);
- } else {
- return a.divide(b);
- }
- } /* Rational.ceil */
-
- /**
- * Remove the fractional part.
- *
- * @return The integer rounded towards zero.
- */
- public BigInteger trunc() {
- /*
- * is already integer: return the numerator
- */
- if (b.compareTo(BigInteger.ONE) == 0) {
- return a;
- } else {
- return a.divide(b);
- }
- } /* Rational.trunc */
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * the other constant to compare with
- * @return -1, 0 or 1 if this number is numerically less than, equal to, or
- * greater than val.
- */
- @Override
- public int compareTo(final Rational val) {
- /*
- * Since we have always kept the denominators positive, simple
- * cross-multiplying works without changing the sign.
- */
- final BigInteger left = a.multiply(val.b);
- final BigInteger right = val.a.multiply(b);
- return left.compareTo(right);
- } /* Rational.compareTo */
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * the other constant to compare with
- * @return -1, 0 or 1 if this number is numerically less than, equal to, or
- * greater than val.
- */
- public int compareTo(final BigInteger val) {
- final Rational val2 = new Rational(val, BigInteger.ONE);
- return compareTo(val2);
- } /* Rational.compareTo */
-
- /**
- * Return a string in the format number/denom. If the denominator equals 1,
- * print just the numerator without a slash.
- *
- * @return the human-readable version in base 10
- */
- @Override
- public String toString() {
- if (b.compareTo(BigInteger.ONE) != 0) {
- return a.toString() + "/" + b.toString();
- } else {
- return a.toString();
- }
- } /* Rational.toString */
-
- /**
- * Return a double value representation.
- *
- * @return The value with double precision.
- * @since 2008-10-26
- */
- public double doubleValue() {
- /*
- * To meet the risk of individual overflows of the exponents of a
- * separate invocation a.doubleValue() or b.doubleValue(), we divide
- * first in a BigDecimal environment and convert the result.
- */
- final BigDecimal adivb = new BigDecimal(a).divide(new BigDecimal(b), MathContext.DECIMAL128);
- return adivb.doubleValue();
- } /* Rational.doubleValue */
-
- /**
- * Return a float value representation.
- *
- * @return The value with single precision.
- * @since 2009-08-06
- */
- public float floatValue() {
- final BigDecimal adivb = new BigDecimal(a).divide(new BigDecimal(b), MathContext.DECIMAL128);
- return adivb.floatValue();
- } /* Rational.floatValue */
-
- /**
- * Return a representation as BigDecimal.
- *
- * @param mc
- * the mathematical context which determines precision, rounding
- * mode etc
- * @return A representation as a BigDecimal floating point number.
- * @since 2008-10-26
- */
- public BigDecimal BigDecimalValue(final MathContext mc) {
- /*
- * numerator and denominator individually rephrased
- */
- final BigDecimal n = new BigDecimal(a);
- final BigDecimal d = new BigDecimal(b);
- /*
- * the problem with n.divide(d,mc) is that the apparent precision might
- * be smaller than what is set by mc if the value has a precise
- * truncated representation. 1/4 will appear as 0.25, independent of mc
- */
- return BigDecimalMath.scalePrec(n.divide(d, mc), mc);
- } /* Rational.BigDecimalValue */
-
- /**
- * Return a string in floating point format.
- *
- * @param digits
- * The precision (number of digits)
- * @return The human-readable version in base 10.
- * @since 2008-10-25
- */
- public String toFString(final int digits) {
- if (b.compareTo(BigInteger.ONE) != 0) {
- final MathContext mc = new MathContext(digits, RoundingMode.DOWN);
- final BigDecimal f = new BigDecimal(a).divide(new BigDecimal(b), mc);
- return f.toString();
- } else {
- return a.toString();
- }
- } /* Rational.toFString */
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * The other constant to compare with
- * @return The arithmetic maximum of this and val.
- * @since 2008-10-19
- */
- public Rational max(final Rational val) {
- if (compareTo(val) > 0) {
- return this;
- } else {
- return val;
- }
- } /* Rational.max */
-
- /**
- * Compares the value of this with another constant.
- *
- * @param val
- * The other constant to compare with
- * @return The arithmetic minimum of this and val.
- * @since 2008-10-19
- */
- public Rational min(final Rational val) {
- if (compareTo(val) < 0) {
- return this;
- } else {
- return val;
- }
- } /* Rational.min */
-
- /**
- * Compute Pochhammer's symbol (this)_n.
- *
- * @param n
- * The number of product terms in the evaluation.
- * @return Gamma(this+n)/Gamma(this) = this*(this+1)*...*(this+n-1).
- * @since 2008-10-25
- */
- public Rational Pochhammer(final BigInteger n) {
- if (n.compareTo(BigInteger.ZERO) < 0) {
- return null;
- } else if (n.compareTo(BigInteger.ZERO) == 0) {
- return Rational.ONE;
- } else {
- /*
- * initialize results with the current value
- */
- Rational res = new Rational(a, b);
- BigInteger i = BigInteger.ONE;
- for (; i.compareTo(n) < 0; i = i.add(BigInteger.ONE)) {
- res = res.multiply(add(i));
- }
- return res;
- }
- } /* Rational.pochhammer */
-
- /**
- * Compute pochhammer's symbol (this)_n.
- *
- * @param n
- * The number of product terms in the evaluation.
- * @return Gamma(this+n)/GAMMA(this).
- * @since 2008-11-13
- */
- public Rational Pochhammer(final int n) {
- return Pochhammer(new BigInteger("" + n));
- } /* Rational.pochhammer */
-
- /**
- * True if the value is integer. Equivalent to the indication whether a
- * conversion to an integer can be exact.
- *
- * @since 2010-05-26
- */
- public boolean isBigInteger() {
- return b.abs().compareTo(BigInteger.ONE) == 0;
- } /* Rational.isBigInteger */
-
- /**
- * True if the value is integer and in the range of the standard integer.
- * Equivalent to the indication whether a conversion to an integer can be
- * exact.
- *
- * @since 2010-05-26
- */
- public boolean isInteger() {
- if (!isBigInteger()) {
- return false;
- }
- return a.compareTo(Rational.MAX_INT) <= 0 && a.compareTo(Rational.MIN_INT) >= 0;
- } /* Rational.isInteger */
-
- /**
- * Conversion to an integer value, if this can be done exactly.
- *
- * @throws Error
- *
- * @since 2011-02-13
- */
- int intValue() throws Error {
- if (!isInteger()) {
- throw new Error(Errors.CONVERSION_ERROR);
- }
- return a.intValue();
- }
-
- /**
- * Conversion to a BigInteger value, if this can be done exactly.
- *
- * @throws Error
- *
- * @since 2012-03-02
- */
- BigInteger BigIntegerValue() throws Error {
- if (!isBigInteger()) {
- throw new Error(Errors.CONVERSION_ERROR);
- }
- return a;
- }
-
- /**
- * True if the value is a fraction of two integers in the range of the
- * standard integer.
- *
- * @since 2010-05-26
- */
- public boolean isIntegerFrac() {
- return a.compareTo(Rational.MAX_INT) <= 0 && a.compareTo(Rational.MIN_INT) >= 0 && b.compareTo(Rational.MAX_INT) <= 0 && b.compareTo(Rational.MIN_INT) >= 0;
- } /* Rational.isIntegerFrac */
-
- /**
- * The sign: 1 if the number is >0, 0 if ==0, -1 if <0
- *
- * @return the signum of the value.
- * @since 2010-05-26
- */
- public int signum() {
- return b.signum() * a.signum();
- } /* Rational.signum */
-
- /**
- * Common lcm of the denominators of a set of rational values.
- *
- * @param vals
- * The list/set of the rational values.
- * @return LCM(denom of first, denom of second, ..,denom of last)
- * @since 2012-03-02
- */
- static public BigInteger lcmDenom(final Rational[] vals) {
- BigInteger l = BigInteger.ONE;
- for (final Rational val : vals) {
- l = BigIntegerMath.lcm(l, val.b);
- }
- return l;
- } /* Rational.lcmDenom */
-
- /**
- * Normalize to coprime numerator and denominator. Also copy a negative sign
- * of the denominator to the numerator.
- *
- * @since 2008-10-19
- */
- protected void normalize() {
- /*
- * compute greatest common divisor of numerator and denominator
- */
- final BigInteger g = a.gcd(b);
- if (g.compareTo(BigInteger.ONE) > 0) {
- a = a.divide(g);
- b = b.divide(g);
- }
- if (b.compareTo(BigInteger.ZERO) == -1) {
- a = a.negate();
- b = b.negate();
- }
- } /* Rational.normalize */
-} /* Rational */
diff --git a/core/src/main/java/org/nevec/rjm/SafeMathContext.java b/core/src/main/java/org/nevec/rjm/SafeMathContext.java
deleted file mode 100644
index 95dd90e0..00000000
--- a/core/src/main/java/org/nevec/rjm/SafeMathContext.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.MathContext;
-import java.math.RoundingMode;
-
-import it.cavallium.warppi.Engine;
-import it.cavallium.warppi.Platform.ConsoleUtils;
-
-public final class SafeMathContext {
-
- public static MathContext newMathContext(int precision) {
- if (precision <= 0) {
- Engine.getPlatform().getConsoleUtils().out().print(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, "Warning! MathContext precision is <= 0 (" + precision + ")");
- precision = 1;
- }
- return new MathContext(precision);
- }
-
- public static MathContext newMathContext(int precision, final RoundingMode roundingMode) {
- if (precision <= 0) {
- Engine.getPlatform().getConsoleUtils().out().print(ConsoleUtils.OUTPUTLEVEL_DEBUG_MIN, "Warning! MathContext precision is <= 0 (" + precision + ")");
- precision = 1;
- }
- return new MathContext(precision, roundingMode);
- }
-
-}
diff --git a/core/src/main/java/org/nevec/rjm/Wigner3j.java b/core/src/main/java/org/nevec/rjm/Wigner3j.java
deleted file mode 100644
index 114ddfa3..00000000
--- a/core/src/main/java/org/nevec/rjm/Wigner3j.java
+++ /dev/null
@@ -1,628 +0,0 @@
-package org.nevec.rjm;
-
-import java.math.BigInteger;
-import java.util.Scanner;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * Exact representations of Wigner 3jm and 3nj values of half-integer arguments.
- *
- * @see R. J. Mathar, Corrigendum to
- * "Universal factorzation fo 3n-j (j>2) symbols ..[J. Phys. A: Math. Gen.37 (2004) 3259]"
- *
- * @see R. J. Mathar, Symmetries in
- * Wigner 18-j and 21-j Symbols
- * @since 2011-02-15
- * @author Richard J. Mathar
- */
-public class Wigner3j {
- /**
- * Test programs. This supports three types of direct evaluations:
- * java -cp . org.nevec.rjm.Wigner3j 3jm 2j1+1 2j2+1 2j3+1 2m1+1 2m2+1 2m3+1
- *
- * java -cp . org.nevec.rjm.Wigner3j 6j 2j1+1 2j2+2 .. 2j6+1
- * java -cp . org.nevec.rjm.Wigner3j 9j 2j1+1 2j2+2 .. 2j9+1
- * The first command line argument is one of the three tags which determine
- * whether a 3jm, a 6j or a 9j symbol will be computed. The other arguments
- * are 6 or 9 integer values, which are the physical (half-integer) values
- * multplied by 2 and augmented by 1. The order of the 6 or 9 values is as
- * reading the corresponding standard symbol as first row, then second row
- * (and for the 9j symbol) third row.
- *
- * @since 2011-02-15
- * @author Richard J. Mathar
- * @throws Error
- */
- static public void main(final String args[]) throws Error {
- if (args[0].compareTo("6j") == 0) {
- try {
- final String m1 = "6";
- final String t1 = "1 2 -3 -1 5 6";
- final String t2 = "4 -5 3 -4 -2 -6";
- String j = "";
- for (int i = 1; i <= 6; i++) {
- j += args[i] + " ";
- }
- final BigSurdVec w = Wigner3j.wigner3j(m1, t1, t2, j);
- System.out.println(w.toString());
- } catch (final Exception e) {
- System.out.println(e.getMessage());
- }
- } else if (args[0].compareTo("9j") == 0) {
- try {
- final String m1 = "9";
- final String t1 = "1 3 2 4 6 5 7 9 8";
- final String t2 = "2 8 5 6 3 9 7 4 1";
- String j = "";
- for (int i = 1; i <= 9; i++) {
- j += args[i] + " ";
- }
- final BigSurdVec w = Wigner3j.wigner3j(m1, t1, t2, j);
- System.out.println(w.toString());
- } catch (final Exception e) {
- System.out.println(e.getMessage());
- }
- } else if (args[0].compareTo("3jm") == 0) {
- final int j1 = new Integer(args[1]).intValue();
- final int j2 = new Integer(args[2]).intValue();
- final int j3 = new Integer(args[3]).intValue();
- final int m1 = new Integer(args[4]).intValue();
- final int m2 = new Integer(args[5]).intValue();
- final int m3 = new Integer(args[6]).intValue();
- try {
- BigSurd w = Wigner3j.wigner3jm(j1, j2, j3, m1, m2, m3);
- System.out.println(w.toString());
- w = w.multiply(new BigSurd(j3 + 1, 1));
- System.out.println("CG factor sqrt" + (j3 + 1) + "sign " + (j2 - j2 - m3) / 2 + " " + w.toString());
- } catch (final Exception e) {
- System.out.println(e.getMessage());
- }
- } else {
- System.out.println("usage:");
- System.out.println(args[0] + " 6j 2j1+1 2j2+1 2j3+1 2j4+1 2j5+1 2j6+1");
- System.out.println(args[0] + " 9j 2j1+1 2j2+1 2j3+1 2j4+1 2j5+1 2j6+1.. 2j9+1 ");
- System.out.println(args[0] + " 3jm 2j1+1 2j2+1 2j3+1 2m1+1 2m2+1 2m3+1 ");
- }
- } /* Wigner3j.main */
-
- /**
- * The Wigner 3jm symbol (j1,j2,j3,m1,m2,m3). All arguments of the function
- * are the actual parameters multiplied by 2, so they all allow an integer
- * representation.
- *
- * @param j1
- * integer representing 2*j1
- * @param j2
- * integer representing 2*j2
- * @param j3
- * integer representing 2*j3
- * @param m1
- * integer representing 2*m1
- * @param m2
- * integer representing 2*m2
- * @param m3
- * integer representing 2*m3
- * @return The value of the symbol. Zero if any of the triangular
- * inequalities is violated or some parameters are out of range.
- * @since 2011-02-13
- * @author Richard J. Mathar
- * @throws Error
- */
- static public BigSurd wigner3jm(final int j1, final int j2, final int j3, final int m1, final int m2, final int m3)
- throws Error {
- final Rational J1 = new Rational(j1, 2);
- final Rational J2 = new Rational(j2, 2);
- final Rational J3 = new Rational(j3, 2);
- final Rational M1 = new Rational(m1, 2);
- final Rational M2 = new Rational(m2, 2);
- final Rational M3 = new Rational(m3, 2);
- return Wigner3j.wigner3jm(J1, J2, J3, M1, M2, M3);
- } /* wigner3jm */
-
- /**
- * Wigner 3jn symbol. For the 6j symbol, the input of the 3 lines is
- * "1 2 3 1 5 6", "4 5 3 4 2 6" "2j1+1 2j2+1 2j3+1 2l1+1 2l2+1 2l3+1"
- *
- * @param m1
- * The information on the number of angular momenta.
- * @param t1
- * The list of one half of the triads, indexing j, whitespace
- * separated
- * @param t2
- * The list of the second half of the triads, indexing j,
- * whitespace separated
- * @param j
- * The list of the integer values of the angular momenta. They
- * are actually the doubled j-values plus 1, whitespace
- * separated. Only as many as announced by the m1 parameter are
- * used; trailing numbers are ignored.
- * @see A. Bar-Shalom and M. Klapisch,
- * NJGRAF...
- * , Comp. Phys Comm. 50 (3) (1988) 375
- * @since 2011-02-13
- * @since 2012-02-15 Upgraded return value to BigSurdVec
- * @author Richard J. Mathar
- * @throws Error
- */
- static public BigSurdVec wigner3j(final String m1, final String t1, final String t2, final String j) throws Error {
- /*
- * The first number in the line "m" is the number of angular momenta.
- * The rest of the line is ignored.
- */
- Scanner s = new Scanner(m1);
- final int m = s.nextInt();
- if (m % 3 != 0) {
- s.close();
- throw new IllegalArgumentException("Angular momenta " + m + " not a multiple of three.");
- }
-
- /*
- * Scan the numbers in the line "j". Excess numbers beyond what has been
- * announced in the "m" line are ignored.
- */
- final int[] jvec = new int[m];
- final int[] tvec = new int[2 * m];
-
- s.close();
-
- /*
- * the third row contains positive 2j+1.
- */
- s = new Scanner(j);
- int ji = 0;
- while (s.hasNextInt() && ji < m) {
- jvec[ji++] = s.nextInt();
- if (jvec[ji - 1] < 1) {
- s.close();
- throw new IllegalArgumentException("Illegal value " + jvec[ji - 1] + " for 2j+1.");
- }
- }
-
- s.close();
-
- /*
- * the first two rows contain signed values of indices into the j list
- */
- s = new Scanner(t1);
- int ti = 0;
- while (s.hasNextInt()) {
- tvec[ti++] = s.nextInt();
- }
-
- s.close();
-
- s = new Scanner(t2);
- while (s.hasNextInt()) {
- tvec[ti++] = s.nextInt();
- }
-
- /*
- * Basic sanity checks. All indices in the first two lines address a
- * number in the third line, and each index occurs exactly twice.
- */
- if (ji % 3 != 0) {
- s.close();
- throw new IllegalArgumentException("j-count " + ji + " not a multiple of three.");
- }
- if (ti != 2 * ji) {
- s.close();
- throw new IllegalArgumentException("triad-count " + ti + " not twice j-count " + ji);
- }
-
- final int[] jfreq = new int[m];
- for (ji = 0; ji < jfreq.length; ji++) {
- jfreq[ji] = 0;
- }
-
- /*
- * maintain a 0-based index which shows where the j-value has its first
- * and second occurrence in the flattened list of triads.
- */
- final int[][] jhash = new int[m][2];
-
- for (ti = 0; ti < 2 * m; ti++) {
- final int t = tvec[ti];
- if (t == 0 || Math.abs(t) > jvec.length) {
- s.close();
- throw new IllegalArgumentException("Triad index " + t + " out of bounds");
- }
- if (jfreq[Math.abs(t) - 1] >= 2) {
- s.close();
- throw new IllegalArgumentException("Node " + t + " referenced more than twice");
- }
- jhash[Math.abs(t) - 1][jfreq[Math.abs(t) - 1]] = ti;
- jfreq[Math.abs(t) - 1]++;
- }
-
- /*
- * Move on from the 2j+1 values of the input to the j-values. Subtract
- * one and divide through 2.
- */
- final Rational[] J = new Rational[jvec.length];
- for (ji = 0; ji < jvec.length; ji++) {
- J[ji] = new Rational(jvec[ji] - 1, 2);
- }
-
- /*
- * Convert the 1-based indices to 0-based indices, loosing the sign
- * information.
- */
- final int[] triadidx = new int[tvec.length];
- for (ti = 0; ti < tvec.length; ti++) {
- triadidx[ti] = Math.abs(tvec[ti]) - 1;
- }
-
- /*
- * The M-values are all null (undetermined) at the start.
- */
- final Rational[] M = new Rational[J.length];
- s.close();
- return Wigner3j.wigner3j(tvec, J, M, triadidx);
- } /* wigner3j */
-
- /**
- * Wigner 3jn symbol. Computes sum_{mi} (-1)^(j1-m1+j2-m2+...)
- * triad(triadidx[0..2])*triad(triadidx[3..5])*... where each factor is a
- * Wigner-3jm symbol with each sign of m_i occurring once at the
- * corresponding l-value.
- *
- * @param triadidx
- * 0-based indices into the list of J
- * @param J
- * The list of J-values
- * @param M
- * The list of M-values associated with the J. This contains null
- * where the parameter has not yet been set by an outer loop.
- * @since 2011-02-13
- * @since 2012-02-15 Upgraded to return BigSurdVec
- * @author Richard J. Mathar
- * @throws Error
- */
- static private BigSurdVec wigner3j(final int[] tvec, final Rational[] J, final Rational[] M, final int[] triadidx)
- throws Error {
- /*
- * The result of the computation. The sum over all m-combinations of the
- * triads.
- */
- BigSurdVec res = new BigSurdVec();
-
- /*
- * First step is to monitor the triangular conditions on the J. If at
- * least one is violated, the result is zero. Loop over the triads.
- */
- for (int t = 0; t < triadidx.length; t += 3) {
- /* Ensure |J[t]-J[t+1]| <= J[t+2] <= J[t]+J[t+1] */
- if (J[triadidx[t]].subtract(J[triadidx[t + 1]]).abs().compareTo(J[triadidx[t + 2]]) > 0) {
- return res;
- }
- if (J[triadidx[t]].add(J[triadidx[t + 1]]).compareTo(J[triadidx[t + 2]]) < 0) {
- return res;
- }
- }
-
- /*
- * the index of the preferred member of the triad list. Preference given
- * to those dangling in triads where alreaday two others are fixed, then
- * to members where at least one is fixed, then to smallest associated
- * J-values.
- */
- int freeM = -1;
- int freeMrank = -1;
- for (int i = 0; i < triadidx.length; i++) {
- /*
- * found an m-value which has not yet been summed over.
- */
- if (M[triadidx[i]] == null) {
- /*
- * two cases: value is fixed implicitly because already two
- * others values are set in the triad. or it is still to
- * maintain its own explicit loop.
- */
- final int triadn = i / 3;
- final int triadr = i % 3;
- /*
- * the neighbors in the triad have indices triadn*3+ (tiradr+1)
- * mod 3 and triadn*3+(triadr+2) mod3
- */
- final int nei1 = 3 * triadn + (triadr + 1) % 3;
- final int nei2 = 3 * triadn + (triadr + 2) % 3;
-
- /*
- * found a candidate for which the two other values are already
- * set.
- */
- if (M[triadidx[nei1]] != null && M[triadidx[nei2]] != null) {
- freeM = i;
- break;
- } else {
- /*
- * rough work load estimator: basically (2J1+1)*(2J2+1)
- */
- Rational wt = J[triadidx[i]].multiply(2).add(1);
- if (M[triadidx[nei1]] == null) {
- wt = wt.multiply(J[triadidx[nei1]].multiply(2).add(1));
- }
- if (M[triadidx[nei2]] == null) {
- wt = wt.multiply(J[triadidx[nei2]].multiply(2).add(1));
- }
- final int thiswt = wt.intValue();
- if (freeM < 0 || thiswt < freeMrank) {
- freeM = i;
- freeMrank = thiswt;
- }
- }
- }
- }
-
- if (freeM >= 0) {
- /*
- * found an m-value which has not yet been summed over.
- */
- if (M[triadidx[freeM]] == null) {
- final Rational[] childM = new Rational[M.length];
- for (int ji = 0; ji < M.length; ji++) {
- if (M[ji] != null) {
- childM[ji] = M[ji];
- }
- }
-
- /*
- * two cases: value is fixed implicitly because already two
- * others values are set in the triad. or it is still to
- * maintain its own explicit loop.
- */
- final int triadn = freeM / 3;
- final int triadr = freeM % 3;
- /*
- * the neighbors in the triad have indices triadn*3+ (triadr+1)
- * mod 3 and triadn*3+(triadr+2) mod3
- */
- final int nei1 = 3 * triadn + (triadr + 1) % 3;
- final int nei2 = 3 * triadn + (triadr + 2) % 3;
- if (M[triadidx[nei1]] == null || M[triadidx[nei2]] == null) {
- /*
- * The J-value is J[triadidx[freeM]]. Loop from -J to +J,
- * the allowed range.
- */
- Rational newm = J[triadidx[freeM]].negate();
- while (newm.compareTo(J[triadidx[freeM]]) <= 0) {
- childM[triadidx[freeM]] = tvec[freeM] > 0 ? newm : newm.negate();
- res = res.add(Wigner3j.wigner3j(tvec, J, childM, triadidx));
- newm = newm.add(Rational.ONE);
- }
- } else {
- /*
- * Set its value and the value at its companion j-value. Sum
- * of the three m-values in the triad is to be zero for a
- * non-zero contribution.
- */
- Rational m1 = M[triadidx[nei1]];
- Rational m2 = M[triadidx[nei2]];
- /*
- * negate if these are the second occurrences of the J in
- * the triads
- */
- if (tvec[nei1] < 0) {
- m1 = m1.negate();
- }
- if (tvec[nei2] < 0) {
- m2 = m2.negate();
- }
- /* m3 = -(m1+m2) */
- final Rational newm = tvec[freeM] > 0 ? m1.add(m2).negate() : m1.add(m2);
- /*
- * No contribution if the m-value enforced by the other two
- * entries is outside the range -|J|..|J| enforced by its
- * associated J-value. One could essentially remove this
- * branching and let wigner3j() decide on this, but this is
- * inefficient.
- */
- if (newm.abs().compareTo(J[triadidx[freeM]]) <= 0) {
- childM[triadidx[freeM]] = newm;
- res = res.add(Wigner3j.wigner3j(tvec, J, childM, triadidx));
- }
- /*
- * zero contribution if this m-value cannot be set to any
- * value compatible with the triangular conditions.
- */
- }
- return res;
- }
- }
-
- /*
- * reached the bottom of the loop where all M-values are assigned. Build
- * the product over all Wigner-3jm values and the associated sign.
- */
- res = BigSurdVec.ONE;
- for (int ji = 0; ji < triadidx.length; ji += 3) {
- Rational m1 = M[triadidx[ji]];
- Rational m2 = M[triadidx[ji + 1]];
- Rational m3 = M[triadidx[ji + 2]];
- /*
- * negate if these are associated with in-flowing vectors in the
- * triads
- */
- if (tvec[ji] < 0) {
- m1 = m1.negate();
- }
- if (tvec[ji + 1] < 0) {
- m2 = m2.negate();
- }
- if (tvec[ji + 2] < 0) {
- m3 = m3.negate();
- }
- res = res.multiply(Wigner3j.wigner3jm(J[triadidx[ji]], J[triadidx[ji + 1]], J[triadidx[ji + 2]], m1, m2, m3));
-
- /*
- * if a partial product yields zero, the total product is zero, too,
- * and offers an early exit.
- */
- if (res.signum() == 0) {
- return BigSurdVec.ZERO;
- }
- }
- /*
- * The overal sign is product_{J-Mpairs} (-1)^(J-M). This is an integer
- * because all the J-M are integer.
- */
- Rational sig = new Rational();
- for (int ji = 0; ji < J.length; ji++) {
- sig = sig.add(J[ji]).subtract(M[ji]);
- }
- /*
- * sign depends on the sum being even or odd. We assume that "sig" is
- * integer and look only at the numerator
- */
- if (sig.a.abs().testBit(0)) {
- res = res.negate();
- }
- return res;
- } /* wigner3j */
-
- /**
- * The Wigner 3jm symbol (j1,j2,j3,m1,m2,m3). Warning: there is no check
- * that each argument is indeed half-integer.
- *
- * @param j1
- * integer or half-integer j1
- * @param j2
- * integer or half-integer j2
- * @param j3
- * integer or half-integer j3
- * @param m1
- * integer or half-integer m1
- * @param m2
- * integer or half-integer m2
- * @param m3
- * integer or half-integer m3
- * @return The value of the symbol. Zero if any of the triangular
- * inequalities is violated or some parameters are out of range.
- * @since 2011-02-13
- * @author Richard J. Mathar
- * @throws Error
- */
- static protected BigSurd wigner3jm(final Rational j1, final Rational j2, final Rational j3, final Rational m1,
- final Rational m2, final Rational m3) throws Error {
- /*
- * Check that m1+m2+m3 = 0
- */
- if (m1.add(m2).add(m3).signum() != 0) {
- return BigSurd.ZERO;
- }
-
- /*
- * Check that j1+j2+j3 is integer
- */
- if (j1.add(j2).add(j3).isBigInteger() == false) {
- return BigSurd.ZERO;
- }
-
- /*
- * Check that |j1-j2|<=j3 <= |j1+j2|
- */
- final Rational j1m2 = j1.subtract(j2);
- if (j1m2.abs().compareTo(j3) > 0) {
- return BigSurd.ZERO;
- }
- final Rational j1p2 = j1.add(j2);
- if (j1p2.abs().compareTo(j3) < 0) {
- return BigSurd.ZERO;
- }
-
- /*
- * Check that |m_i| <= j_i
- */
- if (m1.abs().compareTo(j1) > 0 || m2.abs().compareTo(j2) > 0 || m3.abs().compareTo(j3) > 0) {
- return BigSurd.ZERO;
- }
-
- /*
- * Check that m_i-j_i are integer.
- */
- if (!m1.subtract(j1).isBigInteger() || !m2.subtract(j2).isBigInteger() || !m3.subtract(j3).isBigInteger()) {
- return BigSurd.ZERO;
- }
-
- /*
- * (-)^(j1-j2-m3)*delta(-m3,m1+m2)*sqrt[ (j3+j1-j2)! (j3-j1+j2)!
- * (j1+j2-j3)! /(j1+j2+j3+1)!
- * *(j3-m)!*(j3+m)!(j1-m1)!*(j1+m1)!*(j2-m2)!*(j2+m2)!] *sum_k
- * (-1)^k/[k!(j1+j2-j3-k)!(j1-m1-k)!(j2+m2-k)!(j3-j2+m1+k)!)*(j3-j1-m2+k
- * )!]
- */
-
- /*
- * It is tacitly assumed that all the major j_i, m_i values are in the
- * integer range. This is implicitly plausible since otherwise the
- * execution times of the following loop over the k-values would be
- * immense.
- */
- int j1j2jk = j1p2.subtract(j3).intValue();
- int j1m1k = j1.subtract(m1).intValue();
- int j2m2k = j2.add(m2).intValue();
- int jj2m1k = j3.subtract(j2).add(m1).intValue();
- int jj1m2k = j3.subtract(j1).subtract(m2).intValue();
-
- int k = Math.max(0, -jj2m1k);
- k = Math.max(k, -jj1m2k);
- if (k > 0) {
- j1j2jk -= k;
- j1m1k -= k;
- j2m2k -= k;
- jj2m1k += k;
- jj1m2k += k;
- }
-
- final Factorial f = new Factorial();
- Rational sumk = new Rational();
- while (true) {
- final BigInteger d = f.at(k).multiply(f.at(j1j2jk)).multiply(f.at(j1m1k)).multiply(f.at(j2m2k)).multiply(f.at(jj2m1k)).multiply(f.at(jj1m2k));
- if (k % 2 == 0) {
- sumk = sumk.add(new Rational(BigInteger.ONE, d));
- } else {
- sumk = sumk.subtract(new Rational(BigInteger.ONE, d));
- }
- j1j2jk--;
- j1m1k--;
- j2m2k--;
- jj2m1k++;
- jj1m2k++;
- if (j1j2jk < 0 || j1m1k < 0 || j2m2k < 0) {
- break;
- }
- k++;
- }
- /*
- * sign factor (-1)^(j1-j2-m3)
- */
- if (j1m2.subtract(m3).intValue() % 2 != 0) {
- sumk = sumk.negate();
- }
-
- k = j1m2.add(j3).intValue();
- BigInteger s = f.at(k);
- k = j3.subtract(j1m2).intValue();
- s = s.multiply(f.at(k));
- k = j1p2.subtract(j3).intValue();
- s = s.multiply(f.at(k));
- k = j3.add(m3).intValue();
- s = s.multiply(f.at(k));
- k = j3.subtract(m3).intValue();
- s = s.multiply(f.at(k));
- k = j1.add(m1).intValue();
- s = s.multiply(f.at(k));
- k = j1.subtract(m1).intValue();
- s = s.multiply(f.at(k));
- k = j2.add(m2).intValue();
- s = s.multiply(f.at(k));
- k = j2.subtract(m2).intValue();
- s = s.multiply(f.at(k));
- k = j1p2.add(j3).intValue();
- k++;
- final Rational disc = new Rational(s, f.at(k));
- return new BigSurd(sumk, disc);
- } /* wigner3jm */
-
-} /* Wigner3j */
diff --git a/core/src/main/java/org/nevec/rjm/Wigner3jGUI.java b/core/src/main/java/org/nevec/rjm/Wigner3jGUI.java
deleted file mode 100644
index 8cffd15f..00000000
--- a/core/src/main/java/org/nevec/rjm/Wigner3jGUI.java
+++ /dev/null
@@ -1,335 +0,0 @@
-package org.nevec.rjm;
-
-import java.awt.Color;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Label;
-import java.awt.TextArea;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Scanner;
-
-import javax.swing.JButton;
-import javax.swing.JFrame;
-import javax.swing.JList;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-
-import it.cavallium.warppi.util.Error;
-
-/**
- * An interactive interface to the Wigner3j class. The GUI allows to preselect
- * one of the symbols if the number of j-terms is small (6j up to 15j), or to
- * enter any other connectivity for the triads of j-values. The actual j-values
- * are entered as integers (2j+1) and the computation of one value (in exact
- * square root representation) is started manually.
- *
- * @since 2011-02-15
- */
-public class Wigner3jGUI implements ActionListener, ListSelectionListener {
- /**
- * The master window of the session
- */
- JFrame fram;
-
- /*
- * global labels
- */
- Label Lbl0;
- Label Lbl1;
-
- JButton sear;
- JList> searJ;
- String[] searOpt = { "6j", "9j", "12j 1st", "12j 2nd (not symm)", "15j 1st", "15j 2nd", "15j 3rd", "15j 4th", "15j 5th" };
-
- /**
- * Field with the triads inputs
- */
- TextArea inpGtria;
-
- /**
- * Field with the J-value inputs
- */
- TextArea inpGjval;
-
- /**
- * Field of the outputs.
- */
- TextArea outG;
-
- GridBagLayout gridbag;
- GridBagConstraints gridconstr;
-
- /**
- * @since 2011-02-15
- */
- public void init() {
- fram = new JFrame("Wigner3jGUI");
-
- Lbl0 = new Label("Input: (Triads upper area, values 2J+1 second area");
- Lbl1 = new Label("Output:");
-
- sear = new JButton("Compute");
- sear.setActionCommand("compute");
- sear.addActionListener(this);
- sear.setToolTipText("Compute a general 3jn value");
-
- searJ = new JList