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.cavallium warppi - 0.9.0a2 + 0.9.0a2 warppi-core @@ -17,7 +17,17 @@ it.cavallium warppi-flow - ${project.version} + 0.9.0a2 + + + it.cavallium + warppi-util + 0.9.0a2 + + + it.cavallium + bigdecimal-math + 0.9.0a2 it.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 - * 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(searOpt); - searJ.setLayoutOrientation(JList.HORIZONTAL_WRAP); - searJ.addListSelectionListener(this); - - final Font defFont = new Font("Monospaced", Font.PLAIN, 11); - - fram.setBackground(new Color(250, 250, 250)); - fram.setForeground(new Color(0, 0, 0)); - final Color fg = new Color(0, 200, 0); - final Color bg = new Color(10, 10, 10); - - gridbag = new GridBagLayout(); - fram.setLayout(gridbag); - - gridconstr = new GridBagConstraints(); - gridconstr.gridx = 0; - gridconstr.gridy = GridBagConstraints.RELATIVE; - - inpGtria = new TextArea("", 4, 80); - inpGtria.setFont(defFont); - inpGtria.setForeground(fg); - inpGtria.setBackground(bg); - - inpGjval = new TextArea("", 10, 80); - inpGjval.setFont(defFont); - inpGjval.setForeground(fg); - inpGjval.setBackground(bg); - - outG = new TextArea("", 12, 80); - outG.setEditable(false); - outG.setFont(defFont); - outG.setForeground(fg); - outG.setBackground(bg); - - fram.add(Lbl0); - gridbag.setConstraints(Lbl0, gridconstr); - - fram.add(inpGtria); - gridbag.setConstraints(inpGtria, gridconstr); - - fram.add(inpGjval); - gridbag.setConstraints(inpGjval, gridconstr); - - fram.add(sear); - gridbag.setConstraints(sear, gridconstr); - fram.add(searJ); - gridbag.setConstraints(searJ, gridconstr); - - fram.add(Lbl1); - gridbag.setConstraints(Lbl1, gridconstr); - - fram.add(outG); - gridbag.setConstraints(outG, gridconstr); - - fram.pack(); - fram.setVisible(true); - } /* init */ - - /** - * @throws Error - * @since 2010-08-27 - */ - public void compute() throws Error { - final String tr = inpGtria.getText(); - final String[] trias = new String[4]; - - /* - * Read the trias configuration from inpGtria into trias[0..2], skipping - * lines that start with a hash mark. - */ - Scanner s = new Scanner(tr); - for (int l = 0; l < 3;) { - try { - trias[l] = s.nextLine().trim(); - if (!trias[l].startsWith("#")) { - l++; - } - } catch (final Exception e) { - s.close(); - outG.setText("ERROR: less than 3 lines in the triad definition"); - return; - } - } - - s.close(); - - /* - * Read the J values from inpGjval into trias[3] in a loop - */ - final String j = inpGjval.getText(); - s = new Scanner(j); - while (true) { - try { - trias[3] = s.nextLine().trim(); - } catch (final Exception e) { - s.close(); - return; - } - if (!trias[3].startsWith("#")) { - try { - final BigSurdVec w = Wigner3j.wigner3j(trias[0], trias[1], trias[2], trias[3]); - outG.append(w.toString() + " = " + w.doubleValue()); - } catch (final Exception e) { - outG.append(e.toString()); - e.printStackTrace(); - } - outG.append(" # J = "); - final Scanner num = new Scanner(trias[3]); - while (num.hasNextInt()) { - final int twoj1 = num.nextInt(); - final Rational jfrac = new Rational(twoj1 - 1, 2); - outG.append(jfrac.toString() + " "); - } - outG.append("\n"); - num.close(); - } - } - } /* compute */ - - /** - * Interpreter parser loop. - * - * @param e - * the information on which button had been pressed in the GUI - * @since 2011-02-15 - */ - @Override - public void actionPerformed(final ActionEvent e) { - final String lin = e.getActionCommand(); - /* - * debugging System.out.println("Ac"+e.paramString()) ; - * System.out.println(lin) ; - */ - if (lin == "compute") { - outG.setText(""); - try { - compute(); - } catch (final Error e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } - } /* actionPerformed */ - - /** - * Interpreter parser loop. - * - * @param e - * the information on which of the 3jn templates had been - * selected in the Menu - * @since 2011-02-18 - */ - @Override - public void valueChanged(final ListSelectionEvent e) { - switch (searJ.getMinSelectionIndex()) { - case 0: - inpGtria.setText("6\n"); - inpGtria.append("1 2 -3 -1 5 6\n"); - inpGtria.append("4 -5 3 -4 -2 -6"); - outG.setText(""); - break; - case 1: - /* - * Yutsis Figure 18.1 index map. j1=1, j2=2, j3=3 k1=4, k2=5, - * k3=6 - * l1=7, l2=8, l3=9 - */ - inpGtria.setText("9\n"); - inpGtria.append("1 3 2 4 6 5 7 9 8 # (j1 j3 j2) (k1 k3 k2) (l1 l3 l2)\n"); - inpGtria.append("-2 -8 -5 -6 -3 -9 -7 -4 -1 # (j2 l2 k2) (k3 j3 l3) (l1 k1 j1)"); - outG.setText(""); - break; - case 2: - /* - * Yutsis Figure 19.1 and 19.2, index map, including the sign - * reveral of the l. Assume input order j1..j4, l1..l4, k1..k4. - * j1=1, j2=2, j3=3, j4=4 l1=5, l2=6, l3=7, l4=8 k1=9, k2=10, - * k3=11, - * k4=12 - */ - inpGtria.setText("12\n"); - inpGtria.append("1 12 -8 -1 5 -2 2 6 -3 3 7 -4 # (j1 k4 l4) (j1 l1 j2) (j2 l2 j3) (j3 l3 j4)\n"); - inpGtria.append("4 8 -9 9 -5 -10 10 -6 -11 11 -7 -12 # (j4 l4 k1) (k1 l1 k2) (k2 l2 k3) (k3 l3 k4)"); - outG.setText(""); - break; - case 3: - inpGtria.setText("12\n"); - inpGtria.append("1 5 9 -9 -2 -7 2 11 8 -8 -12 -4 # (j1 l1 k1) (k1 j2 l3 ) (j2 k3 l4) (l4 k4 j4)\n"); - inpGtria.append("4 7 10 -10 -3 -5 3 6 12 -6 -11 -1 # (j4 l3 k2) (k2 j3 l1) (j3 l2 k4) (l2 k3 j1)"); - outG.setText(""); - break; - case 4: - /* - * Yutsis Figure 20.2 to 20.3, index map. j1=1, j2=2, j3=3, - * j4=4, - * j5=5 l1=6, l2=7, l3=8, l4=9, l5=10 k1=11, k2=12, k3=13, - * k4=14, - * k5=15 - */ - inpGtria.setText("15\n"); - inpGtria.append("1 -6 2 -2 -7 3 -3 -8 4 -4 -9 5 -5 -10 11 # (j1 l1 j2)(j2 l2 j3)(j3 l3 j4)(j4 l4 j5)(j5 l5 k1)\n"); - inpGtria.append("-11 6 12 -12 7 13 -13 8 14 -14 9 15 -15 10 -1 # (k1 l1 k2)(k2 l2 k3)(k3 l3 k4)(k4 l4 k5)(k5 l5 j1)"); - outG.setText(""); - break; - case 5: - inpGtria.setText("15\n"); - inpGtria.append("-1 -6 2 -2 -7 3 -3 -8 4 -4 -9 5 1 -5 -10 # (j1 l1 j2)(j2 l2 j3)(j3 l3 j4)(j4 l4 j5)(j1 j5 l5)\n"); - inpGtria.append("11 -15 10 9 15 -14 8 14 -13 7 13 -12 6 12 -11 # (k1 k5 l5)(l4 k5 k4)(l3 k4 k3)(l2 k3 k2)(l1 k2 k1)"); - outG.setText(""); - break; - case 6: - /* - * Yutsis Figure 20.4a, index map. k1=1, k1'=2, k=3, k'=4, k2=5, - * k2'=6 p1=7, p=8, p2=9, j1=10, j1'=11 j=12 j'=13 j2=14 j2'=15 - */ - inpGtria.setText("15\n"); - inpGtria.append("-13 -12 -8 12 14 10 -10 -1 7 -7 -11 -2 2 4 6 # (j' j p)(j j2 j1)(j1 k1 p1)(p1 j1' k1')(k1' k' k2')\n"); - inpGtria.append("-4 -3 8 1 3 5 -14 -5 9 -15 -6 -9 15 11 13 # (k' k p)(k1 k k2)(j2 k2 p2)(j2' k2' p2)(j2' j1' j')"); - outG.setText(""); - break; - case 7: - /* - * Yutsis Figure 20.5a, index map. j1=1, k1=2 s1=3 k1'=4 j1'=5 - * p=6 - * l=7 s=8 l'=9 p'=10 j2=11 k2=12 s2=13 k2'=14 j2'=15 - */ - inpGtria.setText("15\n"); - inpGtria.append("-14 -12 -8 12 11 -10 -11 13 -7 7 -1 3 2 1 6 # (k2' k2 s)(k2 j2 p')(j2 s2 l)(l j1 s1)(k1 j1 p)\n"); - inpGtria.append("-4 -2 8 10 4 5 9 -5 -3 -13 -9 -15 15 -6 14 # (k1' k1 s)(p' k1' j1')(l' j1' s1)(s2 l' j2')(j2' p k2')"); - outG.setText(""); - break; - case 8: - /* - * Yutsis Figure 20.6, index map. k1=1 k1'=2 j1=3 l1=4 l1'=5 - * k2=6 - * k2'=7 j2=8 l2=9 l2'=10 k3=11 k3'=12 j3=13 l3=14 l3'=15 - */ - inpGtria.setText("15\n"); - inpGtria.append("-15 1 -7 -4 -11 7 5 4 -3 -12 -5 6 12 -9 -1 # (l3' k1 k2')(l1 k3 k2')(l1' l1 j1)(k3' l1' k2)(k3' l2 k1)\n"); - inpGtria.append("9 -8 10 -10 11 -2 -14 -6 2 14 -13 15 3 8 13 # (l2 j2 l2')(l2' k3 k1')(l3 k2 k1')(l3 j3 l3')(j1 j2 j3)"); - outG.setText(""); - break; - } - } /* valueChanged */ - - /** - * Main entry point. not taking any command line options:
- * java -jar Wigner3jGUI.jar
- * - * @since 2012-02-16 - * @author Richard J. Mathar - */ - public static void main(final String[] args) { - final Wigner3jGUI g = new Wigner3jGUI(); - g.init(); - } /* main */ - -} /* Wigner3jGUI */ diff --git a/desktop/pom.xml b/desktop/pom.xml index 58f9edd3..c16aa18e 100644 --- a/desktop/pom.xml +++ b/desktop/pom.xml @@ -10,20 +10,18 @@ warppi-desktop - bundle - WarpPI Calculator Desktop WarpPI Calculator desktop project it.cavallium warppi-core - ${project.version} + 0.9.0a2 it.cavallium warppi-engine-jogl - ${project.version} + 0.9.0a2 org.fusesource.jansi @@ -55,23 +53,15 @@ + + org.apache.maven.plugins + maven-compiler-plugin + org.apache.maven.plugins maven-source-plugin - - org.apache.felix - maven-bundle-plugin - true - - - * - it.cavallium.warppi.* - warppi-desktop - - - org.apache.maven.plugins diff --git a/engine-jogl/pom.xml b/engine-jogl/pom.xml index c828b7a5..aa7a3f36 100644 --- a/engine-jogl/pom.xml +++ b/engine-jogl/pom.xml @@ -10,15 +10,13 @@ warppi-engine-jogl - bundle - WarpPI Calculator JOGL Engine WarpPI Calculator engine-jogl project it.cavallium warppi-core - ${project.version} + 0.9.0a2 org.jogamp.jogl @@ -38,16 +36,8 @@ - org.apache.felix - maven-bundle-plugin - true - - - * - it.cavallium.warppi.* - warppi-engine-jogl - - + org.apache.maven.plugins + maven-compiler-plugin org.apache.maven.plugins diff --git a/libs/raspi2fb b/hardware/libs/raspi2fb similarity index 100% rename from libs/raspi2fb rename to hardware/libs/raspi2fb diff --git a/hardware/pom.xml b/hardware/pom.xml index 1af4fd9b..e51cb1f7 100644 --- a/hardware/pom.xml +++ b/hardware/pom.xml @@ -18,12 +18,12 @@ it.cavallium warppi-core - ${project.version} + 0.9.0a2 it.cavallium warppi-engine-jogl - ${project.version} + 0.9.0a2 com.pi4j diff --git a/pom.xml b/pom.xml index 5bf95ad3..daf4c2cb 100755 --- a/pom.xml +++ b/pom.xml @@ -39,6 +39,8 @@ core + util + bigdecimal-math Flow rules diff --git a/rules/pom.xml b/rules/pom.xml index 0e81bb93..52156d1d 100644 --- a/rules/pom.xml +++ b/rules/pom.xml @@ -9,7 +9,6 @@ 0.9.0a2 warppi-rules - bundle WarpPI Calculator Rules WarpPI Calculator rules project @@ -18,23 +17,15 @@ it.cavallium warppi-core - ${project.version} + 0.9.0a2 - org.apache.felix - maven-bundle-plugin - true - - - * - it.cavallium.warppi.* - warppi-rules - - + org.apache.maven.plugins + maven-compiler-plugin org.apache.maven.plugins diff --git a/teavm/pom.xml b/teavm/pom.xml index 1493dc03..fc8c9325 100644 --- a/teavm/pom.xml +++ b/teavm/pom.xml @@ -17,12 +17,12 @@ it.cavallium warppi-core - ${project.version} + 0.9.0a2 it.cavallium warppi-rules - ${project.version} + 0.9.0a2 org.teavm diff --git a/util/.classpath b/util/.classpath new file mode 100644 index 00000000..5e8a55fe --- /dev/null +++ b/util/.classpath @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/util/.gitignore b/util/.gitignore new file mode 100644 index 00000000..b83d2226 --- /dev/null +++ b/util/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/util/.project b/util/.project new file mode 100644 index 00000000..d1a589e7 --- /dev/null +++ b/util/.project @@ -0,0 +1,23 @@ + + + warppi-util + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/util/pom.xml b/util/pom.xml new file mode 100644 index 00000000..84e1c6a6 --- /dev/null +++ b/util/pom.xml @@ -0,0 +1,38 @@ + + + 4.0.0 + + + it.cavallium + warppi + 0.9.0a2 + + warppi-util + + warppi-util + WarpPI Util + + + + cavallium + Andrea Cavalli + andrea@warp.ovh + https://cavallium.it/ + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.apache.maven.plugins + maven-source-plugin + + + + \ No newline at end of file diff --git a/core/src/main/java/it/cavallium/warppi/util/Error.java b/util/src/main/java/it/cavallium/warppi/util/Error.java similarity index 100% rename from core/src/main/java/it/cavallium/warppi/util/Error.java rename to util/src/main/java/it/cavallium/warppi/util/Error.java diff --git a/core/src/main/java/it/cavallium/warppi/util/Errors.java b/util/src/main/java/it/cavallium/warppi/util/Errors.java similarity index 100% rename from core/src/main/java/it/cavallium/warppi/util/Errors.java rename to util/src/main/java/it/cavallium/warppi/util/Errors.java