pax_global_header00006660000000000000000000000064146176771330014531gustar00rootroot0000000000000052 comment=c7ac80c27d942b0d82ba4852d6f795f0f53cccdb apfloat-1.14.0/000077500000000000000000000000001461767713300132425ustar00rootroot00000000000000apfloat-1.14.0/.github/000077500000000000000000000000001461767713300146025ustar00rootroot00000000000000apfloat-1.14.0/.github/workflows/000077500000000000000000000000001461767713300166375ustar00rootroot00000000000000apfloat-1.14.0/.github/workflows/maven.yml000066400000000000000000000022001461767713300204620ustar00rootroot00000000000000# This workflow will build a Java project with Maven, and cache/restore any dependencies to improve the workflow execution time # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-maven # This workflow uses actions that are not certified by GitHub. # They are provided by a third-party and are governed by # separate terms of service, privacy policy, and support # documentation. name: Java CI with Maven on: push: branches: [ "main" ] pull_request: branches: [ "main" ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up JDK 21 uses: actions/setup-java@v4 with: java-version: '21' distribution: 'oracle' check-latest: true cache: maven - name: Build with Maven run: mvn -B clean package -Dgpg.skip -Djarsigner.skip # Optional: Uploads the full dependency graph to GitHub to improve the quality of Dependabot alerts this repository can receive - name: Update dependency graph uses: advanced-security/maven-dependency-submission-action@v4.0.0 apfloat-1.14.0/.gitignore000066400000000000000000000002131461767713300152260ustar00rootroot00000000000000# Eclipse .classpath .metadata/ .project .settings/ # Intellij .idea/ *.iml *.iws # Mac .DS_Store # Maven log/ target/ apfloat-1.14.0/LICENSE.txt000066400000000000000000000021011461767713300150570ustar00rootroot00000000000000MIT License Copyright (c) 2024 Mikko Tommila Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.apfloat-1.14.0/README.md000066400000000000000000000021501461767713300145170ustar00rootroot00000000000000# Apfloat Copyright © 2024 Mikko Tommila This work is licensed under the terms of the MIT license. See the [MIT License](LICENSE.txt) for more details. If you have any questions or need a different type of license, please [contact the author](mailto:Mikko.Tommila@apfloat.org). ## Building the Library To build the library quickly, without running unit tests (takes about 20 minutes) and without signing with GPG run: `mvn clean install -Dgpg.skip -Djarsigner.skip -DskipTests` To build the signed applet files, you need to first generate a signing key, e.g. with: `keytool -genkeypair -validity 21915 -dname "cn=Your Name, o=example.com" -storepass password -keypass password -alias mykey` and then build without -Djarsigner.skip. ## Running the Sample Applications To run the arbitrary precision calculator, run: `mvn -pl :apfloat-calc exec:java -Dexec.mainClass=org.apfloat.calc.CalculatorGUI` To run the pi calculator, run: `mvn -pl :apfloat-samples exec:java -Dexec.mainClass=org.apfloat.samples.PiParallelGUI` ## Apfloat website Go to the [apfloat for Java website](http://www.apfloat.org/apfloat_java/). apfloat-1.14.0/apfloat-aparapi/000077500000000000000000000000001461767713300163035ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/pom.xml000066400000000000000000000050731461767713300176250ustar00rootroot00000000000000 4.0.0 org.apfloat apfloat-parent 1.14.0 apfloat-aparapi apfloat-aparapi Fast number theoretic transform implementation using Aparapi http://www.apfloat.org org.apfloat apfloat com.aparapi aparapi junit junit test org.apfloat apfloat test-jar test biz.aQute.bnd bnd-maven-plugin generate-osgi-manifest bnd-process org.apache.maven.plugins maven-jar-plugin ${project.build.outputDirectory}/META-INF/MANIFEST.MF org.apache.maven.plugins maven-shade-plugin shade org.apfloat:apfloat-aparapi ${project.build.directory}/apfloat-aparapi.jar apfloat-1.14.0/apfloat-aparapi/src/000077500000000000000000000000001461767713300170725ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/000077500000000000000000000000001461767713300200165ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/java/000077500000000000000000000000001461767713300207375ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/java/org/000077500000000000000000000000001461767713300215265ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/000077500000000000000000000000001461767713300231545ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/000077500000000000000000000000001461767713300245715ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/ColumnSixStepFNTStrategy.java000066400000000000000000000064041461767713300323100ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.MatrixStrategy; import org.apfloat.spi.NTTStepStrategy; import org.apfloat.internal.SixStepFNTStrategy; /** * Six-step NTT implementation that processes the data in the columns of the matrix.

* * This transform only works together with an {@link NTTStepStrategy} implementation * that processes the data in columns instead of rows and a {@link MatrixStrategy} * implementation that can transpose the data.

* * The data size should be sufficiently large to meet the parallelization needs of the GPU. * The GPU global size i.e. the number of columns in the data matrix should be at least 1024. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class ColumnSixStepFNTStrategy extends SixStepFNTStrategy { /** * Basic constructor. * * @param stepStrategy A step strategy that can process data in columns. * @param matrixStrategy A matrix strategy that can process the data. */ public ColumnSixStepFNTStrategy(NTTStepStrategy stepStrategy, MatrixStrategy matrixStrategy) { super.stepStrategy = stepStrategy; super.matrixStrategy = matrixStrategy; } @Override protected void transposeInitial(ArrayAccess arrayAccess, int n1, int n2, boolean isInverse) { // Omitted as we want to process the columns, not rows } @Override protected void transposeMiddle(ArrayAccess arrayAccess, int n1, int n2, boolean isInverse) { // Matrix is in transposed form compared to the normal six-step algorithm, so swap n1 and n2 super.transposeMiddle(arrayAccess, n2, n1, isInverse); } @Override protected void multiplyElements(ArrayAccess arrayAccess, int rows, int columns, long length, long totalTransformLength, boolean isInverse, int modulus) { // Matrix is in transposed form compared to the normal six-step algorithm, so swap rows and columns super.multiplyElements(arrayAccess, columns, rows, length, totalTransformLength, isInverse, modulus); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/ColumnTwoPassFNTStrategy.java000066400000000000000000000071061461767713300323110ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.internal.TwoPassFNTStrategy; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.DataStorage; import org.apfloat.spi.NTTStepStrategy; /** * Two-pass NTT implementation that processes the data in the columns of the matrix.

* * This transform only works together with an {@link NTTStepStrategy} implementation * that processes the data in columns instead of rows.

* * Note that if the data size is too big compared to the maximum available memory then the * data is read from disk in too thin slices and the level of parallelism may become too * small for the GPU, ruining the performance. The GPU global size i.e. the number of columns * read from the data matrix to memory at one time should be at least 1024. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class ColumnTwoPassFNTStrategy extends TwoPassFNTStrategy { /** * Basic constructor. * * @param stepStrategy A step strategy that can process data in columns. */ public ColumnTwoPassFNTStrategy(NTTStepStrategy stepStrategy) { // Note that there is no defaultStrategy here; if we get to the two-pass algorithm then we // assume that the data size is always "big enough" for a sufficient level of parallelism on the GPU super.stepStrategy = stepStrategy; } @Override protected ArrayAccess getColumns(DataStorage dataStorage, int startColumn, int columns, int rows) { // Get columns un-transposed return dataStorage.getArray(DataStorage.READ_WRITE, startColumn, columns, rows); } @Override protected ArrayAccess getRows(DataStorage dataStorage, int startRow, int rows, int columns) { // Get rows transposed as we want to organize the data in columns return dataStorage.subsequence(startRow * columns, rows * columns).getTransposedArray(DataStorage.READ_WRITE, 0, columns, rows); } @Override protected void multiplyElements(ArrayAccess arrayAccess, int startRow, int startColumn, int rows, int columns, long length, long totalTransformLength, boolean isInverse, int modulus) { // Data is processed in transposed form compared to the normal two-pass algorithm, so swap rows and columns super.multiplyElements(arrayAccess, startColumn, startRow, columns, rows, length, totalTransformLength, isInverse, modulus); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/IntAparapiBuilderFactory.java000066400000000000000000000034501461767713300323250ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.spi.NTTBuilder; import org.apfloat.internal.IntBuilderFactory; /** * Builder factory for aparapi transform implementations for the int element type. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class IntAparapiBuilderFactory extends IntBuilderFactory { /** * Default constructor. */ public IntAparapiBuilderFactory() { } @Override public NTTBuilder getNTTBuilder() { return IntAparapiBuilderFactory.nttBuilder; } private static NTTBuilder nttBuilder = new IntAparapiNTTBuilder(); } IntAparapiFactor3NTTStepStrategy.java000066400000000000000000000103541461767713300335770ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.DataStorage; import com.aparapi.Range; import org.apfloat.internal.ApfloatInternalException; import org.apfloat.internal.IntFactor3NTTStepStrategy; import static org.apfloat.internal.IntModConstants.*; /** * Steps for the factor-3 NTT using the GPU, for the int element type.

* * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class IntAparapiFactor3NTTStepStrategy extends IntFactor3NTTStepStrategy { @Override public void transformColumns(DataStorage dataStorage0, DataStorage dataStorage1, DataStorage dataStorage2, long startColumn, long columns, long power2length, long length, boolean isInverse, int modulus) throws ApfloatRuntimeException { // Transform length is three times a power of two assert (length == 3 * power2length); // Check that the data storages use consecutive sections of the same memory array if (!dataStorage0.isCached() || !dataStorage1.isCached() || !dataStorage2.isCached() || startColumn > Integer.MAX_VALUE || columns > Integer.MAX_VALUE) { throw new ApfloatInternalException("Data must be stored in memory"); } ArrayAccess arrayAccess0 = dataStorage0.getArray(DataStorage.READ_WRITE, startColumn, (int) columns), arrayAccess1 = dataStorage1.getArray(DataStorage.READ_WRITE, startColumn, (int) columns), arrayAccess2 = dataStorage2.getArray(DataStorage.READ_WRITE, startColumn, (int) columns); if (arrayAccess0.getIntData() != arrayAccess1.getIntData() || arrayAccess1.getIntData() != arrayAccess2.getIntData() || arrayAccess1.getOffset() != arrayAccess0.getOffset() + columns || arrayAccess2.getOffset() != arrayAccess1.getOffset() + columns) { throw new ApfloatInternalException("Data must be stored consecutively in memory"); } setModulus(MODULUS[modulus]); // Modulus int w = (isInverse ? getInverseNthRoot(PRIMITIVE_ROOT[modulus], length) : getForwardNthRoot(PRIMITIVE_ROOT[modulus], length)), // Forward/inverse n:th root w3 = modPow(w, (int) power2length), // Forward/inverse 3rd root ww = modMultiply(w, w), w1 = negate(modDivide((int) 3, (int) 2)), w2 = modAdd(w3, modDivide((int) 1, (int) 2)); IntKernel kernel = IntKernel.getInstance(); kernel.setOp(isInverse ? IntKernel.INVERSE_TRANSFORM_COLUMNS : IntKernel.TRANSFORM_COLUMNS); kernel.setArrayAccess(arrayAccess0); kernel.setStartColumn((int) startColumn); kernel.setColumns((int) columns); kernel.setW(w); kernel.setWw(ww); kernel.setW1(w1); kernel.setW2(w2); kernel.setModulus(MODULUS[modulus]); Range range = RangeHelper.create((int) columns); kernel.execute(range); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/IntAparapiFactor3NTTStrategy.java000066400000000000000000000065521461767713300330270ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.DataStorage; import org.apfloat.internal.ApfloatInternalException; import org.apfloat.internal.Factor3NTTStrategy; /** * Factor-3 NTT implementation for the int element type.

* * @since 1.8.3 * @version 1.9.0 * @author Mikko Tommila */ public class IntAparapiFactor3NTTStrategy extends Factor3NTTStrategy { /** * Default constructor. */ public IntAparapiFactor3NTTStrategy() { super(new ColumnSixStepFNTStrategy(new IntAparapiNTTStepStrategy(), new IntAparapiMatrixStrategy())); super.stepStrategy = new IntAparapiFactor3NTTStepStrategy(); } @Override public void transform(DataStorage dataStorage, int modulus) throws ApfloatRuntimeException { preTransform(dataStorage); super.transform(dataStorage, modulus); postTransform(dataStorage); } @Override public void inverseTransform(DataStorage dataStorage, int modulus, long totalTransformLength) throws ApfloatRuntimeException { preTransform(dataStorage); super.inverseTransform(dataStorage, modulus, totalTransformLength); postTransform(dataStorage); } private void preTransform(DataStorage dataStorage) { long length = dataStorage.getSize(); if (length > Integer.MAX_VALUE) { throw new ApfloatInternalException("Maximum array length exceeded: " + length); } ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ_WRITE, 0, (int) length); IntKernel kernel = IntKernel.getInstance(); kernel.setExplicit(true); kernel.put(arrayAccess.getIntData()); } private void postTransform(DataStorage dataStorage) { long length = dataStorage.getSize(); assert (length <= Integer.MAX_VALUE); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ_WRITE, 0, (int) length); IntKernel kernel = IntKernel.getInstance(); kernel.get(arrayAccess.getIntData()); kernel.cleanUpArrays(); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/IntAparapiMatrixStrategy.java000066400000000000000000000154141461767713300324010ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.MatrixStrategy; import org.apfloat.internal.ApfloatInternalException; import com.aparapi.Range; /** * Matrix transposition in the GPU for the int type. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class IntAparapiMatrixStrategy implements MatrixStrategy { /** * Default constructor. */ public IntAparapiMatrixStrategy() { } @Override public void transpose(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { if (n1 != (n1 & -n1) || n2 != (n2 & -n2) || n1 <= 0 || n2 <= 0) { throw new ApfloatInternalException("Matrix size must be a power of two, not " + n1 + " x " + n2); } if (n1 == n2) { // Simply transpose transposeSquare(arrayAccess, n1, n1); } else if (n2 == 2 * n1) { // First transpose two n1 x n1 blocks transposeSquare(arrayAccess, n1, n2); transposeSquare(arrayAccess.subsequence(n1, arrayAccess.getLength() - n1), n1, n2); // Then permute the rows to correct order permuteToHalfWidth(arrayAccess, n1, n2); } else if (n1 == 2 * n2) { // First permute the rows to correct order permuteToDoubleWidth(arrayAccess, n1, n2); // Then transpose two n2 x n2 blocks transposeSquare(arrayAccess, n2, n1); transposeSquare(arrayAccess.subsequence(n2, arrayAccess.getLength() - n2), n2, n1); } else { throw new ApfloatInternalException("Must be n1 = n2, n1 = 2*n2 or n2 = 2*n1; matrix is " + n1 + " x " + n2); } } @Override public void transposeSquare(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { IntKernel kernel = IntKernel.getInstance(); kernel.setOp(IntKernel.TRANSPOSE); kernel.setArrayAccess(arrayAccess); kernel.setN2(n2); Range range = RangeHelper.create2D(n1, n1); kernel.execute(range); } @Override public void permuteToHalfWidth(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { if (n1 != (n1 & -n1) || n2 != (n2 & -n2) || n1 <= 0 || n2 <= 0) { throw new ApfloatInternalException("Matrix size must be a power of two, not " + n1 + " x " + n2); } // Permute the rows of matrix to correct order, to make the n1 x n2 matrix half as wide (2*n1 x n2/2) if (n1 < 2) { return; } int twicen1 = 2 * n1; boolean[] isRowDone = new boolean[twicen1]; int[] index = new int[twicen1 * 2]; // Overly big but twicen1 just isn't enough int j = 1, p = 0; do { int m = j; index[p++] = m; isRowDone[m] = true; m = (m < n1 ? 2 * m : 2 * (m - n1) + 1); while (m != j) { isRowDone[m] = true; index[p++] = m; m = (m < n1 ? 2 * m : 2 * (m - n1) + 1); } index[p++] = 0; while (isRowDone[j]) { j++; } } while (j < twicen1 - 1); IntKernel kernel = IntKernel.getInstance(); kernel.setOp(IntKernel.PERMUTE); kernel.setArrayAccess(arrayAccess); kernel.setN2(n2 / 2); kernel.setIndex(index); kernel.setIndexCount(p); kernel.put(index); Range range = RangeHelper.create(n2 / 2); kernel.execute(range); } @Override public void permuteToDoubleWidth(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { if (n1 != (n1 & -n1) || n2 != (n2 & -n2) || n1 <= 0 || n2 <= 0) { throw new ApfloatInternalException("Matrix size must be a power of two, not " + n1 + " x " + n2); } if (n1 < 2) { throw new ApfloatInternalException("Matrix height must be at least 2."); } // Permute the rows of matrix to correct order, to make the n1 x n2 matrix twice as wide (n1/2 x 2*n2) if (n1 < 4) { return; } int halfn1 = n1 / 2; boolean[] isRowDone = new boolean[n1]; int[] index = new int[n1 * 2]; // Overly big but n1 just isn't enough int j = 1, p = 0; do { int m = j; index[p++] = m; isRowDone[m] = true; m = ((m & 1) != 0 ? m / 2 + halfn1 : m / 2); while (m != j) { isRowDone[m] = true; index[p++] = m; m = ((m & 1) != 0 ? m / 2 + halfn1 : m / 2); } index[p++] = 0; while (isRowDone[j]) { j++; } } while (j < n1 - 1); IntKernel kernel = IntKernel.getInstance(); kernel.setOp(IntKernel.PERMUTE); kernel.setArrayAccess(arrayAccess); kernel.setN2(n2); kernel.setIndex(index); kernel.setIndexCount(p); kernel.put(index); Range range = RangeHelper.create(n2); kernel.execute(range); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/IntAparapiNTTBuilder.java000066400000000000000000000057371461767713300313750ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.spi.BuilderFactory; import org.apfloat.spi.NTTStrategy; import org.apfloat.ApfloatContext; import org.apfloat.internal.IntNTTBuilder; /** * NTT Builder for aparapi transform implementations for the int element type. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class IntAparapiNTTBuilder extends IntNTTBuilder { private static final int MIN_GPU_LENGTH = 1048576; /** * Default constructor. */ public IntAparapiNTTBuilder() { } @Override protected NTTStrategy createSixStepFNTStrategy(long size) { long length = size; if (length < MIN_GPU_LENGTH) { return super.createSixStepFNTStrategy(size); } return new IntAparapiSixStepFNTStrategy(); } @Override protected NTTStrategy createTwoPassFNTStrategy(long size) { long length = size; if (length < MIN_GPU_LENGTH) { return super.createTwoPassFNTStrategy(size); } return new ColumnTwoPassFNTStrategy(new IntAparapiNTTStepStrategy()); } @Override protected NTTStrategy createFactor3NTTStrategy(long size, NTTStrategy nttStrategy) { if (nttStrategy instanceof IntAparapiSixStepFNTStrategy) { ApfloatContext ctx = ApfloatContext.getContext(); BuilderFactory builderFactory = ctx.getBuilderFactory(); long maxMemoryBlockSize = ctx.getMaxMemoryBlockSize() / builderFactory.getElementSize(); if (size <= maxMemoryBlockSize && size <= Integer.MAX_VALUE) { return new IntAparapiFactor3NTTStrategy(); } } return super.createFactor3NTTStrategy(size, nttStrategy); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/IntAparapiNTTStepStrategy.java000066400000000000000000000112011461767713300324240ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import com.aparapi.Range; import org.apfloat.internal.IntNTTStepStrategy; import org.apfloat.internal.IntWTables; import org.apfloat.internal.Scramble; import static org.apfloat.internal.IntModConstants.*; /** * NTT steps for the int element type aparapi transforms. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class IntAparapiNTTStepStrategy extends IntNTTStepStrategy { /** * Default constructor. */ public IntAparapiNTTStepStrategy() { } @Override public void multiplyElements(ArrayAccess arrayAccess, int startRow, int startColumn, int rows, int columns, long length, long totalTransformLength, boolean isInverse, int modulus) throws ApfloatRuntimeException { setModulus(MODULUS[modulus]); int w = (isInverse ? getInverseNthRoot(PRIMITIVE_ROOT[modulus], length) : getForwardNthRoot(PRIMITIVE_ROOT[modulus], length)); int scaleFactor = (isInverse ? modDivide((int) 1, (int) totalTransformLength) : (int) 1); IntKernel kernel = IntKernel.getInstance(); kernel.setOp(IntKernel.MULTIPLY_ELEMENTS); kernel.setArrayAccess(arrayAccess); kernel.setStartRow(startRow); kernel.setStartColumn(startColumn); kernel.setRows(rows); kernel.setColumns(columns); kernel.setW(w); kernel.setScaleFactor(scaleFactor); kernel.setModulus(MODULUS[modulus]); Range range = RangeHelper.create(columns); kernel.execute(range); } /** * Transform the columns of the data matrix. Note that this method expects the data * to be organized in columns, not rows. The arguments length and * count still mean the length of one transform and number of transforms * to be done. * * @param arrayAccess The memory array to split to columns and to transform. * @param length Length of one transform (one columns). * @param count Number of columns. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param permute If permutation should be done. * @param modulus Index of the modulus. */ @Override public void transformRows(ArrayAccess arrayAccess, int length, int count, boolean isInverse, boolean permute, int modulus) throws ApfloatRuntimeException { int[] wTable = (isInverse ? IntWTables.getInverseWTable(modulus, length) : IntWTables.getWTable(modulus, length)); int[] permutationTable = (permute ? Scramble.createScrambleTable(length) : null); IntKernel kernel = IntKernel.getInstance(); kernel.setOp(isInverse ? IntKernel.INVERSE_TRANSFORM_ROWS : IntKernel.TRANSFORM_ROWS); kernel.setLength(length); kernel.setArrayAccess(arrayAccess); kernel.setWTable(wTable); kernel.setPermutationTable(permutationTable); kernel.setModulus(MODULUS[modulus]); kernel.put(wTable); if (permutationTable != null) { kernel.put(permutationTable); } Range range = RangeHelper.create(count); kernel.execute(range); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/IntAparapiSixStepFNTStrategy.java000066400000000000000000000042251461767713300331020ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.spi.ArrayAccess; /** * Six-step NTT implementation for the int element type.

* * @since 1.8.3 * @version 1.9.0 * @author Mikko Tommila */ public class IntAparapiSixStepFNTStrategy extends ColumnSixStepFNTStrategy { /** * Default constructor. */ public IntAparapiSixStepFNTStrategy() { super(new IntAparapiNTTStepStrategy(), new IntAparapiMatrixStrategy()); } @Override protected void preTransform(ArrayAccess arrayAccess) { IntKernel kernel = IntKernel.getInstance(); kernel.setExplicit(true); kernel.put(arrayAccess.getIntData()); super.preTransform(arrayAccess); } @Override protected void postTransform(ArrayAccess arrayAccess) { super.postTransform(arrayAccess); IntKernel kernel = IntKernel.getInstance(); kernel.get(arrayAccess.getIntData()); kernel.cleanUpArrays(); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/IntKernel.java000066400000000000000000000352561461767713300273420ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import com.aparapi.Kernel; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; /** * Kernel for the int element type. Contains everything needed for the NTT. * The data is organized in columns, not rows, for efficient processing on the GPU.

* * Due to the extreme parallelization requirements (global size should be at lest 1024) * this algorithm works efficiently only with 4 million decimal digit calculations or bigger. * However with 4 million digits, it's only approximately as fast as the pure-Java * version (depending on the GPU and CPU hardware). On the other hand, the algorithm * mathematically only works up to about 226 million digits. So the useful range is only * somewhere around 10-200 million digits.

* * Some notes about the aparapi specific requirements for code that must be converted to OpenCL: *

* * @since 1.8.3 * @version 1.9.0 * @author Mikko Tommila */ class IntKernel extends Kernel { private IntKernel() { } public static IntKernel getInstance() { return IntKernel.kernel.get(); } private static ThreadLocal kernel = ThreadLocal.withInitial(IntKernel::new); // Methods for calculating the column transforms in parallel public static final int TRANSFORM_ROWS = 1; public static final int INVERSE_TRANSFORM_ROWS = 2; public void setLength(int length) { this.length = length; // Transform length } public void setArrayAccess(ArrayAccess arrayAccess) throws ApfloatRuntimeException { this.data = arrayAccess.getIntData(); this.offset = arrayAccess.getOffset(); if (this.length != 0) { this.stride = arrayAccess.getLength() / this.length; } } public void setWTable(int[] wTable) { this.wTable = wTable; } public void setPermutationTable(int[] permutationTable) { this.permutationTable = (permutationTable == null ? new int[1] : permutationTable); // Zero-length array or null won't work this.permutationTableLength = (permutationTable == null ? 0 : permutationTable.length); } private void columnTableFNT() { int nn, istep = 0, mmax = 0, r = 0; int[] data = this.data; int offset = this.offset + getGlobalId(); int stride = this.stride; nn = this.length; if (nn >= 2) { r = 1; mmax = nn >> 1; while (mmax > 0) { istep = mmax << 1; // Optimize first step when wr = 1 for (int i = offset; i < offset + nn * stride; i += istep * stride) { int j = i + mmax * stride; int a = data[i]; int b = data[j]; data[i] = modAdd(a, b); data[j] = modSubtract(a, b); } int t = r; for (int m = 1; m < mmax; m++) { for (int i = offset + m * stride; i < offset + nn * stride; i += istep * stride) { int j = i + mmax * stride; int a = data[i]; int b = data[j]; data[i] = modAdd(a, b); data[j] = modMultiply(this.wTable[t], modSubtract(a, b)); } t += r; } r <<= 1; mmax >>= 1; } if (this.permutationTableLength > 0) { columnScramble(offset); } } } private void inverseColumnTableFNT() { int nn, istep = 0, mmax = 0, r = 0; int[] data = this.data; int offset = this.offset + getGlobalId(); int stride = this.stride; nn = this.length; if (nn >= 2) { if (this.permutationTableLength > 0) { columnScramble(offset); } r = nn; mmax = 1; while (nn > mmax) { istep = mmax << 1; r >>= 1; // Optimize first step when w = 1 for (int i = offset; i < offset + nn * stride; i += istep * stride) { int j = i + mmax * stride; int wTemp = data[j]; data[j] = modSubtract(data[i], wTemp); data[i] = modAdd(data[i], wTemp); } int t = r; for (int m = 1; m < mmax; m++) { for (int i = offset + m * stride; i < offset + nn * stride; i += istep * stride) { int j = i + mmax * stride; int wTemp = modMultiply(this.wTable[t], data[j]); data[j] = modSubtract(data[i], wTemp); data[i] = modAdd(data[i], wTemp); } t += r; } mmax = istep; } } } private void columnScramble(int offset) { for (int k = 0; k < this.permutationTableLength; k += 2) { int i = offset + this.permutationTable[k] * this.stride, j = offset + this.permutationTable[k + 1] * this.stride; int tmp = this.data[i]; this.data[i] = this.data[j]; this.data[j] = tmp; } } private int modMultiply(int a, int b) { long t = (long) a * (long) b; //int r1 = a * b - (int) (this.inverseModulus * (double) a * (double) b) * this.modulus, int r1 = (int) t - (int) ((t >>> 30) * this.inverseModulus >>> 33) * this.modulus, r2 = r1 - this.modulus; return (r2 < 0 ? r1 : r2); } private int modAdd(int a, int b) { int r1 = a + b, r2 = r1 - this.modulus; return (r2 < 0 ? r1 : r2); } private int modSubtract(int a, int b) { int r1 = a - b, r2 = r1 + this.modulus; return (r1 < 0 ? r2 : r1); } public void setModulus(int modulus) { //this.inverseModulus = 1.0 / (modulus + 0.5); // Round down this.inverseModulus = (long) (9223372036854775808.0 / (double) modulus); this.modulus = modulus; } public int getModulus() { return this.modulus; } private int stride; private int length; private int[] data; private int offset; private int[] wTable = { 0 }; private int[] permutationTable = { 0 }; private int permutationTableLength; private int modulus; //private double inverseModulus; private long inverseModulus; // Methods for transposing the matrix public static final int TRANSPOSE = 3; public static final int PERMUTE = 4; public void setN2(int n2) { this.n2 = n2; } public void setIndex(int[] index) { this.index = index; } public void setIndexCount(int indexCount) { this.indexCount = indexCount; } private void transpose() { int i = getGlobalId(0), j = getGlobalId(1); if (i < j) { int position1 = this.offset + j * this.n2 + i, position2 = this.offset + i * this.n2 + j; int tmp = this.data[position1]; this.data[position1] = this.data[position2]; this.data[position2] = tmp; } } private void permute() { int j = getGlobalId(); for (int i = 0; i < this.indexCount; i++) { int o = this.index[i]; int tmp = this.data[this.offset + this.n2 * o + j]; for (i++; this.index[i] != 0; i++) { int m = this.index[i]; this.data[this.offset + this.n2 * o + j] = this.data[this.offset + this.n2 * m + j]; o = m; } this.data[this.offset + this.n2 * o + j] = tmp; } } private int n2; private int[] index = { 0 }; private int indexCount; // Methods for multiplying elements in the matrix public static final int MULTIPLY_ELEMENTS = 5; public void setStartRow(int startRow) { this.startRow = startRow; } public void setStartColumn(int startColumn) { this.startColumn = startColumn; } public void setRows(int rows) { this.rows = rows; } public void setColumns(int columns) { this.columns = columns; } public void setW(int w) { this.w = w; } public void setScaleFactor(int scaleFactor) { this.scaleFactor = scaleFactor; } private void multiplyElements() { int[] data = this.data; int position = this.offset + getGlobalId(); int rowFactor = modPow(this.w, (int) this.startRow); int columnFactor = modPow(this.w, (int) this.startColumn + getGlobalId()); int rowStartFactor = modMultiply(this.scaleFactor, modPow(rowFactor, (int) this.startColumn + getGlobalId())); for (int i = 0; i < this.rows; i++) { data[position] = modMultiply(data[position], rowStartFactor); position += this.columns; rowStartFactor = modMultiply(rowStartFactor, columnFactor); } } private int modPow(int a, int n) { if (n == 0) { return 1; } else if (n < 0) { n = getModulus() - 1 + n; } int exponent = (int) n; while ((exponent & 1) == 0) { a = modMultiply(a, a); exponent >>= 1; } int r = a; for (exponent >>= 1; exponent > 0; exponent >>= 1) { a = modMultiply(a, a); if ((exponent & 1) != 0) { r = modMultiply(r, a); } } return r; } private int startRow; private int startColumn; private int rows; private int columns; private int w; private int scaleFactor; // Methods for factor-3 transform public static final int TRANSFORM_COLUMNS = 6; public static final int INVERSE_TRANSFORM_COLUMNS = 7; public void setOp(int op) { this.op = op; } public void setWw(int ww) { this.ww = ww; } public void setW1(int w1) { this.w1 = w1; } public void setW2(int w2) { this.w2 = w2; } @Override public void run() { if (this.op == TRANSFORM_ROWS) { columnTableFNT(); } else if (this.op == INVERSE_TRANSFORM_ROWS) { inverseColumnTableFNT(); } else if (this.op == TRANSPOSE) { transpose(); } else if (this.op == PERMUTE) { permute(); } else if (this.op == MULTIPLY_ELEMENTS) { multiplyElements(); } else if (this.op == TRANSFORM_COLUMNS || this.op == INVERSE_TRANSFORM_COLUMNS) { transformColumns(); } } private void transformColumns() { int i = getGlobalId(); int tmp1 = modPow(this.w, (int) this.startColumn + i), tmp2 = modPow(this.ww, (int) this.startColumn + i); // 3-point WFTA on the corresponding array elements int x0 = this.data[this.offset + i], x1 = this.data[this.offset + this.columns + i], x2 = this.data[this.offset + 2 * this.columns + i], t; if (this.op == INVERSE_TRANSFORM_COLUMNS) { // Multiply before transform x1 = modMultiply(x1, tmp1); x2 = modMultiply(x2, tmp2); } // Transform column t = modAdd(x1, x2); x2 = modSubtract(x1, x2); x0 = modAdd(x0, t); t = modMultiply(t, this.w1); x2 = modMultiply(x2, this.w2); t = modAdd(t, x0); x1 = modAdd(t, x2); x2 = modSubtract(t, x2); if (this.op == TRANSFORM_COLUMNS) { // Multiply after transform x1 = modMultiply(x1, tmp1); x2 = modMultiply(x2, tmp2); } this.data[this.offset + i] = x0; this.data[this.offset + this.columns + i] = x1; this.data[this.offset + 2 * this.columns + i] = x2; } private int op; private int ww; private int w1; private int w2; } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/LongAparapiBuilderFactory.java000066400000000000000000000034571461767713300325010ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.spi.NTTBuilder; import org.apfloat.internal.LongBuilderFactory; /** * Builder factory for aparapi transform implementations for the long element type. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class LongAparapiBuilderFactory extends LongBuilderFactory { /** * Default constructor. */ public LongAparapiBuilderFactory() { } @Override public NTTBuilder getNTTBuilder() { return LongAparapiBuilderFactory.nttBuilder; } private static NTTBuilder nttBuilder = new LongAparapiNTTBuilder(); } LongAparapiFactor3NTTStepStrategy.java000066400000000000000000000104051461767713300337410ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.DataStorage; import com.aparapi.Range; import org.apfloat.internal.ApfloatInternalException; import org.apfloat.internal.LongFactor3NTTStepStrategy; import static org.apfloat.internal.LongModConstants.*; /** * Steps for the factor-3 NTT using the GPU, for the long element type.

* * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class LongAparapiFactor3NTTStepStrategy extends LongFactor3NTTStepStrategy { @Override public void transformColumns(DataStorage dataStorage0, DataStorage dataStorage1, DataStorage dataStorage2, long startColumn, long columns, long power2length, long length, boolean isInverse, int modulus) throws ApfloatRuntimeException { // Transform length is three times a power of two assert (length == 3 * power2length); // Check that the data storages use consecutive sections of the same memory array if (!dataStorage0.isCached() || !dataStorage1.isCached() || !dataStorage2.isCached() || startColumn > Integer.MAX_VALUE || columns > Integer.MAX_VALUE) { throw new ApfloatInternalException("Data must be stored in memory"); } ArrayAccess arrayAccess0 = dataStorage0.getArray(DataStorage.READ_WRITE, startColumn, (int) columns), arrayAccess1 = dataStorage1.getArray(DataStorage.READ_WRITE, startColumn, (int) columns), arrayAccess2 = dataStorage2.getArray(DataStorage.READ_WRITE, startColumn, (int) columns); if (arrayAccess0.getLongData() != arrayAccess1.getLongData() || arrayAccess1.getLongData() != arrayAccess2.getLongData() || arrayAccess1.getOffset() != arrayAccess0.getOffset() + columns || arrayAccess2.getOffset() != arrayAccess1.getOffset() + columns) { throw new ApfloatInternalException("Data must be stored consecutively in memory"); } setModulus(MODULUS[modulus]); // Modulus long w = (isInverse ? getInverseNthRoot(PRIMITIVE_ROOT[modulus], length) : getForwardNthRoot(PRIMITIVE_ROOT[modulus], length)), // Forward/inverse n:th root w3 = modPow(w, (long) power2length), // Forward/inverse 3rd root ww = modMultiply(w, w), w1 = negate(modDivide((long) 3, (long) 2)), w2 = modAdd(w3, modDivide((long) 1, (long) 2)); LongKernel kernel = LongKernel.getInstance(); kernel.setOp(isInverse ? LongKernel.INVERSE_TRANSFORM_COLUMNS : LongKernel.TRANSFORM_COLUMNS); kernel.setArrayAccess(arrayAccess0); kernel.setStartColumn((int) startColumn); kernel.setColumns((int) columns); kernel.setW(w); kernel.setWw(ww); kernel.setW1(w1); kernel.setW2(w2); kernel.setModulus(MODULUS[modulus]); Range range = RangeHelper.create((int) columns); kernel.execute(range); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/LongAparapiFactor3NTTStrategy.java000066400000000000000000000065661461767713300332010ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.DataStorage; import org.apfloat.internal.ApfloatInternalException; import org.apfloat.internal.Factor3NTTStrategy; /** * Factor-3 NTT implementation for the long element type.

* * @since 1.8.3 * @version 1.9.0 * @author Mikko Tommila */ public class LongAparapiFactor3NTTStrategy extends Factor3NTTStrategy { /** * Default constructor. */ public LongAparapiFactor3NTTStrategy() { super(new ColumnSixStepFNTStrategy(new LongAparapiNTTStepStrategy(), new LongAparapiMatrixStrategy())); super.stepStrategy = new LongAparapiFactor3NTTStepStrategy(); } @Override public void transform(DataStorage dataStorage, int modulus) throws ApfloatRuntimeException { preTransform(dataStorage); super.transform(dataStorage, modulus); postTransform(dataStorage); } @Override public void inverseTransform(DataStorage dataStorage, int modulus, long totalTransformLength) throws ApfloatRuntimeException { preTransform(dataStorage); super.inverseTransform(dataStorage, modulus, totalTransformLength); postTransform(dataStorage); } private void preTransform(DataStorage dataStorage) { long length = dataStorage.getSize(); if (length > Integer.MAX_VALUE) { throw new ApfloatInternalException("Maximum array length exceeded: " + length); } ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ_WRITE, 0, (int) length); LongKernel kernel = LongKernel.getInstance(); kernel.setExplicit(true); kernel.put(arrayAccess.getLongData()); } private void postTransform(DataStorage dataStorage) { long length = dataStorage.getSize(); assert (length <= Integer.MAX_VALUE); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ_WRITE, 0, (int) length); LongKernel kernel = LongKernel.getInstance(); kernel.get(arrayAccess.getLongData()); kernel.cleanUpArrays(); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/LongAparapiMatrixStrategy.java000066400000000000000000000154301461767713300325440ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.MatrixStrategy; import org.apfloat.internal.ApfloatInternalException; import com.aparapi.Range; /** * Matrix transposition in the GPU for the long type. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class LongAparapiMatrixStrategy implements MatrixStrategy { /** * Default constructor. */ public LongAparapiMatrixStrategy() { } @Override public void transpose(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { if (n1 != (n1 & -n1) || n2 != (n2 & -n2) || n1 <= 0 || n2 <= 0) { throw new ApfloatInternalException("Matrix size must be a power of two, not " + n1 + " x " + n2); } if (n1 == n2) { // Simply transpose transposeSquare(arrayAccess, n1, n1); } else if (n2 == 2 * n1) { // First transpose two n1 x n1 blocks transposeSquare(arrayAccess, n1, n2); transposeSquare(arrayAccess.subsequence(n1, arrayAccess.getLength() - n1), n1, n2); // Then permute the rows to correct order permuteToHalfWidth(arrayAccess, n1, n2); } else if (n1 == 2 * n2) { // First permute the rows to correct order permuteToDoubleWidth(arrayAccess, n1, n2); // Then transpose two n2 x n2 blocks transposeSquare(arrayAccess, n2, n1); transposeSquare(arrayAccess.subsequence(n2, arrayAccess.getLength() - n2), n2, n1); } else { throw new ApfloatInternalException("Must be n1 = n2, n1 = 2*n2 or n2 = 2*n1; matrix is " + n1 + " x " + n2); } } @Override public void transposeSquare(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { LongKernel kernel = LongKernel.getInstance(); kernel.setOp(LongKernel.TRANSPOSE); kernel.setArrayAccess(arrayAccess); kernel.setN2(n2); Range range = RangeHelper.create2D(n1, n1); kernel.execute(range); } @Override public void permuteToHalfWidth(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { if (n1 != (n1 & -n1) || n2 != (n2 & -n2) || n1 <= 0 || n2 <= 0) { throw new ApfloatInternalException("Matrix size must be a power of two, not " + n1 + " x " + n2); } // Permute the rows of matrix to correct order, to make the n1 x n2 matrix half as wide (2*n1 x n2/2) if (n1 < 2) { return; } int twicen1 = 2 * n1; boolean[] isRowDone = new boolean[twicen1]; int[] index = new int[twicen1 * 2]; // Overly big but twicen1 just isn't enough int j = 1, p = 0; do { int m = j; index[p++] = m; isRowDone[m] = true; m = (m < n1 ? 2 * m : 2 * (m - n1) + 1); while (m != j) { isRowDone[m] = true; index[p++] = m; m = (m < n1 ? 2 * m : 2 * (m - n1) + 1); } index[p++] = 0; while (isRowDone[j]) { j++; } } while (j < twicen1 - 1); LongKernel kernel = LongKernel.getInstance(); kernel.setOp(LongKernel.PERMUTE); kernel.setArrayAccess(arrayAccess); kernel.setN2(n2 / 2); kernel.setIndex(index); kernel.setIndexCount(p); kernel.put(index); Range range = RangeHelper.create(n2 / 2); kernel.execute(range); } @Override public void permuteToDoubleWidth(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { if (n1 != (n1 & -n1) || n2 != (n2 & -n2) || n1 <= 0 || n2 <= 0) { throw new ApfloatInternalException("Matrix size must be a power of two, not " + n1 + " x " + n2); } if (n1 < 2) { throw new ApfloatInternalException("Matrix height must be at least 2."); } // Permute the rows of matrix to correct order, to make the n1 x n2 matrix twice as wide (n1/2 x 2*n2) if (n1 < 4) { return; } int halfn1 = n1 / 2; boolean[] isRowDone = new boolean[n1]; int[] index = new int[n1 * 2]; // Overly big but n1 just isn't enough int j = 1, p = 0; do { int m = j; index[p++] = m; isRowDone[m] = true; m = ((m & 1) != 0 ? m / 2 + halfn1 : m / 2); while (m != j) { isRowDone[m] = true; index[p++] = m; m = ((m & 1) != 0 ? m / 2 + halfn1 : m / 2); } index[p++] = 0; while (isRowDone[j]) { j++; } } while (j < n1 - 1); LongKernel kernel = LongKernel.getInstance(); kernel.setOp(LongKernel.PERMUTE); kernel.setArrayAccess(arrayAccess); kernel.setN2(n2); kernel.setIndex(index); kernel.setIndexCount(p); kernel.put(index); Range range = RangeHelper.create(n2); kernel.execute(range); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/LongAparapiNTTBuilder.java000066400000000000000000000057501461767713300315350ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.spi.BuilderFactory; import org.apfloat.spi.NTTStrategy; import org.apfloat.ApfloatContext; import org.apfloat.internal.LongNTTBuilder; /** * NTT Builder for aparapi transform implementations for the long element type. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class LongAparapiNTTBuilder extends LongNTTBuilder { private static final int MIN_GPU_LENGTH = 1048576; /** * Default constructor. */ public LongAparapiNTTBuilder() { } @Override protected NTTStrategy createSixStepFNTStrategy(long size) { long length = size; if (length < MIN_GPU_LENGTH) { return super.createSixStepFNTStrategy(size); } return new LongAparapiSixStepFNTStrategy(); } @Override protected NTTStrategy createTwoPassFNTStrategy(long size) { long length = size; if (length < MIN_GPU_LENGTH) { return super.createTwoPassFNTStrategy(size); } return new ColumnTwoPassFNTStrategy(new LongAparapiNTTStepStrategy()); } @Override protected NTTStrategy createFactor3NTTStrategy(long size, NTTStrategy nttStrategy) { if (nttStrategy instanceof LongAparapiSixStepFNTStrategy) { ApfloatContext ctx = ApfloatContext.getContext(); BuilderFactory builderFactory = ctx.getBuilderFactory(); long maxMemoryBlockSize = ctx.getMaxMemoryBlockSize() / builderFactory.getElementSize(); if (size <= maxMemoryBlockSize && size <= Integer.MAX_VALUE) { return new LongAparapiFactor3NTTStrategy(); } } return super.createFactor3NTTStrategy(size, nttStrategy); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/LongAparapiNTTStepStrategy.java000066400000000000000000000112351461767713300326000ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import com.aparapi.Range; import org.apfloat.internal.LongNTTStepStrategy; import org.apfloat.internal.LongWTables; import org.apfloat.internal.Scramble; import static org.apfloat.internal.LongModConstants.*; /** * NTT steps for the long element type aparapi transforms. * * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class LongAparapiNTTStepStrategy extends LongNTTStepStrategy { /** * Default constructor. */ public LongAparapiNTTStepStrategy() { } @Override public void multiplyElements(ArrayAccess arrayAccess, int startRow, int startColumn, int rows, int columns, long length, long totalTransformLength, boolean isInverse, int modulus) throws ApfloatRuntimeException { setModulus(MODULUS[modulus]); long w = (isInverse ? getInverseNthRoot(PRIMITIVE_ROOT[modulus], length) : getForwardNthRoot(PRIMITIVE_ROOT[modulus], length)); long scaleFactor = (isInverse ? modDivide((long) 1, (long) totalTransformLength) : (long) 1); LongKernel kernel = LongKernel.getInstance(); kernel.setOp(LongKernel.MULTIPLY_ELEMENTS); kernel.setArrayAccess(arrayAccess); kernel.setStartRow(startRow); kernel.setStartColumn(startColumn); kernel.setRows(rows); kernel.setColumns(columns); kernel.setW(w); kernel.setScaleFactor(scaleFactor); kernel.setModulus(MODULUS[modulus]); Range range = RangeHelper.create(columns); kernel.execute(range); } /** * Transform the columns of the data matrix. Note that this method expects the data * to be organized in columns, not rows. The arguments length and * count still mean the length of one transform and number of transforms * to be done. * * @param arrayAccess The memory array to split to columns and to transform. * @param length Length of one transform (one columns). * @param count Number of columns. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param permute If permutation should be done. * @param modulus Index of the modulus. */ @Override public void transformRows(ArrayAccess arrayAccess, int length, int count, boolean isInverse, boolean permute, int modulus) throws ApfloatRuntimeException { long[] wTable = (isInverse ? LongWTables.getInverseWTable(modulus, length) : LongWTables.getWTable(modulus, length)); int[] permutationTable = (permute ? Scramble.createScrambleTable(length) : null); LongKernel kernel = LongKernel.getInstance(); kernel.setOp(isInverse ? LongKernel.INVERSE_TRANSFORM_ROWS : LongKernel.TRANSFORM_ROWS); kernel.setLength(length); kernel.setArrayAccess(arrayAccess); kernel.setWTable(wTable); kernel.setPermutationTable(permutationTable); kernel.setModulus(MODULUS[modulus]); kernel.put(wTable); if (permutationTable != null) { kernel.put(permutationTable); } Range range = RangeHelper.create(count); kernel.execute(range); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/LongAparapiSixStepFNTStrategy.java000066400000000000000000000042401461767713300332440ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.spi.ArrayAccess; /** * Six-step NTT implementation for the long element type.

* * @since 1.8.3 * @version 1.9.0 * @author Mikko Tommila */ public class LongAparapiSixStepFNTStrategy extends ColumnSixStepFNTStrategy { /** * Default constructor. */ public LongAparapiSixStepFNTStrategy() { super(new LongAparapiNTTStepStrategy(), new LongAparapiMatrixStrategy()); } @Override protected void preTransform(ArrayAccess arrayAccess) { LongKernel kernel = LongKernel.getInstance(); kernel.setExplicit(true); kernel.put(arrayAccess.getLongData()); super.preTransform(arrayAccess); } @Override protected void postTransform(ArrayAccess arrayAccess) { super.postTransform(arrayAccess); LongKernel kernel = LongKernel.getInstance(); kernel.get(arrayAccess.getLongData()); kernel.cleanUpArrays(); } } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/LongKernel.java000066400000000000000000000354661461767713300275120ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import com.aparapi.Kernel; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; /** * Kernel for the long element type. Contains everything needed for the NTT. * The data is organized in columns, not rows, for efficient processing on the GPU. * * Due to the extreme parallelization requirements (global size should be at lest 1024) * this algorithm works efficiently only with 8 million decimal digit calculations or bigger. * However with 8 million digits, it's only approximately as fast as the pure-Java * version (depending on the GPU and CPU hardware). Depending on the total amount of memory * available for the GPU this algorithm will fail (or revert to the very slow software emulation) * e.g. at one-billion-digit calculations if your GPU has 1 GB of memory. The maximum power-of-two * size for a Java array is one billion (230) so if your GPU has more than 8 GB of * memory then the algorithm can never fail (as any Java long[] will always fit to the GPU memory).

* * Some notes about the aparapi specific requirements for code that must be converted to OpenCL: *

* * @since 1.8.3 * @version 1.9.0 * @author Mikko Tommila */ class LongKernel extends Kernel { private LongKernel() { } public static LongKernel getInstance() { return LongKernel.kernel.get(); } private static ThreadLocal kernel = ThreadLocal.withInitial(LongKernel::new); // Methods for calculating the column transforms in parallel public static final int TRANSFORM_ROWS = 1; public static final int INVERSE_TRANSFORM_ROWS = 2; public void setLength(int length) { this.length = length; // Transform length } public void setArrayAccess(ArrayAccess arrayAccess) throws ApfloatRuntimeException { this.data = arrayAccess.getLongData(); this.offset = arrayAccess.getOffset(); if (this.length != 0) { this.stride = arrayAccess.getLength() / this.length; } } public void setWTable(long[] wTable) { this.wTable = wTable; } public void setPermutationTable(int[] permutationTable) { this.permutationTable = (permutationTable == null ? new int[1] : permutationTable); // Zero-length array or null won't work this.permutationTableLength = (permutationTable == null ? 0 : permutationTable.length); } private void columnTableFNT() { int nn, istep = 0, mmax = 0, r = 0; long[] data = this.data; int offset = this.offset + getGlobalId(); int stride = this.stride; nn = this.length; if (nn >= 2) { r = 1; mmax = nn >> 1; while (mmax > 0) { istep = mmax << 1; // Optimize first step when wr = 1 for (int i = offset; i < offset + nn * stride; i += istep * stride) { int j = i + mmax * stride; long a = data[i]; long b = data[j]; data[i] = modAdd(a, b); data[j] = modSubtract(a, b); } int t = r; for (int m = 1; m < mmax; m++) { for (int i = offset + m * stride; i < offset + nn * stride; i += istep * stride) { int j = i + mmax * stride; long a = data[i]; long b = data[j]; data[i] = modAdd(a, b); data[j] = modMultiply(this.wTable[t], modSubtract(a, b)); } t += r; } r <<= 1; mmax >>= 1; } if (this.permutationTableLength > 0) { columnScramble(offset); } } } private void inverseColumnTableFNT() { int nn, istep = 0, mmax = 0, r = 0; long[] data = this.data; int offset = this.offset + getGlobalId(); int stride = this.stride; nn = this.length; if (nn >= 2) { if (this.permutationTableLength > 0) { columnScramble(offset); } r = nn; mmax = 1; while (nn > mmax) { istep = mmax << 1; r >>= 1; // Optimize first step when w = 1 for (int i = offset; i < offset + nn * stride; i += istep * stride) { int j = i + mmax * stride; long wTemp = data[j]; data[j] = modSubtract(data[i], wTemp); data[i] = modAdd(data[i], wTemp); } int t = r; for (int m = 1; m < mmax; m++) { for (int i = offset + m * stride; i < offset + nn * stride; i += istep * stride) { int j = i + mmax * stride; long wTemp = modMultiply(this.wTable[t], data[j]); data[j] = modSubtract(data[i], wTemp); data[i] = modAdd(data[i], wTemp); } t += r; } mmax = istep; } } } private void columnScramble(int offset) { for (int k = 0; k < this.permutationTableLength; k += 2) { int i = offset + this.permutationTable[k] * this.stride, j = offset + this.permutationTable[k + 1] * this.stride; long tmp = this.data[i]; this.data[i] = this.data[j]; this.data[j] = tmp; } } private long modMultiply(long a, long b) { long r = a * b - this.modulus * (long) ((double) a * (double) b * this.inverseModulus); r -= this.modulus * (int) ((double) r * this.inverseModulus); r = (r >= this.modulus ? r - this.modulus : r); r = (r < 0 ? r + this.modulus : r); return r; } private long modAdd(long a, long b) { long r = a + b; return (r >= this.modulus ? r - this.modulus : r); } private long modSubtract(long a, long b) { long r = a - b; return (r < 0 ? r + this.modulus : r); } public void setModulus(long modulus) { this.inverseModulus = 1.0 / modulus; this.modulus = modulus; } public long getModulus() { return this.modulus; } private int stride; private int length; private long[] data; private int offset; private long[] wTable = { 0 }; private int[] permutationTable = { 0 }; private int permutationTableLength; private long modulus; private double inverseModulus; // Methods for transposing the matrix public static final int TRANSPOSE = 3; public static final int PERMUTE = 4; public void setN2(int n2) { this.n2 = n2; } public void setIndex(int[] index) { this.index = index; } public void setIndexCount(int indexCount) { this.indexCount = indexCount; } private void transpose() { int i = getGlobalId(0), j = getGlobalId(1); if (i < j) { int position1 = this.offset + j * this.n2 + i, position2 = this.offset + i * this.n2 + j; long tmp = this.data[position1]; this.data[position1] = this.data[position2]; this.data[position2] = tmp; } } private void permute() { int j = getGlobalId(); for (int i = 0; i < this.indexCount; i++) { int o = this.index[i]; long tmp = this.data[this.offset + this.n2 * o + j]; for (i++; this.index[i] != 0; i++) { int m = this.index[i]; this.data[this.offset + this.n2 * o + j] = this.data[this.offset + this.n2 * m + j]; o = m; } this.data[this.offset + this.n2 * o + j] = tmp; } } private int n2; private int[] index = { 0 }; private int indexCount; // Methods for multiplying elements in the matrix public static final int MULTIPLY_ELEMENTS = 5; public void setStartRow(int startRow) { this.startRow = startRow; } public void setStartColumn(int startColumn) { this.startColumn = startColumn; } public void setRows(int rows) { this.rows = rows; } public void setColumns(int columns) { this.columns = columns; } public void setW(long w) { this.w = w; } public void setScaleFactor(long scaleFactor) { this.scaleFactor = scaleFactor; } private void multiplyElements() { long[] data = this.data; int position = this.offset + getGlobalId(); long rowFactor = modPow(this.w, (long) this.startRow); long columnFactor = modPow(this.w, (long) this.startColumn + getGlobalId()); long rowStartFactor = modMultiply(this.scaleFactor, modPow(rowFactor, (long) this.startColumn + getGlobalId())); for (int i = 0; i < this.rows; i++) { data[position] = modMultiply(data[position], rowStartFactor); position += this.columns; rowStartFactor = modMultiply(rowStartFactor, columnFactor); } } private long modPow(long a, long n) { if (n == 0) { return 1; } else if (n < 0) { n = getModulus() - 1 + n; } long exponent = (long) n; while ((exponent & 1) == 0) { a = modMultiply(a, a); exponent >>= 1; } long r = a; for (exponent >>= 1; exponent > 0; exponent >>= 1) { a = modMultiply(a, a); if ((exponent & 1) != 0) { r = modMultiply(r, a); } } return r; } private int startRow; private int startColumn; private int rows; private int columns; private long w; private long scaleFactor; // Methods for factor-3 transform public static final int TRANSFORM_COLUMNS = 6; public static final int INVERSE_TRANSFORM_COLUMNS = 7; public void setOp(int op) { this.op = op; } public void setWw(long ww) { this.ww = ww; } public void setW1(long w1) { this.w1 = w1; } public void setW2(long w2) { this.w2 = w2; } @Override public void run() { if (this.op == TRANSFORM_ROWS) { columnTableFNT(); } else if (this.op == INVERSE_TRANSFORM_ROWS) { inverseColumnTableFNT(); } else if (this.op == TRANSPOSE) { transpose(); } else if (this.op == PERMUTE) { permute(); } else if (this.op == MULTIPLY_ELEMENTS) { multiplyElements(); } else if (this.op == TRANSFORM_COLUMNS || this.op == INVERSE_TRANSFORM_COLUMNS) { transformColumns(); } } private void transformColumns() { int i = getGlobalId(); long tmp1 = modPow(this.w, (long) this.startColumn + i), tmp2 = modPow(this.ww, (long) this.startColumn + i); // 3-point WFTA on the corresponding array elements long x0 = this.data[this.offset + i], x1 = this.data[this.offset + this.columns + i], x2 = this.data[this.offset + 2 * this.columns + i], t; if (this.op == INVERSE_TRANSFORM_COLUMNS) { // Multiply before transform x1 = modMultiply(x1, tmp1); x2 = modMultiply(x2, tmp2); } // Transform column t = modAdd(x1, x2); x2 = modSubtract(x1, x2); x0 = modAdd(x0, t); t = modMultiply(t, this.w1); x2 = modMultiply(x2, this.w2); t = modAdd(t, x0); x1 = modAdd(t, x2); x2 = modSubtract(t, x2); if (this.op == TRANSFORM_COLUMNS) { // Multiply after transform x1 = modMultiply(x1, tmp1); x2 = modMultiply(x2, tmp2); } this.data[this.offset + i] = x0; this.data[this.offset + this.columns + i] = x1; this.data[this.offset + 2 * this.columns + i] = x2; } private int op; private long ww; private long w1; private long w2; } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/RangeHelper.java000066400000000000000000000052011461767713300276260ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import com.aparapi.Range; /** * Range helper methods. * * @since 1.11.0 * * @author Mikko Tommila */ class RangeHelper { // Note: it seems that this class is just a workaround to aparapi issue #171 where the local size is sometimes not set correctly // See: https://github.com/Syncleus/aparapi/issues/171 private RangeHelper() { } /** * Creates a one-dimensional range with the maximum local size. * * @param size The size. * * @return The range. */ public static Range create(int size) { assert (size == (size & -size)); // Must be a power of two int localSize = Math.min(size, MAX_LOCAL_SIZE); return Range.create(size, localSize); } /** * Creates a two-dimensional range with the maximum local sizes. * * @param width Size of the first dimension. * @param height Size of the second dimension. * * @return The range. */ public static Range create2D(int width, int height) { assert (width == (width & -width)); // Must be a power of two assert (height == (height & -height)); // Must be a power of two int localWidth = Math.min(width, MAX_LOCAL_SIZE), localHeight = Math.min(height, MAX_LOCAL_SIZE / localWidth); return Range.create2D(width, height, localWidth, localHeight); } private static final int MAX_LOCAL_SIZE = 256; } apfloat-1.14.0/apfloat-aparapi/src/main/java/org/apfloat/aparapi/package-info.java000066400000000000000000000034341461767713300277640ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** Transforms for using a GPU via the aparapi library.

This package contains Number-Theoretic Transform implementations that can use the GPU (Graphics Processing Unit) for executing the transforms. There is significant overhead in invoking the GPU, e.g. in transferring the data between the main memory and the GPU memory, so for small data sets there is usually no performance improvement, and in many cases performance can be even significantly slower. However for very large calculations, e.g. one billion digits, using the GPU can improve the performance noticeably, depending on the hardware used. */ package org.apfloat.aparapi; apfloat-1.14.0/apfloat-aparapi/src/main/resources/000077500000000000000000000000001461767713300220305ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/resources/META-INF/000077500000000000000000000000001461767713300231705ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/resources/META-INF/services/000077500000000000000000000000001461767713300250135ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/main/resources/META-INF/services/org.apfloat.spi.BuilderFactory000066400000000000000000000001351461767713300326600ustar00rootroot00000000000000org.apfloat.aparapi.IntAparapiBuilderFactory org.apfloat.aparapi.LongAparapiBuilderFactory apfloat-1.14.0/apfloat-aparapi/src/test/000077500000000000000000000000001461767713300200515ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/000077500000000000000000000000001461767713300207725ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/org/000077500000000000000000000000001461767713300215615ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/000077500000000000000000000000001461767713300232075ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/aparapi/000077500000000000000000000000001461767713300246245ustar00rootroot00000000000000IntAparapiFactor3NTTStrategyTest.java000066400000000000000000000143421461767713300336370ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/aparapi/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import java.util.Arrays; import org.apfloat.*; import org.apfloat.spi.*; import org.apfloat.internal.*; import junit.framework.TestSuite; /** * @version 1.9.0 * @author Mikko Tommila */ public class IntAparapiFactor3NTTStrategyTest extends IntNTTStrategyTestCase { public IntAparapiFactor3NTTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new IntAparapiFactor3NTTStrategyTest("testForward")); suite.addTest(new IntAparapiFactor3NTTStrategyTest("testRoundTrip")); suite.addTest(new IntAparapiFactor3NTTStrategyTest("testRoundTrip2")); return suite; } public static void testForward() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMemoryThreshold(Long.MAX_VALUE); for (int modulus = 0; modulus < 3; modulus++) { int size = 3 * 2048; DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); int[] data = getPlainArray(dataStorage), expectedTransform = ntt(data, modulus); Arrays.sort(expectedTransform); NTTStrategy nttStrategy = new IntAparapiFactor3NTTStrategy(); nttStrategy.transform(dataStorage, modulus); int[] actualTransform = getPlainArray(dataStorage); Arrays.sort(actualTransform); assertEquals("expected length", size, expectedTransform.length); assertEquals("actual length", size, actualTransform.length); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], [" + i + "]", (long) expectedTransform[i], (long) actualTransform[i]); } } } public static void testRoundTrip() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(1); ctx.setMemoryThreshold(Long.MAX_VALUE); runRoundTrip(); ctx.setNumberOfProcessors(numberOfProcessors); } private static void runRoundTrip() { int size = (int) Math.min(3 * 1048576, IntModConstants.MAX_TRANSFORM_LENGTH); // Will use six-step transform DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); for (int modulus = 0; modulus < 3; modulus++) { Factor3NTTStrategy nttStrategy = new IntAparapiFactor3NTTStrategy(); nttStrategy.transform(dataStorage, modulus); assertEquals("transformed size", size, dataStorage.getSize()); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); assertTrue("transformed [0]", 6 != (long) iterator.getInt()); iterator.close(); nttStrategy.inverseTransform(dataStorage, modulus, size); assertEquals("inverse transformed size", size, dataStorage.getSize()); iterator = dataStorage.iterator(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], round-tripped [" + i + "]", i + 6, (long) iterator.getInt()); iterator.next(); } } } public static void testRoundTrip2() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(1); ctx.setMemoryThreshold(Long.MAX_VALUE); runRoundTrip2(); ctx.setNumberOfProcessors(numberOfProcessors); } private static void runRoundTrip2() { int size = 2048; // Will fall back to the power-of-two length transform DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); for (int modulus = 0; modulus < 3; modulus++) { Factor3NTTStrategy nttStrategy = new IntAparapiFactor3NTTStrategy(); nttStrategy.transform(dataStorage, modulus); assertEquals("transformed size", size, dataStorage.getSize()); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); assertTrue("transformed [0]", 6 != (long) iterator.getInt()); iterator.close(); nttStrategy.inverseTransform(dataStorage, modulus, size); assertEquals("inverse transformed size", size, dataStorage.getSize()); iterator = dataStorage.iterator(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], round-tripped [" + i + "]", i + 6, (long) iterator.getInt()); iterator.next(); } } } } apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/aparapi/IntAparapiMatrixStrategyTest.java000066400000000000000000000246451461767713300333020ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.*; import org.apfloat.spi.*; import org.apfloat.internal.*; import junit.framework.TestSuite; /** * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class IntAparapiMatrixStrategyTest extends IntTestCase { public IntAparapiMatrixStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new IntAparapiMatrixStrategyTest("testTransposeSquare")); suite.addTest(new IntAparapiMatrixStrategyTest("testTransposeSquarePart")); suite.addTest(new IntAparapiMatrixStrategyTest("testTransposeWide")); suite.addTest(new IntAparapiMatrixStrategyTest("testTransposeTall")); suite.addTest(new IntAparapiMatrixStrategyTest("testPermuteToDoubleWidth")); suite.addTest(new IntAparapiMatrixStrategyTest("testPermuteToHalfWidth")); return suite; } private static ArrayAccess getArray(int count) { int[] data = new int[count + 5]; ArrayAccess arrayAccess = new IntMemoryArrayAccess(data, 5, count); for (int i = 0; i < count; i++) { data[i + 5] = (int) (i + 1); } return arrayAccess; } public static void testTransposeSquare() { ArrayAccess arrayAccess = getArray(16); new IntAparapiMatrixStrategy().transpose(arrayAccess, 4, 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("16 elem [" + i + "][" + j + "]", 4 * j + i + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 4 * i + j]); } } arrayAccess = getArray(18).subsequence(1, 16); new IntAparapiMatrixStrategy().transpose(arrayAccess, 4, 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("16 elem sub [" + i + "][" + j + "]", 4 * j + i + 2, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 4 * i + j]); } } ApfloatContext ctx = ApfloatContext.getContext(); int cacheBurstBlockSize = Util.round2down(ctx.getCacheBurst() / 4), // Cache burst in ints cacheL1Size = Util.sqrt4down(ctx.getCacheL1Size() / 4), // To fit in processor L1 cache cacheL2Size = Util.sqrt4down(ctx.getCacheL2Size() / 4), // To fit in processor L2 cache bigSize = cacheL2Size * 2; // To not fit in processor L2 cache arrayAccess = getArray(cacheBurstBlockSize * cacheBurstBlockSize); new IntAparapiMatrixStrategy().transpose(arrayAccess, cacheBurstBlockSize, cacheBurstBlockSize); for (int i = 0; i < cacheBurstBlockSize; i++) { for (int j = 0; j < cacheBurstBlockSize; j++) { assertEquals("cacheBurstBlockSize [" + i + "][" + j + "]", cacheBurstBlockSize * j + i + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + cacheBurstBlockSize * i + j]); } } arrayAccess = getArray(cacheL1Size * cacheL1Size); new IntAparapiMatrixStrategy().transpose(arrayAccess, cacheL1Size, cacheL1Size); for (int i = 0; i < cacheL1Size; i++) { for (int j = 0; j < cacheL1Size; j++) { assertEquals("cacheL1Size [" + i + "][" + j + "]", cacheL1Size * j + i + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + cacheL1Size * i + j]); } } arrayAccess = getArray(cacheL2Size * cacheL2Size); new IntAparapiMatrixStrategy().transpose(arrayAccess, cacheL2Size, cacheL2Size); for (int i = 0; i < cacheL2Size; i++) { for (int j = 0; j < cacheL2Size; j++) { assertEquals("cacheL2Size [" + i + "][" + j + "]", cacheL2Size * j + i + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + cacheL2Size * i + j]); } } arrayAccess = getArray(bigSize * bigSize); new IntAparapiMatrixStrategy().transpose(arrayAccess, bigSize, bigSize); for (int i = 0; i < bigSize; i++) { for (int j = 0; j < bigSize; j++) { assertEquals("bigSize [" + i + "][" + j + "]", bigSize * j + i + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + bigSize * i + j]); } } } public static void testTransposeSquarePart() { ArrayAccess arrayAccess = getArray(32); new IntAparapiMatrixStrategy().transposeSquare(arrayAccess, 4, 8); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("1st transposed [" + i + "][" + j + "]", 8 * j + i + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 8 * i + j]); } for (int j = 4; j < 8; j++) { assertEquals("1st untransposed [" + i + "][" + j + "]", 8 * i + j + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 8 * i + j]); } } arrayAccess = getArray(32); new IntAparapiMatrixStrategy().transposeSquare(arrayAccess.subsequence(4, 28), 4, 8); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("2nd untransposed [" + i + "][" + j + "]", 8 * i + j + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 8 * i + j]); } for (int j = 4; j < 8; j++) { assertEquals("2nd transposed [" + i + "][" + j + "]", 8 * (j - 4) + (i + 4) + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 8 * i + j]); } } } public static void testTransposeWide() { ApfloatContext ctx = ApfloatContext.getContext(); int cacheL2Size = Util.sqrt4down(ctx.getCacheL2Size() / 4), // To fit in processor L2 cache bigSize = cacheL2Size * 2; // To not fit in processor L2 cache ArrayAccess arrayAccess = getArray(2 * bigSize * bigSize + 5).subsequence(5, 2 * bigSize * bigSize); new IntAparapiMatrixStrategy().transpose(arrayAccess, bigSize, 2 * bigSize); for (int i = 0; i < 2 * bigSize; i++) { for (int j = 0; j < bigSize; j++) { assertEquals("transposed [" + i + "][" + j + "]", 2 * bigSize * j + i + 6, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + bigSize * i + j]); } } } public static void testTransposeTall() { ApfloatContext ctx = ApfloatContext.getContext(); int cacheL2Size = Util.sqrt4down(ctx.getCacheL2Size() / 4), // To fit in processor L2 cache bigSize = cacheL2Size * 2; // To not fit in processor L2 cache ArrayAccess arrayAccess = getArray(2 * bigSize * bigSize + 5).subsequence(5, 2 * bigSize * bigSize); new IntAparapiMatrixStrategy().transpose(arrayAccess, 2 * bigSize, bigSize); for (int i = 0; i < bigSize; i++) { for (int j = 0; j < 2 * bigSize; j++) { assertEquals("transposed [" + i + "][" + j + "]", bigSize * j + i + 6, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 2 * bigSize * i + j]); } } } public static void testPermuteToDoubleWidth() { ArrayAccess arrayAccess = getArray(256); new IntAparapiMatrixStrategy().permuteToDoubleWidth(arrayAccess, 8, 32); for (int i = 0; i < 4; i++) { for (int j = 0; j < 32; j++) { assertEquals("permuted to double width [" + i + "][" + j + "]", 32 * i + j + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 64 * i + j]); } for (int j = 32; j < 64; j++) { assertEquals("permuted to double width [" + i + "][" + j + "]", 32 * i + j - 32 + 128 + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 64 * i + j]); } } } public static void testPermuteToHalfWidth() { ArrayAccess arrayAccess = getArray(256); new IntAparapiMatrixStrategy().permuteToHalfWidth(arrayAccess, 4, 64); for (int i = 0; i < 4; i++) { for (int j = 0; j < 32; j++) { assertEquals("permuted to half width [" + i + "][" + j + "]", 64 * i + j + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 32 * i + j]); } } for (int i = 4; i < 8; i++) { for (int j = 0; j < 32; j++) { assertEquals("permuted to half width [" + i + "][" + j + "]", 64 * (i - 4) + j + 32 + 1, (long) arrayAccess.getIntData()[arrayAccess.getOffset() + 32 * i + j]); } } } } IntAparapiSixStepFNTStrategyTest.java000066400000000000000000000075561461767713300337300ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/aparapi/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import java.util.Arrays; import org.apfloat.*; import org.apfloat.spi.*; import org.apfloat.internal.*; import junit.framework.TestSuite; /** * @version 1.8.3 * @author Mikko Tommila */ public class IntAparapiSixStepFNTStrategyTest extends IntNTTStrategyTestCase { public IntAparapiSixStepFNTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new IntAparapiSixStepFNTStrategyTest("testForward")); suite.addTest(new IntAparapiSixStepFNTStrategyTest("testForwardBig")); suite.addTest(new IntAparapiSixStepFNTStrategyTest("testRoundTrip")); suite.addTest(new IntAparapiSixStepFNTStrategyTest("testRoundTripBig")); return suite; } public static void testForward() { runTestForward(1024); } public static void testForwardBig() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMemoryThreshold(8192); runTestForward(4096); } private static void runTestForward(int size) { for (int modulus = 0; modulus < 3; modulus++) { DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); int[] data = getPlainArray(dataStorage), expectedTransform = ntt(data, modulus); IntScramble.scramble(expectedTransform, 0, Scramble.createScrambleTable(size)); Arrays.sort(expectedTransform); AbstractStepFNTStrategy nttStrategy = new IntAparapiSixStepFNTStrategy(); nttStrategy.transform(dataStorage, modulus); int[] actualTransform = getPlainArray(dataStorage); Arrays.sort(actualTransform); assertEquals("expected length", size, expectedTransform.length); assertEquals("actual length", size, actualTransform.length); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], [" + i + "]", (long) expectedTransform[i], (long) actualTransform[i]); } } } public static void testRoundTrip() { runRoundTrip(1024); } public static void testRoundTripBig() { int size = (int) Math.min(1 << 21, IntModConstants.MAX_TRANSFORM_LENGTH & -IntModConstants.MAX_TRANSFORM_LENGTH); runRoundTrip(size); } private static void runRoundTrip(int size) { runRoundTrip(new IntAparapiSixStepFNTStrategy(), size); } } IntAparapiTwoPassFNTStrategyTest.java000066400000000000000000000052341461767713300337200ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/aparapi/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.*; import org.apfloat.spi.*; import org.apfloat.internal.*; import junit.framework.TestSuite; /** * @version 1.8.3 * @author Mikko Tommila */ public class IntAparapiTwoPassFNTStrategyTest extends IntNTTStrategyTestCase { public IntAparapiTwoPassFNTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new IntAparapiTwoPassFNTStrategyTest("testRoundTrip")); suite.addTest(new IntAparapiTwoPassFNTStrategyTest("testRoundTripBig")); return suite; } public static void testRoundTrip() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMaxMemoryBlockSize(65536); ctx.setMemoryThreshold(1024); ctx.setBlockSize(256); runRoundTrip(131072); } public static void testRoundTripBig() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMaxMemoryBlockSize(65536); ctx.setMemoryThreshold(1024); ctx.setBlockSize(256); runRoundTrip((int) Math.min(1 << 21, Util.round2down(IntModConstants.MAX_TRANSFORM_LENGTH))); } private static void runRoundTrip(int size) { runRoundTrip(new ColumnTwoPassFNTStrategy(new IntAparapiNTTStepStrategy()), size); } } LongAparapiFactor3NTTStrategyTest.java000066400000000000000000000143621461767713300340060ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/aparapi/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import java.util.Arrays; import org.apfloat.*; import org.apfloat.spi.*; import org.apfloat.internal.*; import junit.framework.TestSuite; /** * @version 1.9.0 * @author Mikko Tommila */ public class LongAparapiFactor3NTTStrategyTest extends LongNTTStrategyTestCase { public LongAparapiFactor3NTTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new LongAparapiFactor3NTTStrategyTest("testForward")); suite.addTest(new LongAparapiFactor3NTTStrategyTest("testRoundTrip")); suite.addTest(new LongAparapiFactor3NTTStrategyTest("testRoundTrip2")); return suite; } public static void testForward() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMemoryThreshold(Long.MAX_VALUE); for (int modulus = 0; modulus < 3; modulus++) { int size = 3 * 2048; DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); long[] data = getPlainArray(dataStorage), expectedTransform = ntt(data, modulus); Arrays.sort(expectedTransform); NTTStrategy nttStrategy = new LongAparapiFactor3NTTStrategy(); nttStrategy.transform(dataStorage, modulus); long[] actualTransform = getPlainArray(dataStorage); Arrays.sort(actualTransform); assertEquals("expected length", size, expectedTransform.length); assertEquals("actual length", size, actualTransform.length); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], [" + i + "]", (long) expectedTransform[i], (long) actualTransform[i]); } } } public static void testRoundTrip() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(1); ctx.setMemoryThreshold(Long.MAX_VALUE); runRoundTrip(); ctx.setNumberOfProcessors(numberOfProcessors); } private static void runRoundTrip() { int size = (int) Math.min(3 * 1048576, LongModConstants.MAX_TRANSFORM_LENGTH); // Will use six-step transform DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); for (int modulus = 0; modulus < 3; modulus++) { Factor3NTTStrategy nttStrategy = new LongAparapiFactor3NTTStrategy(); nttStrategy.transform(dataStorage, modulus); assertEquals("transformed size", size, dataStorage.getSize()); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); assertTrue("transformed [0]", 6 != (long) iterator.getLong()); iterator.close(); nttStrategy.inverseTransform(dataStorage, modulus, size); assertEquals("inverse transformed size", size, dataStorage.getSize()); iterator = dataStorage.iterator(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], round-tripped [" + i + "]", i + 6, (long) iterator.getLong()); iterator.next(); } } } public static void testRoundTrip2() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(1); ctx.setMemoryThreshold(Long.MAX_VALUE); runRoundTrip2(); ctx.setNumberOfProcessors(numberOfProcessors); } private static void runRoundTrip2() { int size = 2048; // Will fall back to the power-of-two length transform DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); for (int modulus = 0; modulus < 3; modulus++) { Factor3NTTStrategy nttStrategy = new LongAparapiFactor3NTTStrategy(); nttStrategy.transform(dataStorage, modulus); assertEquals("transformed size", size, dataStorage.getSize()); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); assertTrue("transformed [0]", 6 != (long) iterator.getLong()); iterator.close(); nttStrategy.inverseTransform(dataStorage, modulus, size); assertEquals("inverse transformed size", size, dataStorage.getSize()); iterator = dataStorage.iterator(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], round-tripped [" + i + "]", i + 6, (long) iterator.getLong()); iterator.next(); } } } } apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/aparapi/LongAparapiMatrixStrategyTest.java000066400000000000000000000247171461767713300334470ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.*; import org.apfloat.spi.*; import org.apfloat.internal.*; import junit.framework.TestSuite; /** * @since 1.8.3 * @version 1.8.3 * @author Mikko Tommila */ public class LongAparapiMatrixStrategyTest extends LongTestCase { public LongAparapiMatrixStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new LongAparapiMatrixStrategyTest("testTransposeSquare")); suite.addTest(new LongAparapiMatrixStrategyTest("testTransposeSquarePart")); suite.addTest(new LongAparapiMatrixStrategyTest("testTransposeWide")); suite.addTest(new LongAparapiMatrixStrategyTest("testTransposeTall")); suite.addTest(new LongAparapiMatrixStrategyTest("testPermuteToDoubleWidth")); suite.addTest(new LongAparapiMatrixStrategyTest("testPermuteToHalfWidth")); return suite; } private static ArrayAccess getArray(int count) { long[] data = new long[count + 5]; ArrayAccess arrayAccess = new LongMemoryArrayAccess(data, 5, count); for (int i = 0; i < count; i++) { data[i + 5] = (long) (i + 1); } return arrayAccess; } public static void testTransposeSquare() { ArrayAccess arrayAccess = getArray(16); new LongAparapiMatrixStrategy().transpose(arrayAccess, 4, 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("16 elem [" + i + "][" + j + "]", 4 * j + i + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 4 * i + j]); } } arrayAccess = getArray(18).subsequence(1, 16); new LongAparapiMatrixStrategy().transpose(arrayAccess, 4, 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("16 elem sub [" + i + "][" + j + "]", 4 * j + i + 2, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 4 * i + j]); } } ApfloatContext ctx = ApfloatContext.getContext(); int cacheBurstBlockSize = Util.round2down(ctx.getCacheBurst() / 8), // Cache burst in longs cacheL1Size = Util.sqrt4down(ctx.getCacheL1Size() / 8), // To fit in processor L1 cache cacheL2Size = Util.sqrt4down(ctx.getCacheL2Size() / 8), // To fit in processor L2 cache bigSize = cacheL2Size * 2; // To not fit in processor L2 cache arrayAccess = getArray(cacheBurstBlockSize * cacheBurstBlockSize); new LongAparapiMatrixStrategy().transpose(arrayAccess, cacheBurstBlockSize, cacheBurstBlockSize); for (int i = 0; i < cacheBurstBlockSize; i++) { for (int j = 0; j < cacheBurstBlockSize; j++) { assertEquals("cacheBurstBlockSize [" + i + "][" + j + "]", cacheBurstBlockSize * j + i + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + cacheBurstBlockSize * i + j]); } } arrayAccess = getArray(cacheL1Size * cacheL1Size); new LongAparapiMatrixStrategy().transpose(arrayAccess, cacheL1Size, cacheL1Size); for (int i = 0; i < cacheL1Size; i++) { for (int j = 0; j < cacheL1Size; j++) { assertEquals("cacheL1Size [" + i + "][" + j + "]", cacheL1Size * j + i + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + cacheL1Size * i + j]); } } arrayAccess = getArray(cacheL2Size * cacheL2Size); new LongAparapiMatrixStrategy().transpose(arrayAccess, cacheL2Size, cacheL2Size); for (int i = 0; i < cacheL2Size; i++) { for (int j = 0; j < cacheL2Size; j++) { assertEquals("cacheL2Size [" + i + "][" + j + "]", cacheL2Size * j + i + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + cacheL2Size * i + j]); } } arrayAccess = getArray(bigSize * bigSize); new LongAparapiMatrixStrategy().transpose(arrayAccess, bigSize, bigSize); for (int i = 0; i < bigSize; i++) { for (int j = 0; j < bigSize; j++) { assertEquals("bigSize [" + i + "][" + j + "]", bigSize * j + i + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + bigSize * i + j]); } } } public static void testTransposeSquarePart() { ArrayAccess arrayAccess = getArray(32); new LongAparapiMatrixStrategy().transposeSquare(arrayAccess, 4, 8); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("1st transposed [" + i + "][" + j + "]", 8 * j + i + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 8 * i + j]); } for (int j = 4; j < 8; j++) { assertEquals("1st untransposed [" + i + "][" + j + "]", 8 * i + j + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 8 * i + j]); } } arrayAccess = getArray(32); new LongAparapiMatrixStrategy().transposeSquare(arrayAccess.subsequence(4, 28), 4, 8); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("2nd untransposed [" + i + "][" + j + "]", 8 * i + j + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 8 * i + j]); } for (int j = 4; j < 8; j++) { assertEquals("2nd transposed [" + i + "][" + j + "]", 8 * (j - 4) + (i + 4) + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 8 * i + j]); } } } public static void testTransposeWide() { ApfloatContext ctx = ApfloatContext.getContext(); int cacheL2Size = Util.sqrt4down(ctx.getCacheL2Size() / 8), // To fit in processor L2 cache bigSize = cacheL2Size * 2; // To not fit in processor L2 cache ArrayAccess arrayAccess = getArray(2 * bigSize * bigSize + 5).subsequence(5, 2 * bigSize * bigSize); new LongAparapiMatrixStrategy().transpose(arrayAccess, bigSize, 2 * bigSize); for (int i = 0; i < 2 * bigSize; i++) { for (int j = 0; j < bigSize; j++) { assertEquals("transposed [" + i + "][" + j + "]", 2 * bigSize * j + i + 6, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + bigSize * i + j]); } } } public static void testTransposeTall() { ApfloatContext ctx = ApfloatContext.getContext(); int cacheL2Size = Util.sqrt4down(ctx.getCacheL2Size() / 8), // To fit in processor L2 cache bigSize = cacheL2Size * 2; // To not fit in processor L2 cache ArrayAccess arrayAccess = getArray(2 * bigSize * bigSize + 5).subsequence(5, 2 * bigSize * bigSize); new LongAparapiMatrixStrategy().transpose(arrayAccess, 2 * bigSize, bigSize); for (int i = 0; i < bigSize; i++) { for (int j = 0; j < 2 * bigSize; j++) { assertEquals("transposed [" + i + "][" + j + "]", bigSize * j + i + 6, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 2 * bigSize * i + j]); } } } public static void testPermuteToDoubleWidth() { ArrayAccess arrayAccess = getArray(256); new LongAparapiMatrixStrategy().permuteToDoubleWidth(arrayAccess, 8, 32); for (int i = 0; i < 4; i++) { for (int j = 0; j < 32; j++) { assertEquals("permuted to double width [" + i + "][" + j + "]", 32 * i + j + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 64 * i + j]); } for (int j = 32; j < 64; j++) { assertEquals("permuted to double width [" + i + "][" + j + "]", 32 * i + j - 32 + 128 + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 64 * i + j]); } } } public static void testPermuteToHalfWidth() { ArrayAccess arrayAccess = getArray(256); new LongAparapiMatrixStrategy().permuteToHalfWidth(arrayAccess, 4, 64); for (int i = 0; i < 4; i++) { for (int j = 0; j < 32; j++) { assertEquals("permuted to half width [" + i + "][" + j + "]", 64 * i + j + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 32 * i + j]); } } for (int i = 4; i < 8; i++) { for (int j = 0; j < 32; j++) { assertEquals("permuted to half width [" + i + "][" + j + "]", 64 * (i - 4) + j + 32 + 1, (long) arrayAccess.getLongData()[arrayAccess.getOffset() + 32 * i + j]); } } } } LongAparapiSixStepFNTStrategyTest.java000066400000000000000000000075741461767713300340750ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/aparapi/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import java.util.Arrays; import org.apfloat.*; import org.apfloat.spi.*; import org.apfloat.internal.*; import junit.framework.TestSuite; /** * @version 1.8.3 * @author Mikko Tommila */ public class LongAparapiSixStepFNTStrategyTest extends LongNTTStrategyTestCase { public LongAparapiSixStepFNTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new LongAparapiSixStepFNTStrategyTest("testForward")); suite.addTest(new LongAparapiSixStepFNTStrategyTest("testForwardBig")); suite.addTest(new LongAparapiSixStepFNTStrategyTest("testRoundTrip")); suite.addTest(new LongAparapiSixStepFNTStrategyTest("testRoundTripBig")); return suite; } public static void testForward() { runTestForward(1024); } public static void testForwardBig() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMemoryThreshold(8192); runTestForward(4096); } private static void runTestForward(int size) { for (int modulus = 0; modulus < 3; modulus++) { DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); long[] data = getPlainArray(dataStorage), expectedTransform = ntt(data, modulus); LongScramble.scramble(expectedTransform, 0, Scramble.createScrambleTable(size)); Arrays.sort(expectedTransform); AbstractStepFNTStrategy nttStrategy = new LongAparapiSixStepFNTStrategy(); nttStrategy.transform(dataStorage, modulus); long[] actualTransform = getPlainArray(dataStorage); Arrays.sort(actualTransform); assertEquals("expected length", size, expectedTransform.length); assertEquals("actual length", size, actualTransform.length); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], [" + i + "]", (long) expectedTransform[i], (long) actualTransform[i]); } } } public static void testRoundTrip() { runRoundTrip(1024); } public static void testRoundTripBig() { int size = (int) Math.min(1 << 21, LongModConstants.MAX_TRANSFORM_LENGTH & -LongModConstants.MAX_TRANSFORM_LENGTH); runRoundTrip(size); } private static void runRoundTrip(int size) { runRoundTrip(new LongAparapiSixStepFNTStrategy(), size); } } LongAparapiTwoPassFNTStrategyTest.java000066400000000000000000000052431461767713300340650ustar00rootroot00000000000000apfloat-1.14.0/apfloat-aparapi/src/test/java/org/apfloat/aparapi/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.aparapi; import org.apfloat.*; import org.apfloat.spi.*; import org.apfloat.internal.*; import junit.framework.TestSuite; /** * @version 1.8.3 * @author Mikko Tommila */ public class LongAparapiTwoPassFNTStrategyTest extends LongNTTStrategyTestCase { public LongAparapiTwoPassFNTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new LongAparapiTwoPassFNTStrategyTest("testRoundTrip")); suite.addTest(new LongAparapiTwoPassFNTStrategyTest("testRoundTripBig")); return suite; } public static void testRoundTrip() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMaxMemoryBlockSize(65536); ctx.setMemoryThreshold(1024); ctx.setBlockSize(256); runRoundTrip(131072); } public static void testRoundTripBig() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMaxMemoryBlockSize(65536); ctx.setMemoryThreshold(1024); ctx.setBlockSize(256); runRoundTrip((int) Math.min(1 << 21, Util.round2down(LongModConstants.MAX_TRANSFORM_LENGTH))); } private static void runRoundTrip(int size) { runRoundTrip(new ColumnTwoPassFNTStrategy(new LongAparapiNTTStepStrategy()), size); } } apfloat-1.14.0/apfloat-applet/000077500000000000000000000000001461767713300161535ustar00rootroot00000000000000apfloat-1.14.0/apfloat-applet/pom.xml000066400000000000000000000036151461767713300174750ustar00rootroot00000000000000 4.0.0 org.apfloat apfloat-parent 1.14.0 apfloat-applet apfloat-applet Configuration for apfloat to not use disk files for data storage http://www.apfloat.org org.apfloat apfloat junit junit test org.apache.maven.plugins maven-javadoc-plugin org.apache.maven.plugins maven-shade-plugin shade org.apfloat:apfloat-applet ${project.build.directory}/applet.jar apfloat-1.14.0/apfloat-applet/src/000077500000000000000000000000001461767713300167425ustar00rootroot00000000000000apfloat-1.14.0/apfloat-applet/src/main/000077500000000000000000000000001461767713300176665ustar00rootroot00000000000000apfloat-1.14.0/apfloat-applet/src/main/java/000077500000000000000000000000001461767713300206075ustar00rootroot00000000000000apfloat-1.14.0/apfloat-applet/src/main/java/apfloat.java000066400000000000000000000073501461767713300231050ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import java.util.ListResourceBundle; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; import org.apfloat.ApfloatContext; import org.apfloat.spi.Util; /** * Default initial settings for the global {@link ApfloatContext}. * These settings are intended for applets that are not allowed to create * disk files. * * @version 1.9.1 * @author Mikko Tommila */ public class apfloat extends ListResourceBundle { @Override public Object[][] getContents() { return CONTENTS; } private static final Object[][] CONTENTS; static { // Try to use up to 80% of total memory and all processors long totalMemory; try { MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); MemoryUsage memoryUsage = memoryBean.getHeapMemoryUsage(); totalMemory = Math.max(memoryUsage.getCommitted(), memoryUsage.getMax()); } catch (NoClassDefFoundError | NullPointerException e) { // The ManagementFactory class might be unavailable totalMemory = Runtime.getRuntime().maxMemory(); } long maxMemoryBlockSize = Util.round23down(totalMemory / 5 * 4); int numberOfProcessors = Runtime.getRuntime().availableProcessors(); long memoryThreshold = Long.MAX_VALUE; int blockSize = Util.round2down((int) Math.min(Math.max(maxMemoryBlockSize >> 10, 65536), Integer.MAX_VALUE)); Object[][] contents = { { ApfloatContext.BUILDER_FACTORY, "org.apfloat.internal.LongBuilderFactory" }, { ApfloatContext.DEFAULT_RADIX, "10" }, { ApfloatContext.MAX_MEMORY_BLOCK_SIZE, String.valueOf(maxMemoryBlockSize) }, { ApfloatContext.CACHE_L1_SIZE, "8192" }, { ApfloatContext.CACHE_L2_SIZE, "262144" }, { ApfloatContext.CACHE_BURST, "32" }, { ApfloatContext.MEMORY_THRESHOLD, String.valueOf(memoryThreshold) }, { ApfloatContext.SHARED_MEMORY_TRESHOLD, String.valueOf(maxMemoryBlockSize / numberOfProcessors / 32) }, { ApfloatContext.BLOCK_SIZE, String.valueOf(blockSize) }, { ApfloatContext.NUMBER_OF_PROCESSORS, String.valueOf(numberOfProcessors) }, { ApfloatContext.FILE_PATH, "" }, { ApfloatContext.FILE_INITIAL_VALUE, "0" }, { ApfloatContext.FILE_SUFFIX, ".ap" }, { ApfloatContext.CLEANUP_AT_EXIT, "false" } }; CONTENTS = contents; } } apfloat-1.14.0/apfloat-calc/000077500000000000000000000000001461767713300155705ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/pom.xml000066400000000000000000000063161461767713300171130ustar00rootroot00000000000000 4.0.0 org.apfloat apfloat-parent 1.14.0 apfloat-calc apfloat-calc Interactive arbitrary precision calculator application http://www.apfloat.org org.apfloat apfloat junit junit test org.codehaus.mojo javacc-maven-plugin javacc javacc src/main/java biz.aQute.bnd bnd-maven-plugin generate-osgi-manifest bnd-process org.apache.maven.plugins maven-jar-plugin ${project.build.outputDirectory}/META-INF/MANIFEST.MF org.apache.maven.plugins maven-shade-plugin shade org.apfloat:apfloat-calc ${project.build.directory}/calc.jar apfloat.jar apfloat-1.14.0/apfloat-calc/src/000077500000000000000000000000001461767713300163575ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/main/000077500000000000000000000000001461767713300173035ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/main/java/000077500000000000000000000000001461767713300202245ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/main/java/org/000077500000000000000000000000001461767713300210135ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/000077500000000000000000000000001461767713300224415ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/000077500000000000000000000000001461767713300233435ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/AbstractCalculatorImpl.java000066400000000000000000000114031461767713300306040ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.calc; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Basic calculator implementation. * Provides a storage for variables, and maps * the elementary operators to function calls. * * @version 1.14.0 * @author Mikko Tommila */ public abstract class AbstractCalculatorImpl implements CalculatorImpl, Serializable { private static final long serialVersionUID = 1L; /** * Default constructor. */ protected AbstractCalculatorImpl() { this.variables = new HashMap<>(); this.pretty = false; } @Override public Number negate(Number x) throws ParseException { return function("negate", toList(x)); } @Override public Number add(Number x, Number y) throws ParseException { return function("add", toList(x, y)); } @Override public Number subtract(Number x, Number y) throws ParseException { return function("subtract", toList(x, y)); } @Override public Number multiply(Number x, Number y) throws ParseException { return function("multiply", toList(x, y)); } @Override public Number divide(Number x, Number y) throws ParseException { return function("divide", toList(x, y)); } @Override public Number mod(Number x, Number y) throws ParseException { return function("mod", toList(x, y)); } @Override public Number pow(Number x, Number y) throws ParseException { return function("pow", toList(x, y)); } @Override public Number factorial(Number x) throws ParseException { return function("factorial", toList(x)); } @Override public Number doubleFactorial(Number x) throws ParseException { return function("doubleFactorial", toList(x)); } @Override public Number getVariable(String name) throws ParseException { Number variable = this.variables.get(name); if (variable == null) { throw new ParseException("Invalid variable: " + name); } return variable; } @Override public void setVariable(String name, Number value) { this.variables.put(name, value); } @Override public void setFormat(boolean pretty) { this.pretty = pretty; } @Override public void setInputPrecision(Long inputPrecision) { this.inputPrecision = inputPrecision; } /** * Get the formatting option. * * @return If a fixed-point or a floating-point notation should be used. */ protected boolean getFormat() { return this.pretty; } /** * Get the input precision. * * @return The input precision if a fixed precision is used or null for arbitrary precision. */ protected Long getInputPrecision() { return this.inputPrecision; } private static List toList(Number x) { List list = new ArrayList<>(); list.add(x); return list; } private static List toList(Number x, Number y) { List list = new ArrayList<>(); list.add(x); list.add(y); return list; } private Map variables; private boolean pretty; private Long inputPrecision; } apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/ApfloatCalculatorImpl.java000066400000000000000000001243431461767713300304370ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.calc; import java.math.RoundingMode; import java.util.function.BiFunction; import org.apfloat.Apcomplex; import org.apfloat.ApcomplexMath; import org.apfloat.Apfloat; import org.apfloat.ApfloatMath; import org.apfloat.Apint; import org.apfloat.ApintMath; import org.apfloat.Aprational; import org.apfloat.AprationalMath; import org.apfloat.FixedPrecisionApcomplexHelper; import org.apfloat.spi.Util; /** * Arbitrary precision calculator implementation. * * @version 1.14.0 * @author Mikko Tommila */ public class ApfloatCalculatorImpl extends FunctionCalculatorImpl { private static final long serialVersionUID = 1L; private class ApcomplexFunctions implements Functions { @Override public Number negate(Number x) { return ((Apcomplex) x).negate(); } @Override public Number add(Number x, Number y) { return ((Apcomplex) x).add((Apcomplex) y); } @Override public Number subtract(Number x, Number y) { return ((Apcomplex) x).subtract((Apcomplex) y); } @Override public Number multiply(Number x, Number y) { return ((Apcomplex) x).multiply((Apcomplex) y); } @Override public Number divide(Number x, Number y) { return ((Apcomplex) x).divide((Apcomplex) y); } @Override public Number mod(Number x, Number y) { throw new IllegalArgumentException("Modulus can only be used with scalar values"); } @Override public Number pow(Number x, Number y) { if (isLong(y)) { if (((Apcomplex) y).precision() < ((Apcomplex) x).precision()) { x = ((Apcomplex) x).precision(((Apcomplex) y).precision()); } return pow(x, y.longValue()); } else { return ApcomplexMath.pow((Apcomplex) x, (Apcomplex) y); } } protected Number pow(Number x, long y) { return ApcomplexMath.pow((Apcomplex) x, y); } @Override public Number arg(Number x) { return ApcomplexMath.arg((Apcomplex) x); } @Override public Number conj(Number x) { return ((Apcomplex) x).conj(); } @Override public Number imag(Number x) { return ((Apcomplex) x).imag(); } @Override public Number real(Number x) { return ((Apcomplex) x).real(); } @Override public Number abs(Number x) { return ApcomplexMath.abs((Apcomplex) x); } @Override public Number acos(Number x) { return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::acos, ApcomplexMath::acos, x); } @Override public Number acosh(Number x) { return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::acosh, ApcomplexMath::acosh, x); } @Override public Number airyAi(Number x) { return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::airyAi, ApcomplexMath::airyAi, x); } @Override public Number airyAiPrime(Number x) { return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::airyAiPrime, ApcomplexMath::airyAiPrime, x); } @Override public Number airyBi(Number x) { return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::airyBi, ApcomplexMath::airyBi, x); } @Override public Number airyBiPrime(Number x) { return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::airyBiPrime, ApcomplexMath::airyBiPrime, x); } @Override public Number asin(Number x) { return ApcomplexMath.asin((Apcomplex) x); } @Override public Number asinh(Number x) { return ApcomplexMath.asinh((Apcomplex) x); } @Override public Number atan(Number x) { return ApcomplexMath.atan((Apcomplex) x); } @Override public Number atanh(Number x) { return ApcomplexMath.atanh((Apcomplex) x); } @Override public Number bernoulli(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Bernoulli can only be used with a valid integer argument"); } long n = x.longValue(); return AprationalMath.bernoulli(n); } @Override public Number bernoulliB(Number x, Number y) { if (!isLong(x)) { throw new IllegalArgumentException("Bernoulli B can only be used with a valid integer first argument"); } long n = x.longValue(); return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::bernoulliB, ApcomplexMath::bernoulliB, n, (Apcomplex) y); } @Override public Number besselI(Number x, Number y) { return ApcomplexMath.besselI((Apcomplex) x, (Apcomplex) y); } @Override public Number besselJ(Number x, Number y) { return ApcomplexMath.besselJ((Apcomplex) x, (Apcomplex) y); } @Override public Number besselK(Number x, Number y) { return ApcomplexMath.besselK((Apcomplex) x, (Apcomplex) y); } @Override public Number besselY(Number x, Number y) { return ApcomplexMath.besselY((Apcomplex) x, (Apcomplex) y); } @Override public Number beta(Number a, Number b) { return ApcomplexMath.beta((Apcomplex) a, (Apcomplex) b); } @Override public Number beta(Number x, Number a, Number b) { return ApcomplexMath.beta((Apcomplex) x, (Apcomplex) a, (Apcomplex) b); } @Override public Number beta(Number x1, Number x2, Number a, Number b) { return ApcomplexMath.beta((Apcomplex) x1, (Apcomplex) x2, (Apcomplex) a, (Apcomplex) b); } @Override public Number binomial(Number x, Number y) { return ApcomplexMath.binomial((Apcomplex) x, (Apcomplex) y); } @Override public Number catalan(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Catalan can only be used with a valid integer argument"); } long n = x.longValue(); return ApfloatMath.catalan(n); } @Override public Number cbrt(Number x) { return root(x, 3); } @Override public Number ceil(Number x) { throw new IllegalArgumentException("Ceiling can only be used with scalar values"); } @Override public Number chebyshevT(Number x, Number y) { return ApcomplexMath.chebyshevT((Apcomplex) x, (Apcomplex) y); } @Override public Number chebyshevU(Number x, Number y) { return ApcomplexMath.chebyshevU((Apcomplex) x, (Apcomplex) y); } @Override public Number cos(Number x) { return ApcomplexMath.cos((Apcomplex) x); } @Override public Number cosIntegral(Number x) { return ApcomplexMath.cosIntegral((Apcomplex) x); } @Override public Number cosh(Number x) { return ApcomplexMath.cosh((Apcomplex) x); } @Override public Number coshIntegral(Number x) { return ApcomplexMath.coshIntegral((Apcomplex) x); } @Override public Number digamma(Number x) { return ApcomplexMath.digamma((Apcomplex) x); } @Override public Number doubleFactorial(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Double factorial can only be used with a valid integer argument"); } long n = x.longValue(); return ApintMath.doubleFactorial(n); } @Override public Number e(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("E can only be used with a valid integer argument"); } long n = x.longValue(); return ApfloatMath.e(n); } @Override public Number ellipticE(Number x) { return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::ellipticE, ApcomplexMath::ellipticE, x); } @Override public Number ellipticK(Number x) { return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::ellipticK, ApcomplexMath::ellipticK, x); } @Override public Number erf(Number x) { return ApcomplexMath.erf((Apcomplex) x); } @Override public Number erfc(Number x) { return ApcomplexMath.erfc((Apcomplex) x); } @Override public Number erfi(Number x) { return ApcomplexMath.erfi((Apcomplex) x); } @Override public Number euler(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Euler can only be used with a valid integer argument"); } long n = x.longValue(); return ApfloatMath.euler(n); } @Override public Number eulerE(Number x, Number y) { if (!isLong(x)) { throw new IllegalArgumentException("Euler E can only be used with a valid integer first argument"); } long n = x.longValue(); return fixedOrArbitraryPrecision(fixedPrecisionApcomplexHelper::eulerE, ApcomplexMath::eulerE, n, (Apcomplex) y); } @Override public Number exp(Number x) { return ApcomplexMath.exp((Apcomplex) x); } @Override public Number expIntegralE(Number x, Number y) { return ApcomplexMath.expIntegralE((Apcomplex) x, (Apcomplex) y); } @Override public Number expIntegralEi(Number x) { return ApcomplexMath.expIntegralEi((Apcomplex) x); } @Override public Number factorial(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Factorial can only be used with a valid integer argument"); } long n = x.longValue(); return ApintMath.factorial(n); } @Override public Number fibonacci(Number x, Number y) { return ApcomplexMath.fibonacci((Apcomplex) x, (Apcomplex) y); } @Override public Number floor(Number x) { throw new IllegalArgumentException("Floor can only be used with scalar values"); } @Override public Number frac(Number x) { throw new IllegalArgumentException("Frac can only be used with scalar values"); } @Override public Number fresnelC(Number x) { return ApcomplexMath.fresnelC((Apcomplex) x); } @Override public Number fresnelS(Number x) { return ApcomplexMath.fresnelS((Apcomplex) x); } @Override public Number gegenbauerC(Number x, Number y) { return ApcomplexMath.gegenbauerC((Apcomplex) x, (Apcomplex) y); } @Override public Number gegenbauerC(Number x, Number y, Number z) { return ApcomplexMath.gegenbauerC((Apcomplex) x, (Apcomplex) y, (Apcomplex) z); } @Override public Number glaisher(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Glaisher can only be used with a valid integer argument"); } long n = x.longValue(); return ApfloatMath.glaisher(n); } @Override public Number gamma(Number x) { return ApcomplexMath.gamma((Apcomplex) x); } @Override public Number gamma(Number x, Number y) { return ApcomplexMath.gamma((Apcomplex) x, (Apcomplex) y); } @Override public Number gamma(Number x, Number y, Number z) { return ApcomplexMath.gamma((Apcomplex) x, (Apcomplex) y, (Apcomplex) z); } @Override public Number harmonicNumber(Number x) { return ApcomplexMath.harmonicNumber((Apcomplex) x); } @Override public Number harmonicNumber(Number x, Number y) { return ApcomplexMath.harmonicNumber((Apcomplex) x, (Apcomplex) y); } @Override public Number hermiteH(Number x, Number y) { return ApcomplexMath.hermiteH((Apcomplex) x, (Apcomplex) y); } @Override public Number hypergeometric0F1(Number a, Number z) { return ApcomplexMath.hypergeometric0F1((Apcomplex) a, (Apcomplex) z); } @Override public Number hypergeometric0F1Regularized(Number a, Number z) { return ApcomplexMath.hypergeometric0F1Regularized((Apcomplex) a, (Apcomplex) z); } @Override public Number hypergeometric1F1(Number a, Number b, Number z) { return ApcomplexMath.hypergeometric1F1((Apcomplex) a, (Apcomplex) b, (Apcomplex) z); } @Override public Number hypergeometric1F1Regularized(Number a, Number b, Number z) { return ApcomplexMath.hypergeometric1F1Regularized((Apcomplex) a, (Apcomplex) b, (Apcomplex) z); } @Override public Number hypergeometric2F1(Number a, Number b, Number c, Number z) { return ApcomplexMath.hypergeometric2F1((Apcomplex) a, (Apcomplex) b, (Apcomplex) c, (Apcomplex) z); } @Override public Number hypergeometric2F1Regularized(Number a, Number b, Number c, Number z) { return ApcomplexMath.hypergeometric2F1Regularized((Apcomplex) a, (Apcomplex) b, (Apcomplex) c, (Apcomplex) z); } @Override public Number hypergeometricU(Number a, Number b, Number z) { return ApcomplexMath.hypergeometricU((Apcomplex) a, (Apcomplex) b, (Apcomplex) z); } @Override public Number inverseErf(Number x) { throw new IllegalArgumentException("Inverse erf can only be used with scalar values"); } @Override public Number inverseErfc(Number x) { throw new IllegalArgumentException("Inverse erfc can only be used with scalar values"); } @Override public Number jacobiP(Number x, Number y, Number z, Number w) { return ApcomplexMath.jacobiP((Apcomplex) x, (Apcomplex) y, (Apcomplex) z, (Apcomplex) w); } @Override public Number khinchin(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Khinchin can only be used with a valid integer argument"); } long n = x.longValue(); return ApfloatMath.khinchin(n); } @Override public Number laguerreL(Number x, Number y) { return ApcomplexMath.laguerreL((Apcomplex) x, (Apcomplex) y); } @Override public Number laguerreL(Number x, Number y, Number z) { return ApcomplexMath.laguerreL((Apcomplex) x, (Apcomplex) y, (Apcomplex) z); } @Override public Number legendreP(Number x, Number y) { return ApcomplexMath.legendreP((Apcomplex) x, (Apcomplex) y); } @Override public Number legendreP(Number x, Number y, Number z) { return ApcomplexMath.legendreP((Apcomplex) x, (Apcomplex) y, (Apcomplex) z); } @Override public Number legendreQ(Number x, Number y) { return ApcomplexMath.legendreQ((Apcomplex) x, (Apcomplex) y); } @Override public Number legendreQ(Number x, Number y, Number z) { return ApcomplexMath.legendreQ((Apcomplex) x, (Apcomplex) y, (Apcomplex) z); } @Override public Number log(Number x) { return ApcomplexMath.log((Apcomplex) x); } @Override public Number log(Number x, Number y) { return ApcomplexMath.log((Apcomplex) x, (Apcomplex) y); } @Override public Number logGamma(Number x) { return ApcomplexMath.logGamma((Apcomplex) x); } @Override public Number logIntegral(Number x) { return ApcomplexMath.logIntegral((Apcomplex) x); } @Override public Number logisticSigmoid(Number x) { return ApcomplexMath.logisticSigmoid((Apcomplex) x); } @Override public Number max(Number x, Number y) { throw new IllegalArgumentException("Max can only be used with scalar values"); } @Override public Number min(Number x, Number y) { throw new IllegalArgumentException("Min can only be used with scalar values"); } @Override public Number nextAfter(Number x, Number y) { throw new IllegalArgumentException("Next after can only be used with scalar values"); } @Override public Number nextDown(Number x) { throw new IllegalArgumentException("Next down can only be used with scalar values"); } @Override public Number nextUp(Number x) { throw new IllegalArgumentException("Next up can only be used with scalar values"); } @Override public Number pi(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Pi can only be used with a valid integer argument"); } long n = x.longValue(); return ApfloatMath.pi(n); } @Override public Number pochhammer(Number x, Number y) { return ApcomplexMath.pochhammer((Apcomplex) x, (Apcomplex) y); } @Override public Number polygamma(Number x, Number y) { if (!isLong(x)) { throw new IllegalArgumentException("Polygamma can only be used with a valid integer first argument"); } long n = x.longValue(); return ApcomplexMath.polygamma(n, (Apcomplex) y); } @Override public Number polylog(Number x, Number y) { return ApcomplexMath.polylog((Apcomplex) x, (Apcomplex) y); } @Override public Number random(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Random can only be used with a valid integer argument"); } long n = x.longValue(); return ApfloatMath.random(n); } @Override public Number randomGaussian(Number x) { if (!isLong(x)) { throw new IllegalArgumentException("Random Gaussian can only be used with a valid integer argument"); } long n = x.longValue(); return ApfloatMath.randomGaussian(n); } @Override public Number round(Number x, Number y) { return roundToPrecision(x, y); } @Override public Number roundToPrecision(Number x, Number y) { throw new IllegalArgumentException("Rounding can only be used with scalar values"); } @Override public Number roundToInteger(Number x) { throw new IllegalArgumentException("Rounding can only be used with scalar values"); } @Override public Number roundToPlaces(Number x, Number y) { throw new IllegalArgumentException("Rounding can only be used with scalar values"); } @Override public Number roundToMultiple(Number x, Number y) { throw new IllegalArgumentException("Rounding can only be used with scalar values"); } @Override public Number sin(Number x) { return ApcomplexMath.sin((Apcomplex) x); } @Override public Number sinc(Number x) { return ApcomplexMath.sinc((Apcomplex) x); } @Override public Number sinIntegral(Number x) { return ApcomplexMath.sinIntegral((Apcomplex) x); } @Override public Number sinh(Number x) { return ApcomplexMath.sinh((Apcomplex) x); } @Override public Number sinhIntegral(Number x) { return ApcomplexMath.sinhIntegral((Apcomplex) x); } @Override public Number sphericalHarmonicY(Number x, Number y, Number z, Number w) { return ApcomplexMath.sphericalHarmonicY((Apcomplex) x, (Apcomplex) y, (Apcomplex) z, (Apcomplex) w); } @Override public Number sqrt(Number x) { return root(x, 2); } @Override public Number tan(Number x) { return ApcomplexMath.tan((Apcomplex) x); } @Override public Number tanh(Number x) { return ApcomplexMath.tanh((Apcomplex) x); } @Override public Number truncate(Number x) { throw new IllegalArgumentException("Truncate can only be used with scalar values"); } @Override public Number toDegrees(Number x) { throw new IllegalArgumentException("ToDegrees can only be used with scalar values"); } @Override public Number toRadians(Number x) { throw new IllegalArgumentException("ToRadians can only be used with scalar values"); } @Override public Number ulp(Number x) { return ApcomplexMath.ulp((Apcomplex) x); } @Override public Number zeta(Number x) { return ApcomplexMath.zeta((Apcomplex) x); } @Override public Number zeta(Number x, Number y) { return ApcomplexMath.zeta((Apcomplex) x, (Apcomplex) y); } @Override public Number agm(Number x, Number y) { return ApcomplexMath.agm((Apcomplex) x, (Apcomplex) y); } @Override public Number w(Number x) { return ApcomplexMath.w((Apcomplex) x); } @Override public Number w(Number x, Number y) { if (!isLong(y)) { throw new IllegalArgumentException("Lambert W can only be used with a valid integer argument"); } return ApcomplexMath.w((Apcomplex) x, y.longValue()); } @Override public Number atan2(Number x, Number y) { throw new IllegalArgumentException("Atan2 can only be used with scalar values"); } @Override public Number copySign(Number x, Number y) { throw new IllegalArgumentException("CopySign can only be used with scalar values"); } @Override public Number fmod(Number x, Number y) { throw new IllegalArgumentException("Fmod can only be used with scalar values"); } @Override public Number gcd(Number x, Number y) { throw new IllegalArgumentException("Greatest Common Ddivisor can only be used with integer values"); } @Override public Number hypot(Number x, Number y) { throw new IllegalArgumentException("Hypot can only be used with scalar values"); } @Override public Number inverseRoot(Number x, Number y) { if (!isLong(y)) { throw new IllegalArgumentException("Inverse root can only be used with a valid integer argument"); } return inverseRoot(x, y.longValue()); } @Override public Number inverseRoot(Number x, Number y, Number z) { if (!isLong(y) || !isLong(z)) { throw new IllegalArgumentException("Inverse root can only be used with valid integer arguments"); } return inverseRoot(x, y.longValue(), z.longValue()); } protected Number inverseRoot(Number x, long y) { return ApcomplexMath.inverseRoot((Apcomplex) x, y); } protected Number inverseRoot(Number x, long y, long z) { return ApcomplexMath.inverseRoot((Apcomplex) x, y, z); } @Override public Number lcm(Number x, Number y) { throw new IllegalArgumentException("Least Common Multiplier can only be used with integer values"); } @Override public Number root(Number x, Number y) { if (!isLong(y)) { throw new IllegalArgumentException("Root can only be used with a valid integer argument"); } return root(x, y.longValue()); } @Override public Number root(Number x, Number y, Number z) { if (!isLong(y) || !isLong(z)) { throw new IllegalArgumentException("Root can only be used with valid integer arguments"); } return root(x, y.longValue(), z.longValue()); } protected Number root(Number x, long y) { return ApcomplexMath.root((Apcomplex) x, y); } protected Number root(Number x, long y, long z) { return ApcomplexMath.root((Apcomplex) x, y, z); } @Override public Number scale(Number x, Number y) { if (!isLong(y)) { throw new IllegalArgumentException("Scale can only be used with a valid integer argument"); } return scale(x, y.longValue()); } protected Number scale(Number x, long y) { return ApcomplexMath.scale((Apcomplex) x, y); } @Override public Number precision(Number x, Number y) { if (!isLong(y)) { throw new IllegalArgumentException("Precision can only be used with a valid integer argument"); } return precision(x, y.longValue()); } protected Number precision(Number x, long precision) { return ((Apcomplex) x).precision(precision); } protected boolean isLong(Number value) { return value instanceof Long || value != null && new Apint(value.longValue()).equals(value); } } private class ApfloatFunctions extends ApcomplexFunctions { @Override public Number mod(Number x, Number y) { return ((Apfloat) x).mod((Apfloat) y); } @Override public Number ceil(Number x) { return ((Apfloat) x).ceil(); } @Override public Number floor(Number x) { return ((Apfloat) x).floor(); } @Override public Number frac(Number x) { return ((Apfloat) x).frac(); } @Override public Number inverseErf(Number x) { return ApfloatMath.inverseErf((Apfloat) x); } @Override public Number inverseErfc(Number x) { return ApfloatMath.inverseErfc((Apfloat) x); } @Override public Number max(Number x, Number y) { return ApfloatMath.max((Apfloat) x, (Apfloat) y); } @Override public Number min(Number x, Number y) { return ApfloatMath.min((Apfloat) x, (Apfloat) y); } @Override public Number nextAfter(Number x, Number y) { return ApfloatMath.nextAfter((Apfloat) x, (Apfloat) y); } @Override public Number nextDown(Number x) { return ApfloatMath.nextDown((Apfloat) x); } @Override public Number nextUp(Number x) { return ApfloatMath.nextUp((Apfloat) x); } @Override public Number truncate(Number x) { return ((Apfloat) x).truncate(); } @Override public Number toDegrees(Number x) { return ApfloatMath.toDegrees((Apfloat) x); } @Override public Number toRadians(Number x) { return ApfloatMath.toRadians((Apfloat) x); } @Override public Number atan2(Number x, Number y) { return ApfloatMath.atan2((Apfloat) x, (Apfloat) y); } @Override public Number copySign(Number x, Number y) { return ApfloatMath.copySign((Apfloat) x, (Apfloat) y); } @Override public Number fmod(Number x, Number y) { return ApfloatMath.fmod((Apfloat) x, (Apfloat) y); } @Override public Number hypot(Number x, Number y) { return ApcomplexMath.abs(new Apcomplex((Apfloat) x, (Apfloat) y)); } @Override public Number roundToPrecision(Number x, Number y) { if (!isLong(y)) { throw new IllegalArgumentException("Rounding can only be used with a valid integer argument"); } return roundToPrecision(x, y.longValue()); } protected Number roundToPrecision(Number x, long precision) { return ApfloatMath.roundToPrecision((Apfloat) x, precision, RoundingMode.HALF_UP); } @Override public Number roundToInteger(Number x) { return ApfloatMath.roundToInteger((Apfloat) x, RoundingMode.HALF_UP); } @Override public Number roundToPlaces(Number x, Number y) { if (!isLong(y)) { throw new IllegalArgumentException("Rounding can only be used with a valid integer argument"); } return roundToPlaces(x, y.longValue()); } protected Number roundToPlaces(Number x, long precision) { return ApfloatMath.roundToPlaces((Apfloat) x, precision, RoundingMode.HALF_UP); } @Override public Number roundToMultiple(Number x, Number y) { return ApfloatMath.roundToMultiple((Apfloat) x, (Apfloat) y, RoundingMode.HALF_UP); } } private class AprationalFunctions extends ApfloatFunctions { @Override public Number add(Number x, Number y) { return ((Aprational) x).add((Aprational) y); } @Override public Number subtract(Number x, Number y) { return ((Aprational) x).subtract((Aprational) y); } @Override public Number multiply(Number x, Number y) { return ((Aprational) x).multiply((Aprational) y); } @Override public Number divide(Number x, Number y) { return ((Aprational) x).divide((Aprational) y); } @Override public Number mod(Number x, Number y) { return ((Aprational) x).mod((Aprational) y); } @Override public Number pochhammer(Number x, Number y) { if (y instanceof Apint) { return AprationalMath.pochhammer((Aprational) x, (Apint) y); } return super.pochhammer(x, y); } @Override protected Number pow(Number x, long y) { return AprationalMath.pow((Aprational) x, y); } @Override public Number binomial(Number x, Number y) { return AprationalMath.binomial((Aprational) x, (Aprational) y); } @Override public Number hypot(Number x, Number y) { return root(add(pow(x, 2), pow(y, 2)), 2); } @Override protected Number root(Number x, long y) { return new Aprational(root(((Aprational) x).numerator(), y), root(((Aprational) x).denominator(), y)); } private Apint root(Apint x, long y) { Apint[] root = ApintMath.root(x, y); if (root[1].signum() != 0) { throw new IllegalArgumentException("Cannot calculate inexact root to infinite precision"); } return root[0]; } @Override protected Number roundToPrecision(Number x, long precision) { return AprationalMath.roundToPrecision((Aprational) x, precision, RoundingMode.HALF_UP); } @Override public Number roundToInteger(Number x) { return AprationalMath.roundToInteger((Aprational) x, RoundingMode.HALF_UP); } @Override protected Number roundToPlaces(Number x, long places) { return AprationalMath.roundToPlaces((Aprational) x, places, RoundingMode.HALF_UP); } @Override public Number roundToMultiple(Number x, Number y) { return AprationalMath.roundToMultiple((Aprational) x, (Aprational) y, RoundingMode.HALF_UP); } @Override protected Number scale(Number x, long y) { return AprationalMath.scale((Aprational) x, y); } } private class ApintFunctions extends AprationalFunctions { @Override public Number binomial(Number x, Number y) { if (isLong(x) && isLong(y)) { return ApintMath.binomial(x.longValue(), y.longValue()); } return ApintMath.binomial((Apint) x, (Apint) y); } @Override public Number gcd(Number x, Number y) { return ApintMath.gcd((Apint) x, (Apint) y); } @Override public Number harmonicNumber(Number x) { return AprationalMath.harmonicNumber((Apint) x); } @Override public Number harmonicNumber(Number x, Number y) { return AprationalMath.harmonicNumber((Apint) x, (Apint) y); } @Override public Number lcm(Number x, Number y) { return ApintMath.lcm((Apint) x, (Apint) y); } @Override protected Number scale(Number x, long y) { return (y >= 0 ? ApintMath.scale((Apint) x, y) : super.scale(x, y)); } } /** * Default constructor. */ public ApfloatCalculatorImpl() { } @Override public Number parseInteger(String value) { Apcomplex x; if (value.equalsIgnoreCase("i")) { x = Apcomplex.I; } else if (value.endsWith("i") || value.endsWith("I")) { x = new Apint(value.substring(0, value.length() - 1)).multiply(Apcomplex.I); } else { x = new Apint(value); } if (getInputPrecision() != null) { x = x.precision(getInputPrecision()); } return x; } @Override public Number parseDecimal(String value) { Apcomplex x; if (value.endsWith("i") || value.endsWith("I")) { x = new Apfloat(value.substring(0, value.length() - 1)).multiply(Apcomplex.I); } else { x = new Apfloat(value); } if (getInputPrecision() != null) { x = x.precision(getInputPrecision()); } return x; } @Override public String format(Number x) { String text; boolean pretty = getFormat(); if (x instanceof Aprational) { text = x.toString(); } else if (x instanceof Apfloat) { Apfloat a = (Apfloat) x; a = ApfloatMath.roundToPrecision(a.precision(Util.ifFinite(a.precision(), a.precision() + 1)), a.precision(), RoundingMode.HALF_UP); text = a.toString(pretty); } else { Apcomplex z = (Apcomplex) x; String imag = (z.imag().equals(Apfloat.ONE) ? "" : (z.imag().negate().equals(Apfloat.ONE) ? "-" : format(z.imag()))); if (z.real().signum() == 0) { text = imag + "i"; } else { text = format(z.real()) + (z.imag().signum() < 0 ? "" : "+") + imag + "i"; } } return text; } @Override protected Functions getFunctions(Number x) { Functions functions; if (x instanceof Apint) { functions = new ApintFunctions(); } else if (x instanceof Aprational) { functions = new AprationalFunctions(); } else if (x instanceof Apfloat) { functions = new ApfloatFunctions(); } else { functions = new ApcomplexFunctions(); } return functions; } @Override protected Number promote(Number x) { if (!(x instanceof Apfloat) && ((Apcomplex) x).imag().signum() == 0) { // Complex to float x = ((Apcomplex) x).real(); } if (x instanceof Apfloat && !(x instanceof Aprational) && ((Apfloat) x).precision() == Apfloat.INFINITE && ((Apfloat) x).isInteger()) { // Float to integer x = ((Apfloat) x).truncate(); } if (x instanceof Aprational && !(x instanceof Apint) && ((Aprational) x).denominator().equals(Apint.ONE)) { // Rational to integer x = ((Aprational) x).numerator(); } return x; } @Override public void setInputPrecision(Long inputPrecision) { super.setInputPrecision(inputPrecision); this.fixedPrecisionApcomplexHelper = new FixedPrecisionApcomplexHelper(inputPrecision == null ? Apfloat.INFINITE : inputPrecision); } private Number fixedOrArbitraryPrecision(java.util.function.Function fixedPrecisionFunction, java.util.function.Function arbitraryPrecisionFunction, Number x) { Apcomplex z = (Apcomplex) x; return (getInputPrecision() != null && z.isZero() ? fixedPrecisionFunction.apply(z) : arbitraryPrecisionFunction.apply(z)); } private Number fixedOrArbitraryPrecision(BiFunction fixedPrecisionFunction, BiFunction arbitraryPrecisionFunction, T x, U y) { return (getInputPrecision() != null && y.isZero() ? fixedPrecisionFunction.apply(x, y) : arbitraryPrecisionFunction.apply(x, y)); } private FixedPrecisionApcomplexHelper fixedPrecisionApcomplexHelper = new FixedPrecisionApcomplexHelper(Apfloat.INFINITE); } apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/Calculator.java000066400000000000000000000055111461767713300263010ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.calc; /** * Command-line calculator. * * @version 1.11.0 * @author Mikko Tommila */ public class Calculator { private Calculator() { } /** * Command-line entry point. * * @param args Command-line parameters. * * @exception ParseException In case of invalid input */ public static void main(String args[]) throws ParseException { boolean pretty = false; Long inputPrecision = null; for (int i = 0; i < args.length; i++) { switch (args[i]) { case "-p": pretty = true; break; case "-i": try { i++; inputPrecision = Long.valueOf(args[i]); break; } catch (NumberFormatException | ArrayIndexOutOfBoundsException e) { // Fall through to usage } default: System.err.println("Usage: calculator [-p] [-i inputPrecision]"); System.exit(1); } } CalculatorImpl calculatorImpl = new ApfloatCalculatorImpl(); calculatorImpl.setFormat(pretty); calculatorImpl.setInputPrecision(inputPrecision); CalculatorParser calculatorParser = new CalculatorParser(System.in, System.out, calculatorImpl); while (calculatorParser.parseOneLine()) { // Loop until input ends or exception is thrown } } } apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/CalculatorAWT.java000066400000000000000000000235561461767713300266660ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.calc; import java.awt.GridBagLayout; import java.awt.GridBagConstraints; import java.awt.Insets; import java.awt.Panel; import java.awt.Label; import java.awt.Checkbox; import java.awt.CheckboxGroup; import java.awt.TextField; import java.awt.TextArea; import java.awt.Button; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.StringReader; import java.io.StringWriter; import java.io.PrintWriter; import java.util.List; import java.util.ArrayList; /** * Graphical AWT elements for the calculator. * * @version 1.14.0 * @author Mikko Tommila */ public class CalculatorAWT extends Panel { private static final long serialVersionUID = 1L; /** * Construct a panel with graphical elements. */ public CalculatorAWT() { this.calculatorImpl = new ApfloatCalculatorImpl(); this.history = new ArrayList<>(); this.historyPosition = 0; initGUI(); this.out = new PrintWriter(new FlushStringWriter(this.outputArea), true); } // Initialize the container and add the graphical elements to it private void initGUI() { setLayout(new GridBagLayout()); GridBagConstraints constraints = new GridBagConstraints(); constraints.anchor = GridBagConstraints.NORTHWEST; constraints.insets = new Insets(5, 5, 5, 5); constraints.weightx = 1; constraints.weighty = 1; // Initial focus will be on the first element, which is added here although it's located at the bottom this.inputField = new TextField(null, 60); constraints.gridy = 8; add(this.inputField, constraints); this.calculateButton = new Button("Calculate"); add(this.calculateButton, constraints); this.abortButton = new Button("Abort"); this.abortButton.setEnabled(false); constraints.gridwidth = GridBagConstraints.REMAINDER; add(this.abortButton, constraints); this.outputArea = new TextArea(null, 20, 60, TextArea.SCROLLBARS_VERTICAL_ONLY); this.outputArea.setEditable(false); constraints.gridy = 0; constraints.gridwidth = 1; constraints.gridheight = 8; add(this.outputArea, constraints); this.formatLabel = new Label("Format:"); constraints.gridwidth = GridBagConstraints.REMAINDER; constraints.gridheight = 1; add(this.formatLabel, constraints); this.formats = new CheckboxGroup(); this.floating = new Checkbox("Floating", true, this.formats); constraints.gridy = 1; add(this.floating, constraints); this.fixed = new Checkbox("Fixed", false, this.formats); constraints.gridy = 2; add(this.fixed, constraints); this.inputTypeLabel = new Label("Input precision:"); constraints.gridy = 3; add(this.inputTypeLabel, constraints); this.inputPrecisionTypes = new CheckboxGroup(); this.inputPrecisionArbitrary = new Checkbox("Arbitrary", true, this.inputPrecisionTypes); constraints.gridy = 4; add(this.inputPrecisionArbitrary, constraints); this.inputPrecisionFixed = new Checkbox("Fixed", false, this.inputPrecisionTypes); constraints.gridy = 5; add(this.inputPrecisionFixed, constraints); this.inputPrecisionField = new TextField(null, 10); constraints.gridy = 6; add(this.inputPrecisionField, constraints); this.clearButton = new Button("Clear"); constraints.gridy = 7; constraints.weighty = 1000; add(this.clearButton, constraints); // Clear output area and command history this.clearButton.addActionListener((actionEvent) -> { CalculatorAWT.this.outputArea.setText(null); CalculatorAWT.this.history.clear(); CalculatorAWT.this.historyPosition = 0; }); // Calculate current input button this.calculateButton.addActionListener((actionEvent) -> processInput()); // Calculate current input by hitting enter in the input field this.inputField.addActionListener((actionEvent) -> processInput()); // Abort button this.abortButton.addActionListener((actionEvent) -> abortCalculation()); // Command history handler for up and down arrow keys this.inputField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent keyEvent) { switch(keyEvent.getKeyCode()) { case KeyEvent.VK_UP: if (CalculatorAWT.this.historyPosition > 0) { CalculatorAWT.this.inputField.setText(CalculatorAWT.this.history.get(--CalculatorAWT.this.historyPosition)); CalculatorAWT.this.inputField.setCaretPosition(Integer.MAX_VALUE); } break; case KeyEvent.VK_DOWN: if (CalculatorAWT.this.historyPosition < CalculatorAWT.this.history.size() - 1) { CalculatorAWT.this.inputField.setText(CalculatorAWT.this.history.get(++CalculatorAWT.this.historyPosition)); CalculatorAWT.this.inputField.setCaretPosition(Integer.MAX_VALUE); } break; default: } } }); } private void processInput() { this.calculateButton.setEnabled(false); Long inputPrecision; if (this.inputPrecisionArbitrary.getState()) { inputPrecision = null; } else { try { inputPrecision = Long.parseLong(this.inputPrecisionField.getText()); } catch (NumberFormatException nfe) { this.inputPrecisionField.requestFocus(); return; } } String text = this.inputField.getText(); this.inputField.setText(null); this.out.println(text); // Parse the input line; the parser prints the output this.calculatorImpl.setFormat(this.fixed.getState()); this.calculatorImpl.setInputPrecision(inputPrecision); CalculatorParser calculatorParser = new CalculatorParser(new StringReader(text), this.out, this.calculatorImpl); this.calculatorThread = new Thread(() -> { try { calculatorParser.parseOneLine(); } catch (Exception e) { this.out.println(e.getMessage()); } finally { this.abortButton.setEnabled(false); this.calculateButton.setEnabled(true); } }); this.calculatorThread.start(); this.abortButton.setEnabled(true); // Show the bottom part of the output area this.outputArea.requestFocus(); this.outputArea.setCaretPosition(Integer.MAX_VALUE); this.inputField.requestFocus(); // Add last command to history and reset history position this.history.add(text); this.historyPosition = this.history.size(); } private void abortCalculation() { this.calculatorThread.interrupt(); } // Prints output to a text area private static class FlushStringWriter extends StringWriter { public FlushStringWriter(TextArea dst) { this.dst = dst; } @Override public void flush() { super.flush(); StringBuffer buffer = getBuffer(); String text = buffer.toString(); this.dst.append(text); buffer.setLength(0); } private TextArea dst; } private CalculatorImpl calculatorImpl; private List history; private int historyPosition; private TextArea outputArea; private Label formatLabel; private CheckboxGroup formats; private Checkbox floating; private Checkbox fixed; private Label inputTypeLabel; private CheckboxGroup inputPrecisionTypes; private Checkbox inputPrecisionArbitrary; private Checkbox inputPrecisionFixed; private TextField inputPrecisionField; private Button clearButton; private TextField inputField; private Button calculateButton; private Button abortButton; private PrintWriter out; private Thread calculatorThread; } apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/CalculatorApplet.java000066400000000000000000000065351461767713300274560ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.calc; import java.applet.Applet; import java.io.File; import java.security.AccessControlException; import org.apfloat.ApfloatContext; import org.apfloat.spi.FilenameGenerator; /** * Calculator applet. * * @version 1.9.1 * @author Mikko Tommila */ public class CalculatorApplet extends Applet { private static final long serialVersionUID = 1L; /** * Default constructor. */ public CalculatorApplet() { } /** * Initialize this applet. */ @Override public void init() { add(new CalculatorAWT()); // Recreate the executor service in case the old thread group was destroyed by reloading the applet ApfloatContext ctx = ApfloatContext.getContext(); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); try { // The applet may not be able to write files to the current directory, but probably can write to the temp directory String path = System.getProperty("java.io.tmpdir"); if (path != null && !path.endsWith(File.separator)) { path = path + File.separator; } FilenameGenerator filenameGenerator = new FilenameGenerator(path, null, null); ctx.setFilenameGenerator(filenameGenerator); } catch (AccessControlException ace) { // Ignore - reading the system property may not be allowed in unsigned applets } } /** * Called when this applet is destroyed. */ @Override public void destroy() { removeAll(); } /** * Get information about this applet. * * @return Information about this applet. */ @Override public String getAppletInfo() { String lineSeparator = System.lineSeparator(); return "Calculator applet" + lineSeparator + "Written by Mikko Tommila 2011 - 2023" + lineSeparator + "Java version: " + System.getProperty("java.version") + lineSeparator + "Java Virtual Machine: " + System.getProperty("java.vm.name"); } } apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/CalculatorGUI.java000066400000000000000000000045101461767713300266440ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.calc; import java.awt.Frame; import java.awt.BorderLayout; import java.awt.Label; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; /** * AWT client application for the calculator. * * @version 1.9.0 * @author Mikko Tommila */ public class CalculatorGUI extends Frame { private static final long serialVersionUID = 1L; /** * Default constructor. */ protected CalculatorGUI() { super("Calculator"); setSize(720, 540); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent windowEvent) { setVisible(false); dispose(); System.exit(0); } }); setLayout(new BorderLayout()); add(new CalculatorAWT(), BorderLayout.NORTH); add(new Label(), BorderLayout.SOUTH); setVisible(true); } /** * Command-line entry point. * * @param args Command-line parameters. */ public static void main(String[] args) { new CalculatorGUI(); } } apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/CalculatorImpl.java000066400000000000000000000143171461767713300271270ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.calc; import java.util.List; /** * Calculator implementation interface. * The calculator parser uses this interface to perform the actual calculations. * * @version 1.14.0 * @author Mikko Tommila */ public interface CalculatorImpl { /** * Negative value. * * @param x The argument. * * @return -x * * @exception ParseException In case of invalid argument. */ public Number negate(Number x) throws ParseException; /** * Addition. * * @param x First argument. * @param y Second argument. * * @return x + y * * @exception ParseException In case of invalid arguments. */ public Number add(Number x, Number y) throws ParseException; /** * Subtraction. * * @param x First argument. * @param y Second argument. * * @return x - y * * @exception ParseException In case of invalid arguments. */ public Number subtract(Number x, Number y) throws ParseException; /** * Multiplication. * * @param x First argument. * @param y Second argument. * * @return x * y * * @exception ParseException In case of invalid arguments. */ public Number multiply(Number x, Number y) throws ParseException; /** * Division. * * @param x First argument. * @param y Second argument. * * @return x / y * * @exception ParseException In case of invalid arguments. */ public Number divide(Number x, Number y) throws ParseException; /** * Remainder. * * @param x First argument. * @param y Second argument. * * @return x % y * * @exception ParseException In case of invalid arguments. */ public Number mod(Number x, Number y) throws ParseException; /** * Power. * * @param x First argument. * @param y Second argument. * * @return xy * * @exception ParseException In case of invalid arguments. */ public Number pow(Number x, Number y) throws ParseException; /** * Factorial. * * @param x The argument. * * @return x! * * @exception ParseException In case of invalid arguments. */ public Number factorial(Number x) throws ParseException; /** * Double factorial. * * @param x The argument. * * @return x!! * * @exception ParseException In case of invalid arguments. */ public Number doubleFactorial(Number x) throws ParseException; /** * Arbitrary function. * * @param name Name of the function. * @param arguments Function arguments. * * @return Function value. * * @exception ParseException In case of invalid arguments. */ public Number function(String name, List arguments) throws ParseException; /** * Parse a string to an integer number. * * @param value The string to parse. * * @return The number. * * @exception ParseException In case of invalid number. */ public Number parseInteger(String value) throws ParseException; /** * Parse a string to a floating-point number. * * @param value The string to parse. * * @return The number. * * @exception ParseException In case of invalid number. */ public Number parseDecimal(String value) throws ParseException; /** * Get a variable. * * @param name Name of the variable. * * @return Value of the variable, or null if the variable is not defined. * * @exception ParseException In case of invalid argument. */ public Number getVariable(String name) throws ParseException; /** * Set a variable. * * @param name Name of the variable. * @param value Value of the variable. * * @exception ParseException In case of invalid arguments. */ public void setVariable(String name, Number value) throws ParseException; /** * Set the formatting option. * * @param pretty If a fixed-point or a floating-point notation should be used. */ public void setFormat(boolean pretty); /** * Set a fixed input precision. * * @param inputPrecision The precision if a fixed precision is used or null for arbitrary precision. */ public void setInputPrecision(Long inputPrecision); /** * Convert a number to a String. The current formatting option is used. * * @param x The number. * * @return The String. */ public String format(Number x); } apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/CalculatorParser.jj000066400000000000000000000153431461767713300271440ustar00rootroot00000000000000options { LOOKAHEAD = 2; STATIC = false; UNICODE_INPUT = true; ERROR_REPORTING = false; } PARSER_BEGIN(CalculatorParser) package org.apfloat.calc; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.util.List; import java.util.ArrayList; public class CalculatorParser { public CalculatorParser(InputStream in, OutputStream out, CalculatorImpl calculatorImpl) { this(in); this.out = new PrintWriter(new OutputStreamWriter(out), true); this.calculatorImpl = calculatorImpl; } public CalculatorParser(Reader in, Writer out, CalculatorImpl calculatorImpl) { this(in); this.out = new PrintWriter(out, true); this.calculatorImpl = calculatorImpl; } public CalculatorParser(Reader in, PrintWriter out, CalculatorImpl calculatorImpl) { this(in); this.out = out; this.calculatorImpl = calculatorImpl; } private PrintWriter out; private CalculatorImpl calculatorImpl; } PARSER_END(CalculatorParser) SKIP: { " " | "\t" } TOKEN: { < INTEGER: (()+ ()? | ()) > | < DECIMAL: (()+ ("." ()*)? | "." ()+) (["e","E"] (["+","-"])? ()+)? ()? > | < DIGIT: ["0"-"9"] > | < IMAGINARY: ["i","I"] > | < IDENTIFIER: () ( | )* > | < LETTER: ["$","A"-"Z","_","a"-"z","\u00c0"-"\u00d6","\u00d8"-"\u00f6","\u00f8"-"\u00ff","\u0100"-"\u1fff","\u3040"-"\u318f","\u3300"-"\u337f","\u3400"-"\u3d2d","\u4e00"-"\u9fff","\uf900"-"\ufaff"] > | < DELIMITER: (";")+ > | < EOL: ("\n" | "\r\n" | "\r") > } boolean parseOneLine(): { Number a; } { ( a = expression() { this.out.println(this.calculatorImpl.format(a)); } )? ( a = expression() { this.out.println(this.calculatorImpl.format(a)); } )* ( )? ( { return true; } | { return false; } ) } Number expression(): { Number a; } { ( a = assignmentExpression() | a = additiveExpression() ) { return a; } } Number assignmentExpression(): { String v; Number a; } { v = variable() ( "=" a = additiveExpression() { this.calculatorImpl.setVariable(v, a); } | "+=" a = additiveExpression() { this.calculatorImpl.setVariable(v, this.calculatorImpl.add(this.calculatorImpl.getVariable(v), a)); } | "-=" a = additiveExpression() { this.calculatorImpl.setVariable(v, this.calculatorImpl.subtract(this.calculatorImpl.getVariable(v), a)); } | "*=" a = additiveExpression() { this.calculatorImpl.setVariable(v, this.calculatorImpl.multiply(this.calculatorImpl.getVariable(v), a)); } | "/=" a = additiveExpression() { this.calculatorImpl.setVariable(v, this.calculatorImpl.divide(this.calculatorImpl.getVariable(v), a)); } | "%=" a = additiveExpression() { this.calculatorImpl.setVariable(v, this.calculatorImpl.mod(this.calculatorImpl.getVariable(v), a)); } | "^=" a = additiveExpression() { this.calculatorImpl.setVariable(v, this.calculatorImpl.pow(this.calculatorImpl.getVariable(v), a)); } ) { return this.calculatorImpl.getVariable(v); } } Number additiveExpression(): { Number a; Number b; } { a = multiplicativeExpression() ( "+" b = multiplicativeExpression() { a = this.calculatorImpl.add(a, b); } | "-" b = multiplicativeExpression() { a = this.calculatorImpl.subtract(a, b); } )* { return a; } } Number multiplicativeExpression(): { Number a; Number b; } { a = unaryExpression() ( "*" b = unaryExpression() { a = this.calculatorImpl.multiply(a, b); } | "/" b = unaryExpression() { a = this.calculatorImpl.divide(a, b); } | "%" b = unaryExpression() { a = this.calculatorImpl.mod(a, b); } )* { return a; } } Number unaryExpression(): { Number a; } { "-" a = unaryExpression() { return this.calculatorImpl.negate(a); } | "+" a = unaryExpression() { return a; } | a = powerExpression() { return a; } } Number powerExpression(): { Number a; Number b; } { a = factorialExpression() ( "^" b = unaryExpression() { a = this.calculatorImpl.pow(a, b); } )? { return a; } } Number factorialExpression(): { Number a; } { a = element() ( "!!" { a = this.calculatorImpl.doubleFactorial(a); } | "!" { a = this.calculatorImpl.factorial(a); } )* { return a; } } Number element(): { String v; Number a; } { a = constant() { return a; } | a = function() { return a; } | v = variable() { return this.calculatorImpl.getVariable(v); } | "(" a = expression() ")" { return a; } } String variable(): { String v; } { v = identifier() { return v; } } Number function(): { String v; List l; Number a; } { v = identifier() "(" l = argumentList() ")" { return this.calculatorImpl.function(v, l); } } List argumentList(): { List list = new ArrayList(); Number a; } { ( a = expression() { list.add(a); } ( "," a = expression() { list.add(a); } )* )? { return list; } } String identifier(): { Token t; } { t = { return t.toString(); } } Number constant(): { Token t; } { t = { return this.calculatorImpl.parseInteger(t.toString()); } | t = { return this.calculatorImpl.parseDecimal(t.toString()); } } TOKEN: { < INVALID_CHAR: ~[] > } apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/FunctionCalculatorImpl.java000066400000000000000000000774341461767713300306460ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.calc; import java.io.Serializable; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Calculator implementation with function support. * Provides a mapping mechanism for functions. * * @version 1.14.0 * @author Mikko Tommila */ public abstract class FunctionCalculatorImpl extends AbstractCalculatorImpl { private static final long serialVersionUID = 1L; /** * Arbitrary function. */ @FunctionalInterface protected static interface Function extends Serializable { /** * Call the function. * * @param arguments The function's arguments. * * @return The function's value. * * @exception ParseException In case the arguments are invalid. */ public Number call(List arguments) throws ParseException; } /** * Function taking a fixed number of arguments. */ protected class FixedFunction implements Function { private static final long serialVersionUID = 1L; /** * Validate the number of arguments. * * @param arguments The function's arguments. * * @exception ParseException In case of incorrect number of arguments. */ protected void validate(List arguments) throws ParseException { if (this.minArguments == this.maxArguments && arguments.size() != this.minArguments) { throw new ParseException("Function " + this.name + " takes " + this.minArguments + " argument" + (this.minArguments == 1 ? "" : "s") + ", not " + arguments.size()); } if (arguments.size() < this.minArguments || arguments.size() > this.maxArguments) { throw new ParseException("Function " + this.name + " takes " + this.minArguments + " to " + this.maxArguments + " arguments, not " + arguments.size()); } } @Override public final Number call(List arguments) throws ParseException { validate(arguments); return promote(handler.call(getFunctions(arguments), arguments)); } private String name; private int minArguments; private int maxArguments; private FixedFunctionHandler handler; } /** * Handler for FixedFunction. */ @FunctionalInterface protected static interface FixedFunctionHandler extends Serializable { /** * Call the function. * * @param functions The function implementations. * @param arguments The function's argument(s). * * @return The function's value. */ public Number call(Functions functions, List arguments); } /** * Function implementations. */ protected static interface Functions { public Number negate(Number x); public Number add(Number x, Number y); public Number subtract(Number x, Number y); public Number multiply(Number x, Number y); public Number divide(Number x, Number y); public Number mod(Number x, Number y); public Number pow(Number x, Number y); public Number arg(Number x); public Number conj(Number x); public Number imag(Number x); public Number real(Number x); public Number abs(Number x); public Number acos(Number x); public Number acosh(Number x); public Number airyAi(Number x); public Number airyAiPrime(Number x); public Number airyBi(Number x); public Number airyBiPrime(Number x); public Number asin(Number x); public Number asinh(Number x); public Number atan(Number x); public Number atanh(Number x); public Number bernoulli(Number x); public Number bernoulliB(Number x, Number y); public Number besselI(Number x, Number y); public Number besselJ(Number x, Number y); public Number besselK(Number x, Number y); public Number besselY(Number x, Number y); public Number beta(Number a, Number b); public Number beta(Number x, Number a, Number b); public Number beta(Number x1, Number x2, Number a, Number b); public Number binomial(Number x, Number y); public Number catalan(Number x); public Number cbrt(Number x); public Number ceil(Number x); public Number chebyshevT(Number x, Number y); public Number chebyshevU(Number x, Number y); public Number cos(Number x); public Number cosIntegral(Number x); public Number cosh(Number x); public Number coshIntegral(Number x); public Number digamma(Number x); public Number doubleFactorial(Number x); public Number e(Number x); public Number ellipticE(Number x); public Number ellipticK(Number x); public Number erf(Number x); public Number erfc(Number x); public Number erfi(Number x); public Number euler(Number x); public Number eulerE(Number x, Number y); public Number exp(Number x); public Number expIntegralE(Number x, Number y); public Number expIntegralEi(Number x); public Number factorial(Number x); public Number fibonacci(Number x, Number y); public Number floor(Number x); public Number frac(Number x); public Number fresnelC(Number x); public Number fresnelS(Number x); public Number gamma(Number x); public Number gamma(Number x, Number y); public Number gamma(Number x, Number y, Number z); public Number gegenbauerC(Number x, Number y); public Number gegenbauerC(Number x, Number y, Number z); public Number harmonicNumber(Number x); public Number harmonicNumber(Number x, Number y); public Number hermiteH(Number x, Number y); public Number hypergeometric0F1(Number a, Number z); public Number hypergeometric0F1Regularized(Number a, Number z); public Number hypergeometric1F1(Number a, Number b, Number z); public Number hypergeometric1F1Regularized(Number a, Number b, Number z); public Number hypergeometric2F1(Number a, Number b, Number c, Number z); public Number hypergeometric2F1Regularized(Number a, Number b, Number c, Number z); public Number hypergeometricU(Number a, Number b, Number z); public Number inverseErf(Number x); public Number inverseErfc(Number x); public Number jacobiP(Number x, Number y, Number z, Number w); public Number glaisher(Number x); public Number khinchin(Number x); public Number laguerreL(Number x, Number y); public Number laguerreL(Number x, Number y, Number z); public Number legendreP(Number x, Number y); public Number legendreP(Number x, Number y, Number z); public Number legendreQ(Number x, Number y); public Number legendreQ(Number x, Number y, Number z); public Number log(Number x); public Number log(Number x, Number y); public Number logGamma(Number x); public Number logIntegral(Number x); public Number logisticSigmoid(Number x); public Number max(Number x, Number y); public Number min(Number x, Number y); public Number nextAfter(Number x, Number y); public Number nextDown(Number x); public Number nextUp(Number x); public Number pi(Number x); public Number pochhammer(Number x, Number y); public Number polygamma(Number x, Number y); public Number polylog(Number x, Number y); public Number random(Number x); public Number randomGaussian(Number x); @Deprecated public Number round(Number x, Number y); public Number roundToPrecision(Number x, Number y); public Number roundToInteger(Number x); public Number roundToPlaces(Number x, Number y); public Number roundToMultiple(Number x, Number y); public Number sin(Number x); public Number sinc(Number x); public Number sinIntegral(Number x); public Number sinh(Number x); public Number sinhIntegral(Number x); public Number sphericalHarmonicY(Number x, Number y, Number z, Number w); public Number sqrt(Number x); public Number tan(Number x); public Number tanh(Number x); public Number truncate(Number x); public Number toDegrees(Number x); public Number toRadians(Number x); public Number ulp(Number x); public Number zeta(Number x); public Number zeta(Number x, Number y); public Number agm(Number x, Number y); public Number w(Number x); public Number w(Number x, Number y); public Number atan2(Number x, Number y); public Number copySign(Number x, Number y); public Number fmod(Number x, Number y); public Number gcd(Number x, Number y); public Number hypot(Number x, Number y); public Number inverseRoot(Number x, Number y); public Number inverseRoot(Number x, Number y, Number z); public Number lcm(Number x, Number y); public Number root(Number x, Number y); public Number root(Number x, Number y, Number z); public Number scale(Number x, Number y); public Number precision(Number x, Number y); } /** * Default constructor. */ protected FunctionCalculatorImpl() { this.functions = new HashMap<>(); setFunction("negate", fixedFunction("negate", 1, (functions, arguments) -> functions.negate(arguments.get(0)))); setFunction("add", fixedFunction("add", 2, (functions, arguments) -> functions.add(arguments.get(0), arguments.get(1)))); setFunction("subtract", fixedFunction("subtract", 2, (functions, arguments) -> functions.subtract(arguments.get(0), arguments.get(1)))); setFunction("multiply", fixedFunction("multiply", 2, (functions, arguments) -> functions.multiply(arguments.get(0), arguments.get(1)))); setFunction("divide", fixedFunction("divide", 2, (functions, arguments) -> functions.divide(arguments.get(0), arguments.get(1)))); setFunction("mod", fixedFunction("mod", 2, (functions, arguments) -> functions.mod(arguments.get(0), arguments.get(1)))); setFunction("pow", fixedFunction("pow", 2, (functions, arguments) -> functions.pow(arguments.get(0), arguments.get(1)))); setFunction("abs", fixedFunction("abs", 1, (functions, arguments) -> functions.abs(arguments.get(0)))); setFunction("acos", fixedFunction("acos", 1, (functions, arguments) -> functions.acos(arguments.get(0)))); setFunction("acosh", fixedFunction("acosh", 1, (functions, arguments) -> functions.acosh(arguments.get(0)))); setFunction("airyAi", fixedFunction("airyAi", 1, (functions, arguments) -> functions.airyAi(arguments.get(0)))); setFunction("airyAiPrime", fixedFunction("airyAiPrime", 1, (functions, arguments) -> functions.airyAiPrime(arguments.get(0)))); setFunction("airyBi", fixedFunction("airyBi", 1, (functions, arguments) -> functions.airyBi(arguments.get(0)))); setFunction("airyBiPrime", fixedFunction("airyBiPrime", 1, (functions, arguments) -> functions.airyBiPrime(arguments.get(0)))); setFunction("asin", fixedFunction("asin", 1, (functions, arguments) -> functions.asin(arguments.get(0)))); setFunction("asinh", fixedFunction("asinh", 1, (functions, arguments) -> functions.asinh(arguments.get(0)))); setFunction("atan", fixedFunction("atan", 1, (functions, arguments) -> functions.atan(arguments.get(0)))); setFunction("atanh", fixedFunction("atanh", 1, (functions, arguments) -> functions.atanh(arguments.get(0)))); setFunction("bernoulli", fixedFunction("bernoulli", 1, (functions, arguments) -> functions.bernoulli(arguments.get(0)))); setFunction("bernoulliB", fixedFunction("bernoulliB", 2, (functions, arguments) -> functions.bernoulliB(arguments.get(0), arguments.get(1)))); setFunction("besselI", fixedFunction("besselI", 2, (functions, arguments) -> functions.besselI(arguments.get(0), arguments.get(1)))); setFunction("besselJ", fixedFunction("besselJ", 2, (functions, arguments) -> functions.besselJ(arguments.get(0), arguments.get(1)))); setFunction("besselK", fixedFunction("besselK", 2, (functions, arguments) -> functions.besselK(arguments.get(0), arguments.get(1)))); setFunction("besselY", fixedFunction("besselY", 2, (functions, arguments) -> functions.besselY(arguments.get(0), arguments.get(1)))); setFunction("beta", fixedFunction("beta", 2, 4, (functions, arguments) -> (arguments.size() == 2 ? functions.beta(arguments.get(0), arguments.get(1)) : arguments.size() == 3 ? functions.beta(arguments.get(0), arguments.get(1), arguments.get(2)): functions.beta(arguments.get(0), arguments.get(1), arguments.get(2), arguments.get(3))))); setFunction("binomial", fixedFunction("binomial", 2, (functions, arguments) -> functions.binomial(arguments.get(0), arguments.get(1)))); setFunction("catalan", fixedFunction("catalan", 0, 1, (functions, arguments) -> functions.catalan(argumentOrInputPrecision(arguments)))); setFunction("cbrt", fixedFunction("cbrt", 1, (functions, arguments) -> functions.cbrt(arguments.get(0)))); setFunction("ceil", fixedFunction("ceil", 1, (functions, arguments) -> functions.ceil(arguments.get(0)))); setFunction("chebyshevT", fixedFunction("chebyshevT", 2, (functions, arguments) -> functions.chebyshevT(arguments.get(0), arguments.get(1)))); setFunction("chebyshevU", fixedFunction("chebyshevU", 2, (functions, arguments) -> functions.chebyshevU(arguments.get(0), arguments.get(1)))); setFunction("cos", fixedFunction("cos", 1, (functions, arguments) -> functions.cos(arguments.get(0)))); setFunction("cosIntegral", fixedFunction("cosIntegral", 1, (functions, arguments) -> functions.cosIntegral(arguments.get(0)))); setFunction("cosh", fixedFunction("cosh", 1, (functions, arguments) -> functions.cosh(arguments.get(0)))); setFunction("coshIntegral", fixedFunction("coshIntegral", 1, (functions, arguments) -> functions.coshIntegral(arguments.get(0)))); setFunction("digamma", fixedFunction("digamma", 1, (functions, arguments) -> functions.digamma(arguments.get(0)))); setFunction("doubleFactorial", fixedFunction("doubleFactorial", 1, (functions, arguments) -> functions.doubleFactorial(arguments.get(0)))); setFunction("e", fixedFunction("e", 0, 1, (functions, arguments) -> functions.e(argumentOrInputPrecision(arguments)))); setFunction("ellipticE", fixedFunction("ellipticE", 1, (functions, arguments) -> functions.ellipticE(arguments.get(0)))); setFunction("ellipticK", fixedFunction("ellipticK", 1, (functions, arguments) -> functions.ellipticK(arguments.get(0)))); setFunction("erf", fixedFunction("erf", 1, (functions, arguments) -> functions.erf(arguments.get(0)))); setFunction("erfc", fixedFunction("erfc", 1, (functions, arguments) -> functions.erfc(arguments.get(0)))); setFunction("erfi", fixedFunction("erfi", 1, (functions, arguments) -> functions.erfi(arguments.get(0)))); setFunction("euler", fixedFunction("euler", 0, 1, (functions, arguments) -> functions.euler(argumentOrInputPrecision(arguments)))); setFunction("eulerE", fixedFunction("eulerE", 2, (functions, arguments) -> functions.eulerE(arguments.get(0), arguments.get(1)))); setFunction("exp", fixedFunction("exp", 1, (functions, arguments) -> functions.exp(arguments.get(0)))); setFunction("expIntegralE", fixedFunction("expIntegralE", 2, (functions, arguments) -> functions.expIntegralE(arguments.get(0), arguments.get(1)))); setFunction("expIntegralEi", fixedFunction("expIntegralEi", 1, (functions, arguments) -> functions.expIntegralEi(arguments.get(0)))); setFunction("factorial", fixedFunction("factorial", 1, (functions, arguments) -> functions.factorial(arguments.get(0)))); setFunction("fibonacci", fixedFunction("fibonacci", 2, (functions, arguments) -> functions.fibonacci(arguments.get(0), arguments.get(1)))); setFunction("floor", fixedFunction("floor", 1, (functions, arguments) -> functions.floor(arguments.get(0)))); setFunction("frac", fixedFunction("frac", 1, (functions, arguments) -> functions.frac(arguments.get(0)))); setFunction("fresnelC", fixedFunction("fresnelC", 1, (functions, arguments) -> functions.fresnelC(arguments.get(0)))); setFunction("fresnelS", fixedFunction("fresnelS", 1, (functions, arguments) -> functions.fresnelS(arguments.get(0)))); setFunction("gamma", fixedFunction("gamma", 1, 3, (functions, arguments) -> (arguments.size() == 1 ? functions.gamma(arguments.get(0)) : arguments.size() == 2 ? functions.gamma(arguments.get(0), arguments.get(1)): functions.gamma(arguments.get(0), arguments.get(1), arguments.get(2))))); setFunction("gegenbauerC", fixedFunction("gegenbauerC", 2, 3, (functions, arguments) -> (arguments.size() == 2 ? functions.gegenbauerC(arguments.get(0), arguments.get(1)) : functions.gegenbauerC(arguments.get(0), arguments.get(1), arguments.get(2))))); setFunction("glaisher", fixedFunction("glaisher", 0, 1, (functions, arguments) -> functions.glaisher(argumentOrInputPrecision(arguments)))); setFunction("harmonicNumber", fixedFunction("harmonicNumber", 1, 2, (functions, arguments) -> (arguments.size() == 1 ? functions.harmonicNumber(arguments.get(0)) : functions.harmonicNumber(arguments.get(0), arguments.get(1))))); setFunction("hermiteH", fixedFunction("hermiteH", 2, (functions, arguments) -> functions.hermiteH(arguments.get(0), arguments.get(1)))); setFunction("hypergeometric0F1", fixedFunction("hypergeometric0F1", 2, (functions, arguments) -> functions.hypergeometric0F1(arguments.get(0), arguments.get(1)))); setFunction("hypergeometric0F1Regularized", fixedFunction("hypergeometric0F1Regularized", 2, (functions, arguments) -> functions.hypergeometric0F1Regularized(arguments.get(0), arguments.get(1)))); setFunction("hypergeometric1F1", fixedFunction("hypergeometric1F1", 3, (functions, arguments) -> functions.hypergeometric1F1(arguments.get(0), arguments.get(1), arguments.get(2)))); setFunction("hypergeometric1F1Regularized", fixedFunction("hypergeometric1F1Regularized", 3, (functions, arguments) -> functions.hypergeometric1F1Regularized(arguments.get(0), arguments.get(1), arguments.get(2)))); setFunction("hypergeometric2F1", fixedFunction("hypergeometric2F1", 4, (functions, arguments) -> functions.hypergeometric2F1(arguments.get(0), arguments.get(1), arguments.get(2), arguments.get(3)))); setFunction("hypergeometric2F1Regularized", fixedFunction("hypergeometric2F1Regularized", 4, (functions, arguments) -> functions.hypergeometric2F1Regularized(arguments.get(0), arguments.get(1), arguments.get(2), arguments.get(3)))); setFunction("hypergeometricU", fixedFunction("hypergeometricU", 3, (functions, arguments) -> functions.hypergeometricU(arguments.get(0), arguments.get(1), arguments.get(2)))); setFunction("inverseErf", fixedFunction("inverseErf", 1, (functions, arguments) -> functions.inverseErf(arguments.get(0)))); setFunction("inverseErfc", fixedFunction("inverseErfc", 1, (functions, arguments) -> functions.inverseErfc(arguments.get(0)))); setFunction("jacobiP", fixedFunction("jacobiP", 4, (functions, arguments) -> functions.jacobiP(arguments.get(0), arguments.get(1), arguments.get(2), arguments.get(3)))); setFunction("khinchin", fixedFunction("khinchin", 0, 1, (functions, arguments) -> functions.khinchin(argumentOrInputPrecision(arguments)))); setFunction("laguerreL", fixedFunction("laguerreL", 2, 3, (functions, arguments) -> (arguments.size() == 2 ? functions.laguerreL(arguments.get(0), arguments.get(1)) : functions.laguerreL(arguments.get(0), arguments.get(1), arguments.get(2))))); setFunction("legendreP", fixedFunction("legendreP", 2, 3, (functions, arguments) -> (arguments.size() == 2 ? functions.legendreP(arguments.get(0), arguments.get(1)) : functions.legendreP(arguments.get(0), arguments.get(1), arguments.get(2))))); setFunction("legendreQ", fixedFunction("legendreQ", 2, 3, (functions, arguments) -> (arguments.size() == 2 ? functions.legendreQ(arguments.get(0), arguments.get(1)) : functions.legendreQ(arguments.get(0), arguments.get(1), arguments.get(2))))); setFunction("log", fixedFunction("log", 1, 2, (functions, arguments) -> (arguments.size() == 1 ? functions.log(arguments.get(0)) : functions.log(arguments.get(0), arguments.get(1))))); setFunction("logGamma", fixedFunction("logGamma", 1, (functions, arguments) -> functions.logGamma(arguments.get(0)))); setFunction("logIntegral", fixedFunction("logIntegral", 1, (functions, arguments) -> functions.logIntegral(arguments.get(0)))); setFunction("logisticSigmoid", fixedFunction("logisticSigmoid", 1, (functions, arguments) -> functions.logisticSigmoid(arguments.get(0)))); setFunction("max", fixedFunction("max", 2, (functions, arguments) -> functions.max(arguments.get(0), arguments.get(1)))); setFunction("min", fixedFunction("min", 2, (functions, arguments) -> functions.min(arguments.get(0), arguments.get(1)))); setFunction("nextAfter", fixedFunction("nextAfter", 2, (functions, arguments) -> functions.nextAfter(arguments.get(0), arguments.get(1)))); setFunction("nextDown", fixedFunction("nextDown", 1, (functions, arguments) -> functions.nextDown(arguments.get(0)))); setFunction("nextUp", fixedFunction("nextUp", 1, (functions, arguments) -> functions.nextUp(arguments.get(0)))); setFunction("pi", fixedFunction("pi", 0, 1, (functions, arguments) -> functions.pi(argumentOrInputPrecision(arguments)))); setFunction("pochhammer", fixedFunction("pochhammer", 2, (functions, arguments) -> functions.pochhammer(arguments.get(0), arguments.get(1)))); setFunction("polygamma", fixedFunction("polygamma", 2, (functions, arguments) -> functions.polygamma(arguments.get(0), arguments.get(1)))); setFunction("polylog", fixedFunction("polylog", 2, (functions, arguments) -> functions.polylog(arguments.get(0), arguments.get(1)))); setFunction("random", fixedFunction("random", 0, 1, (functions, arguments) -> functions.random(argumentOrInputPrecision(arguments)))); setFunction("randomGaussian", fixedFunction("randomGaussian", 0, 1, (functions, arguments) -> functions.randomGaussian(argumentOrInputPrecision(arguments)))); setFunction("round", fixedFunction("round", 2, (functions, arguments) -> functions.round(arguments.get(0), arguments.get(1)))); setFunction("roundToPrecision", fixedFunction("roundToPrecision", 2, (functions, arguments) -> functions.roundToPrecision(arguments.get(0), arguments.get(1)))); setFunction("roundToInteger", fixedFunction("roundToInteger", 1, (functions, arguments) -> functions.roundToInteger(arguments.get(0)))); setFunction("roundToPlaces", fixedFunction("roundToPlaces", 2, (functions, arguments) -> functions.roundToPlaces(arguments.get(0), arguments.get(1)))); setFunction("roundToMultiple", fixedFunction("roundToMultiple", 2, (functions, arguments) -> functions.roundToMultiple(arguments.get(0), arguments.get(1)))); setFunction("sin", fixedFunction("sin", 1, (functions, arguments) -> functions.sin(arguments.get(0)))); setFunction("sinc", fixedFunction("sinc", 1, (functions, arguments) -> functions.sinc(arguments.get(0)))); setFunction("sinIntegral", fixedFunction("sinIntegral", 1, (functions, arguments) -> functions.sinIntegral(arguments.get(0)))); setFunction("sinh", fixedFunction("sinh", 1, (functions, arguments) -> functions.sinh(arguments.get(0)))); setFunction("sinhIntegral", fixedFunction("sinhIntegral", 1, (functions, arguments) -> functions.sinhIntegral(arguments.get(0)))); setFunction("sphericalHarmonicY", fixedFunction("sphericalHarmonicY", 4, (functions, arguments) -> functions.sphericalHarmonicY(arguments.get(0), arguments.get(1), arguments.get(2), arguments.get(3)))); setFunction("sqrt", fixedFunction("sqrt", 1, (functions, arguments) -> functions.sqrt(arguments.get(0)))); setFunction("tan", fixedFunction("tan", 1, (functions, arguments) -> functions.tan(arguments.get(0)))); setFunction("tanh", fixedFunction("tanh", 1, (functions, arguments) -> functions.tanh(arguments.get(0)))); setFunction("truncate", fixedFunction("truncate", 1, (functions, arguments) -> functions.truncate(arguments.get(0)))); setFunction("toDegrees", fixedFunction("toDegrees", 1, (functions, arguments) -> functions.toDegrees(arguments.get(0)))); setFunction("toRadians", fixedFunction("toRadians", 1, (functions, arguments) -> functions.toRadians(arguments.get(0)))); setFunction("ulp", fixedFunction("ulp", 1, (functions, arguments) -> functions.ulp(arguments.get(0)))); setFunction("zeta", fixedFunction("zeta", 1, 2, (functions, arguments) -> (arguments.size() == 1 ? functions.zeta(arguments.get(0)) : functions.zeta(arguments.get(0), arguments.get(1))))); setFunction("arg", fixedFunction("arg", 1, (functions, arguments) -> functions.arg(arguments.get(0)))); setFunction("conj", fixedFunction("conj", 1, (functions, arguments) -> functions.conj(arguments.get(0)))); setFunction("imag", fixedFunction("imag", 1, (functions, arguments) -> functions.imag(arguments.get(0)))); setFunction("real", fixedFunction("real", 1, (functions, arguments) -> functions.real(arguments.get(0)))); setFunction("agm", fixedFunction("agm", 2, (functions, arguments) -> functions.agm(arguments.get(0), arguments.get(1)))); setFunction("w", fixedFunction("w", 1, 2, (functions, arguments) -> (arguments.size() == 1 ? functions.w(arguments.get(0)) : functions.w(arguments.get(0), arguments.get(1))))); setFunction("atan2", fixedFunction("atan2", 2, (functions, arguments) -> functions.atan2(arguments.get(0), arguments.get(1)))); setFunction("copySign", fixedFunction("copySign", 2, (functions, arguments) -> functions.copySign(arguments.get(0), arguments.get(1)))); setFunction("fmod", fixedFunction("fmod", 2, (functions, arguments) -> functions.fmod(arguments.get(0), arguments.get(1)))); setFunction("gcd", fixedFunction("gcd", 2, (functions, arguments) -> functions.gcd(arguments.get(0), arguments.get(1)))); setFunction("hypot", fixedFunction("hypot", 2, (functions, arguments) -> functions.hypot(arguments.get(0), arguments.get(1)))); setFunction("inverseRoot", fixedFunction("inverseRoot", 2, 3, (functions, arguments) -> (arguments.size() == 2 ? functions.inverseRoot(arguments.get(0), arguments.get(1)) : functions.inverseRoot(arguments.get(0), arguments.get(1), arguments.get(2))))); setFunction("lcm", fixedFunction("lcm", 2, (functions, arguments) -> functions.lcm(arguments.get(0), arguments.get(1)))); setFunction("root", fixedFunction("root", 2, 3, (functions, arguments) -> (arguments.size() == 2 ? functions.root(arguments.get(0), arguments.get(1)) : functions.root(arguments.get(0), arguments.get(1), arguments.get(2))))); setFunction("scale", fixedFunction("scale", 2, (functions, arguments) -> functions.scale(arguments.get(0), arguments.get(1)))); setFunction("n", fixedFunction("precision", 2, (functions, arguments) -> functions.precision(arguments.get(0), arguments.get(1)))); } @Override public Number function(String name, List arguments) throws ParseException { Function function = functions.get(name); if (function == null) { throw new ParseException("Invalid function: " + name); } return function.call(arguments); } private Functions getFunctions(List arguments) { Functions functions = (arguments.isEmpty() ? getFunctions((Number) null) : null); for (Number argument : arguments) { Functions functions2 = getFunctions(argument); functions = (functions != null && functions.getClass().isAssignableFrom(functions2.getClass()) ? functions : functions2); } return functions; } private Number argumentOrInputPrecision(List arguments) { return arguments.size() == 0 ? getInputPrecision() : arguments.get(0); } /** * Factory method. * * @param name The function's name. * @param arguments The number of arguments that the function takes. * @param handler The handler of the function. * * @return The function. */ protected FixedFunction fixedFunction(String name, int arguments, FixedFunctionHandler handler) { return fixedFunction(name, arguments, arguments, handler); } /** * Factory method. * * @param name The function's name. * @param minArguments The minimum number of arguments that the function takes. * @param maxArguments The maximum number of arguments that the function takes. * @param handler The handler of the function. * * @return The function. */ protected FixedFunction fixedFunction(String name, int minArguments, int maxArguments, FixedFunctionHandler handler) { FixedFunction fixedFunction = new FixedFunction(); fixedFunction.name = name; fixedFunction.minArguments = minArguments; fixedFunction.maxArguments = maxArguments; fixedFunction.handler = handler; return fixedFunction; } /** * Define a function. * * @param name The function name. * @param function The function. */ protected void setFunction(String name, Function function) { this.functions.put(name, function); } /** * Get the function implementations. * * @param x The number to use as the function argument. * * @return The function implementations. */ protected abstract Functions getFunctions(Number x); /** * Promote a number to a more specific class. * * @param x The argument. * * @return The argument, possibly converted to a more specific subclass. */ protected abstract Number promote(Number x); private Map functions; } apfloat-1.14.0/apfloat-calc/src/main/java/org/apfloat/calc/package-info.java000066400000000000000000000023551461767713300265370ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** Arbitrary precision calculator interactive application. */ package org.apfloat.calc; apfloat-1.14.0/apfloat-calc/src/test/000077500000000000000000000000001461767713300173365ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/test/java/000077500000000000000000000000001461767713300202575ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/test/java/org/000077500000000000000000000000001461767713300210465ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/test/java/org/apfloat/000077500000000000000000000000001461767713300224745ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/test/java/org/apfloat/calc/000077500000000000000000000000001461767713300233765ustar00rootroot00000000000000apfloat-1.14.0/apfloat-calc/src/test/java/org/apfloat/calc/CalculatorTest.java000066400000000000000000001212631461767713300271770ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.calc; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.PrintStream; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.14.0 * @author Mikko Tommila */ public class CalculatorTest extends TestCase { public CalculatorTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new CalculatorTest("testOperators")); suite.addTest(new CalculatorTest("testFunctions")); suite.addTest(new CalculatorTest("testArguments")); return suite; } private static void assertCalculation(String expected, String input, String... args) throws ParseException { String actual = runCalculation(input, args); assertEquals(input, expected + NEWLINE, actual); } private static void assertCalculationMatch(String expectedPattern, String input, String... args) throws ParseException { String actual = runCalculation(input, args); if (!actual.matches('(' + expectedPattern + ')' + NEWLINE)) { assertEquals(input, expectedPattern + NEWLINE, actual); } } private static String runCalculation(String input, String... args) throws ParseException { InputStream oldIn = System.in; PrintStream oldOut = System.out; String actual; try { InputStream in = new ByteArrayInputStream(input.getBytes()); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); PrintStream out = new PrintStream(buffer, true); System.setIn(in); System.setOut(out); Calculator.main(args); actual = new String(buffer.toByteArray()); } finally { System.setIn(oldIn); System.setOut(oldOut); } return actual; } private static void assertCalculationFailure(String input, String... args) { try { runCalculation(input, args); fail(input + " accepted"); } catch (ParseException pe) { // OK: syntax error } catch (ArithmeticException ae) { // OK: result is not a number } catch (IllegalArgumentException iae) { // OK: invalid parameter } catch (org.apfloat.ApfloatRuntimeException are) { // OK: attempt invalid calculation } } public static void testOperators() throws ParseException { assertCalculation("163", "1+2*3^4"); assertCalculation("77", "99-22"); assertCalculation("7.7e1", "99.1-22.1"); assertCalculation("i", "2i-i"); assertCalculation("5" + NEWLINE + "11", "x = 5; x + 6"); assertCalculation("5" + NEWLINE + "11" + NEWLINE + "11", "x = 5; x += 6; x"); assertCalculation("5" + NEWLINE + "-1" + NEWLINE + "-1", "x = 5; x -= 6; x"); assertCalculation("5" + NEWLINE + "30" + NEWLINE + "30", "x = 5; x *= 6; x"); assertCalculation("30" + NEWLINE + "5" + NEWLINE + "5", "x = 30; x /= 6; x"); assertCalculation("31" + NEWLINE + "1" + NEWLINE + "1", "x = 31; x %= 6; x"); assertCalculation("5" + NEWLINE + "125" + NEWLINE + "125", "x = 5; x ^= 3; x"); assertCalculation("2", "5 % 3"); assertCalculation("2.1", "5.1 % 3"); assertCalculation("2", "5 + -3"); assertCalculation("7/6", "1/2 + 2/3"); assertCalculation("5e-1", "1./2"); assertCalculation("5e-1", ".5"); assertCalculation("5e-1", ".5e0"); assertCalculation("5e-1", "5e-1"); assertCalculation("5e-1", "5.e-1"); assertCalculation("5e1", "5e1"); assertCalculation("6.67", "20.0/3.00"); assertCalculation("-1", "I*I"); assertCalculation("3+2i", "2I+3"); assertCalculation("3-2i", "i*-2+3"); assertCalculation("35", "((5))*(3+4)"); assertCalculation("7", "+++++++++++++7"); assertCalculation("8", "--8"); assertCalculation("-9", "-----9"); assertCalculation("1", " ;;; \t 1 ;;;;;;;;; "); assertCalculation("1.41421", "2.0000^0.50000"); assertCalculation("8.8080652584e646456992", "2^2147483647.0"); assertCalculation("-1", "i^2"); assertCalculation("1", "1^2i"); assertCalculation("2417851639229258349412352", "2^3^4"); assertCalculation("120", "5!"); assertCalculation("15", "5!!"); assertCalculation("64", "2^3!"); assertCalculation("8", "2^3!!"); assertCalculation("1307674368000", "5!!!"); assertCalculation("2027025", "5!!!!"); assertCalculation("-24", "-4!"); assertCalculation("1/16777216", "2^-4!"); assertCalculation("-1/16777216", "-2^-4!"); assertCalculation("8", "2^3!!!!"); assertCalculation("-1/8", "-2^-3!!!!"); assertCalculation("4", "2!^2!"); assertCalculation("4", "2!!^2!!"); assertCalculationFailure("6%i"); assertCalculationFailure("5e"); assertCalculationFailure("2^^2"); assertCalculationFailure("2a2"); assertCalculationFailure("x="); assertCalculationFailure("x+="); assertCalculationFailure("x-="); assertCalculationFailure("x*="); assertCalculationFailure("x/="); assertCalculationFailure("x%="); assertCalculationFailure("x^="); assertCalculationFailure("*5"); assertCalculationFailure("/"); assertCalculationFailure("6%"); assertCalculationFailure("2-"); assertCalculationFailure("bogus^5"); assertCalculationFailure("!"); assertCalculationFailure("bogus!"); assertCalculationFailure("bogus!!"); assertCalculationFailure("5!="); assertCalculationFailure("5!=4"); } public static void testFunctions() throws ParseException { assertCalculation("3", "abs(-3)"); assertCalculation("3", "abs(-3i)"); assertCalculation("5", "abs(3.00 + 4.00I)"); assertCalculation("3.03703e-1", "airyAi(0.200000)"); assertCalculation("-2.52405e-1", "airyAiPrime(0.200000)"); assertCalculation("7.05464e-1", "airyBi(0.200000)"); assertCalculation("4.61789e-1", "airyBiPrime(0.200000)"); assertCalculation("7/6", "bernoulli(14)"); assertCalculation("3.3124e4", "bernoulliB(4,14.0000)"); assertCalculation("1.72763", "besselI(0.700000,1.90000)"); assertCalculation("5.84978e-1", "besselJ(0.700000,1.90000)"); assertCalculation("2.06052", "besselK(0.700000,0.300000)"); assertCalculation("-1.6523", "besselY(0.700000,0.300000)"); assertCalculation("3.55114", "beta(0.200000,4.00000)"); assertCalculation("3.00545", "beta(0.100000,0.200000,4.00000)"); assertCalculation("-1.02994", "beta(0.100000,2.90000,0.200000,4.00000)"); assertCalculation("1.5057e2", "binomial(9.20000,4.60000)"); assertCalculation("2.3282", "binomial(4,3.5000)"); assertCalculation("6.5625", "binomial(4.5000,3)"); assertCalculation("45", "binomial(10,2)"); assertCalculation("366166666666666666665821666666666666666667100000000000000000000", "binomial(1300000000000000000000,3)"); assertCalculation("0", "binomial(3,1300000000000000000000)"); assertCalculation("1", "binomial(1300000000000000000000,1300000000000000000000)"); assertCalculation("1040/81", "binomial(16/3,7/3)"); assertCalculation("-455/81", "binomial(-7/3,-16/3)"); assertCalculation("-1", "binomial(-1,1)"); assertCalculation("0", "binomial(1,-1)"); assertCalculation("0", "binomial(3.5,4.5)"); assertCalculation("-3.109-1.604i", "binomial(3.000+4.000i,5.000+6.000i)"); assertCalculation("9.1596559e-1", "catalan(8)"); assertCalculation("2", "cbrt(8)"); assertCalculation("2/3", "cbrt(8/27)"); assertCalculation("7.07e-1+7.07e-1i", "cbrt(-0.707+0.707i)"); assertCalculation("1.2599", "cbrt(2.0000)"); assertCalculation("2", "ceil(1.1)"); assertCalculation("2", "ceil(3/2)"); assertCalculation("1.41288", "chebyshevT(0.70000,1.9000)"); assertCalculation("2.58673", "chebyshevU(0.700000,1.90000)"); assertCalculation("-2", "copySign(2, -3)"); assertCalculation("-1.04221", "cosIntegral(0.200000)"); assertCalculation("-1.02221", "coshIntegral(0.200000)"); assertCalculation("1.7061", "digamma(6.0000)"); assertCalculation("34459425", "doubleFactorial(17)"); assertCalculation("1.48904", "ellipticE(0.200000)"); assertCalculation("1.65962", "ellipticK(0.200000)"); assertCalculation("2.22703e-1", "erf(0.200000)"); assertCalculation("7.77297e-1", "erfc(0.200000)"); assertCalculation("2.41591", "erfi(1.20000)"); assertCalculation("1.2141", "eulerE(4, 1.90000)"); assertCalculation("1.1722", "expIntegralE(0.70000,0.30000)"); assertCalculation("2.44209", "expIntegralEi(1.20000)"); assertCalculation("5040", "factorial(7)"); assertCalculation("7.3936", "fibonacci(5.00000, 1.20000)"); assertCalculation("2", "floor(2.9)"); assertCalculation("2", "floor(29/10)"); assertCalculation("9e-1", "frac(2.9)"); assertCalculation("9/10", "frac(29/10)"); assertCalculation("7.15438e-1", "fresnelC(1.20000)"); assertCalculation("6.23401e-1", "fresnelS(1.20000)"); assertCalculation("6", "gamma(4)"); assertCalculation("5.8861", "gamma(4.0000, 1.0000)"); assertCalculation("5.0928", "gamma(4.0000, 0, 6.0000)"); assertCalculation("4.74294943677064514689542753377e1-3.27488916473624576880974867017e1i", "gamma(100.000000000000000000000000000+374.000000000000000000000000000i)"); assertCalculation("-5.25676", "gegenbauerC(-1.10000,2.50000)"); assertCalculation("-2.60129", "gegenbauerC(-1.10000,-1.30000,2.50000)"); assertCalculation("1.282427", "glaisher(7)"); assertCalculation("1.12151", "harmonicNumber(1.20000)"); assertCalculation("1.104112", "harmonicNumber(1.200000,1.300000)"); assertCalculation("42142223/12252240", "harmonicNumber(17)"); assertCalculation("6301272372663207205033976933/6076911214672415134617600000", "harmonicNumber(13,5)"); assertCalculation("3.04424", "hermiteH(1.20000,1.30000)"); assertCalculation("1.453+1.237i", "hypergeometric0F1(3.456+2.890i,0.1234+4.678i)"); assertCalculation("2.6328", "hypergeometric0F1Regularized(-3.00000,2.50000)"); assertCalculation("-7.477+3.738i", "hypergeometric1F1(3.456+2.890i,3.456+2.890i,2.1234+2.678i)"); assertCalculation("1.2856", "hypergeometric1F1Regularized(0.200000,-3,1.50000)"); assertCalculation("-1.477-2.073i", "hypergeometric2F1(9.456+4.890i,3.456+2.890i,1.256+1.390i,0.11234+0.1678i)"); assertCalculation("4.8317", "hypergeometric2F1Regularized(0.100000,0.200000,-3,0.800000)"); assertCalculation("4.99704", "hypergeometricU(1.20000,2,0.200000)"); assertCalculation("2", "fmod(5, 3)"); assertCalculation("5", "hypot(3, 4)"); assertCalculation("5e-1", "hypot(0.3, 0.4)"); assertCalculation("1.16309", "inverseErf(0.900000)"); assertCalculation("1.0179", "inverseErfc(0.150000)"); assertCalculation("5e-1", "inverseRoot(2.0, 1)"); assertCalculation("5e-1", "inverseRoot(4.0, 2)"); assertCalculation("7.07e-1-7.07e-1i", "inverseRoot(-0.707+0.707i, 3)"); assertCalculation("-5e-1", "inverseRoot(4.0, 2, 1)"); assertCalculation("6.28477", "jacobiP(1.20000,1.70000,0.900000,1.90000)"); assertCalculation("2.685452", "khinchin(7)"); assertCalculation("-1.01693", "laguerreL(1.20000,1.90000)"); assertCalculation("1.38308", "laguerreL(1.20000,1.70000,1.30000)"); assertCalculation("2.26206", "legendreP(1.20000,1.90000)"); assertCalculation("-3.36749", "legendreP(1.20000,1.70000,0.900000)"); assertCalculation("1.07204", "legendreQ(1.70000,-0.900000)"); assertCalculation("4.1358", "legendreQ(1.20000,1.70000,0.900000)"); assertCalculation("-4.371-3.651i", "logGamma(-1.234+2.345i)"); assertCalculation("1.04516", "logIntegral(2.000000)"); assertCalculation("8.80797e-1", "logisticSigmoid(2.00000)"); assertCalculation("1.23", "n(1.23456, 3)"); assertCalculation("1.04748", "pochhammer(1.20000,0.700000)"); assertCalculation("280/81", "pochhammer(1/3,4)"); assertCalculation("-3.2018", "polygamma(2,0.900000)"); assertCalculation("1.79112-2.61823i", "polylog(1.20000,1.30000)"); assertCalculation("2", "root(8, 3)"); assertCalculation("2/3", "root(16/81, 4)"); assertCalculation("7.07e-1+7.07e-1i", "root(-0.707+0.707i, 3)"); assertCalculation("1.2599", "root(2.0000, 3)"); assertCalculation("-4", "root(16.0, 2, 1)"); assertCalculation("3", "round(2.9, 1)"); assertCalculation("3", "round(29/10, 1)"); assertCalculation("3", "round(2.5, 1)"); assertCalculation("4", "round(3.5, 1)"); assertCalculation("-3", "round(-2.5, 1)"); assertCalculation("-4", "round(-3.5, 1)"); assertCalculation("3", "roundToPrecision(2.9, 1)"); assertCalculation("3", "roundToPrecision(29/10, 1)"); assertCalculation("3", "roundToPrecision(2.5, 1)"); assertCalculation("4", "roundToPrecision(3.5, 1)"); assertCalculation("-3", "roundToPrecision(-2.5, 1)"); assertCalculation("-4", "roundToPrecision(-3.5, 1)"); assertCalculation("3", "roundToInteger(2.9)"); assertCalculation("3", "roundToInteger(29/10)"); assertCalculation("3", "roundToInteger(2.5)"); assertCalculation("-3", "roundToInteger(-2.5)"); assertCalculation("-4", "roundToInteger(-3.5)"); assertCalculation("2.9", "roundToPlaces(2.94, 1)"); assertCalculation("3e-1", "roundToPlaces(29/100, 1)"); assertCalculation("30", "roundToPlaces(25, -1)"); assertCalculation("4", "roundToPlaces(3.5, 0)"); assertCalculation("-2.35", "roundToPlaces(-2.345, 2)"); assertCalculation("-3.36", "roundToPlaces(-3.355, 2)"); assertCalculation("2.4", "roundToMultiple(2.9, 1.2)"); assertCalculation("20/7", "roundToMultiple(29/10, 1/7)"); assertCalculation("3", "roundToMultiple(2.5, 1.0)"); assertCalculation("4", "roundToMultiple(3.5, 1.0)"); assertCalculation("-2.5", "roundToMultiple(-2.5, 1.25)"); assertCalculation("-3", "roundToMultiple(-3., 0.3)"); assertCalculation("20000000000", "scale(2, 10)"); assertCalculation("1/5", "scale(2, -1)"); assertCalculation("2.1e10", "scale(2.1, 10)"); assertCalculation("2.5e10+1.5e10i", "scale(2.5+1.5i, 10)"); assertCalculation("200000/3", "scale(2/3, 5)"); assertCalculation("4.54649e-1", "sinc(2.00000)"); assertCalculation("1.60541", "sinIntegral(2.00000)"); assertCalculation("2.50157", "sinhIntegral(2.00000)"); assertCalculation("4.33712e-1-1.30178e-1i", "sphericalHarmonicY(1.20000,1.50000,0.900000,1.90000)"); assertCalculation("3", "sqrt(9)"); assertCalculation("2/3", "sqrt(4/9)"); assertCalculation("7.07+7.07i", "sqrt(100.i)"); assertCalculation("1.4142", "sqrt(2.0000)"); assertCalculation("2", "truncate(2.5)"); assertCalculation("2", "truncate(5/2)"); assertCalculation("1.79e2", "toDegrees(3.14)"); assertCalculation("1.57", "toRadians(90.0)"); assertCalculation("1.644", "zeta(2.000)"); assertCalculation("1.181e-1", "zeta(3.000,-1.500)"); assertCalculation("3.14", "acos(-1.00)"); assertCalculation("1.01", "acosh(1.55)"); assertCalculation("1.57", "asin(1.00)"); assertCalculation("0", "asinh(0)"); assertCalculation("7.85e-1", "atan(1.00)"); assertCalculation("0", "atanh(0)"); assertCalculation("1.57", "atan2(1.00, 0)"); assertCalculation("1", "cos(0)"); assertCalculation("1.54", "cosh(1.00)"); assertCalculation("8.414709848e-1", "sin(1.000000000)"); assertCalculation("1.18", "sinh(1.00)"); assertCalculation("1.56", "tan(1.00)"); assertCalculation("9.64e-1", "tanh(2.00)"); assertCalculation("2.7182818284590452353602874713526624977572470937", "e(47)"); assertCalculation("5.772e-1", "euler(4)"); assertCalculation("2.718", "exp(1.000)"); assertCalculation("1.79+3.14i", "log(-6.00)"); assertCalculation("1.58", "log(3.00, 2.00)"); assertCalculation("1.585", "log(3.000, 2)"); assertCalculation("1.585", "log(3, 2.0000)"); assertCalculation("1.2", "max(1.1, 1.2)"); assertCalculation("1/3", "max(1/3, 1/4)"); assertCalculation("2", "max(1, 2)"); assertCalculation("1.1", "min(1.1, 1.2)"); assertCalculation("1/4", "min(1/3, 1/4)"); assertCalculation("1", "min(1, 2)"); assertCalculation("2", "nextAfter(1., 2)"); assertCalculation("2", "nextUp(1.)"); assertCalculation("1", "nextDown(2.)"); assertCalculation("2/3", "nextDown(2/3)"); assertCalculation("1", "ulp(2.)"); assertCalculation("0", "ulp(2/3)"); assertCalculation("0", "ulp(1+i)"); assertCalculation("1e-1", "ulp(-10.00-2.0i)"); assertCalculation("1.57", "arg(1.00i)"); assertCalculation("2-i", "conj(2+i)"); assertCalculation("1", "imag(2+i)"); assertCalculation("2", "real(2+i)"); assertCalculation("2.47468", "agm(2.000000, 3.000000)"); assertCalculation("5.672e-1", "w(1.000)"); assertCalculation("-3.181e-1+1.3372i", "w(-1.0000)"); assertCalculation("-1.34285+5.24725i", "w(1.00000+i, 1)"); assertCalculation("3", "gcd(15, 12)"); assertCalculation("60", "lcm(15, 12)"); assertCalculation("3.14159", "pi(6)"); assertCalculationMatch("0|[1-9]e-1", "random(1)"); assertCalculationMatch("0|-?([1-5]|[1-9]e-1)", "randomGaussian(1)"); assertCalculation("5", "add(2, 3)"); assertCalculation("-1", "subtract(2, 3)"); assertCalculation("6", "multiply(2, 3)"); assertCalculation("2/3", "divide(2, 3)"); assertCalculation("-2", "negate(2)"); assertCalculation("2", "mod(5, 3)"); assertCalculation("8", "pow(2, 3)"); assertCalculationFailure("airyAi()"); assertCalculationFailure("airyAi(0,0)"); assertCalculationFailure("airyAiPrime()"); assertCalculationFailure("airyAiPrime(0,0)"); assertCalculationFailure("airyBi()"); assertCalculationFailure("airyBi(0,0)"); assertCalculationFailure("airyBiPrime()"); assertCalculationFailure("airyBiPrime(0,0)"); assertCalculationFailure("bernoulli(-1)"); assertCalculationFailure("bernoulli(i)"); assertCalculationFailure("bernoulli()"); assertCalculationFailure("bernoulli(1,1)"); assertCalculationFailure("bernoulliB(1)"); assertCalculationFailure("bernoulliB(1,1.0,1.0)"); assertCalculationFailure("bernoulliB(-1,1.0)"); assertCalculationFailure("bernoulliB(i,1.0)"); assertCalculationFailure("bernoulliB(2/3,1.0)"); assertCalculationFailure("besselI(1.0)"); assertCalculationFailure("besselI(1.0,1.0,1.0)"); assertCalculationFailure("besselJ(1.0)"); assertCalculationFailure("besselJ(1.0,1.0,1.0)"); assertCalculationFailure("besselK(1.0)"); assertCalculationFailure("besselK(1.0,1.0,1.0)"); assertCalculationFailure("besselY(1.0)"); assertCalculationFailure("besselY(1.0,1.0,1.0)"); assertCalculationFailure("beta(1.0)"); assertCalculationFailure("beta(1.0,1.0,1.0,1.0,1.0)"); assertCalculationFailure("binomial(-3,5i)"); assertCalculationFailure("binomial(-3i,5)"); assertCalculationFailure("binomial(-3i,5i)"); assertCalculationFailure("binomial(-3,3.5)"); assertCalculationFailure("binomial(4/3,3/2)"); assertCalculationFailure("binomial()"); assertCalculationFailure("binomial(2)"); assertCalculationFailure("binomial(2,2,2)"); assertCalculationFailure("catalan()"); assertCalculationFailure("catalan(5, 5)"); assertCalculationFailure("catalan(0)"); assertCalculationFailure("catalan(-1)"); assertCalculationFailure("catalan(0.5)"); assertCalculationFailure("catalan(i)"); assertCalculationFailure("cbrt(2)"); assertCalculationFailure("cbrt()"); assertCalculationFailure("cbrt(8, 2)"); assertCalculationFailure("ceil(i)"); assertCalculationFailure("ceil()"); assertCalculationFailure("ceil(2, 2)"); assertCalculationFailure("chebyshevT(1.0)"); assertCalculationFailure("chebyshevT(1.0,1.0,1.0)"); assertCalculationFailure("chebyshevU(1.0)"); assertCalculationFailure("chebyshevU(1.0,1.0,1.0)"); assertCalculationFailure("copySign(2i, -3)"); assertCalculationFailure("copySign(2)"); assertCalculationFailure("copySign(2, 2, 2)"); assertCalculationFailure("cosIntegral()"); assertCalculationFailure("cosIntegral(1.0,1.0)"); assertCalculationFailure("coshIntegral()"); assertCalculationFailure("coshIntegral(1.0,1.0)"); assertCalculationFailure("digamma(0)"); assertCalculationFailure("digamma()"); assertCalculationFailure("digamma(2,2)"); assertCalculationFailure("doubleFactorial(0.5)"); assertCalculationFailure("doubleFactorial(2i)"); assertCalculationFailure("doubleFactorial(2/3)"); assertCalculationFailure("doubleFactorial()"); assertCalculationFailure("doubleFactorial(2, 2)"); assertCalculationFailure("ellipticE()"); assertCalculationFailure("ellipticE(0.5,0.5)"); assertCalculationFailure("ellipticK()"); assertCalculationFailure("ellipticK(0.5,0.5)"); assertCalculationFailure("erf()"); assertCalculationFailure("erf(0.5,0.5)"); assertCalculationFailure("erfc()"); assertCalculationFailure("erfc(0.5,0.5)"); assertCalculationFailure("erfi()"); assertCalculationFailure("erfi(0.5,0.5)"); assertCalculationFailure("eulerE(1)"); assertCalculationFailure("eulerE(1,1.0,1.0"); assertCalculationFailure("eulerE(-1,1.0)"); assertCalculationFailure("eulerE(i,1.0)"); assertCalculationFailure("eulerE(2/3,1.0)"); assertCalculationFailure("expIntegralE(0.5)"); assertCalculationFailure("expIntegralE(0.5,0.5,0.5)"); assertCalculationFailure("expIntegralEi()"); assertCalculationFailure("expIntegralEi(0.5,0.5)"); assertCalculationFailure("factorial(0.5)"); assertCalculationFailure("factorial(2i)"); assertCalculationFailure("factorial(2/3)"); assertCalculationFailure("factorial()"); assertCalculationFailure("factorial(2, 2)"); assertCalculationFailure("fibonacci(1.0)"); assertCalculationFailure("fibonacci(1.0,1.0,1.0)"); assertCalculationFailure("floor(i)"); assertCalculationFailure("floor()"); assertCalculationFailure("floor(2, 2)"); assertCalculationFailure("frac(i)"); assertCalculationFailure("frac()"); assertCalculationFailure("frac(2, 2)"); assertCalculationFailure("fresnelC()"); assertCalculationFailure("fresnelC(1.0,1.0)"); assertCalculationFailure("fresnelS()"); assertCalculationFailure("fresnelS(1.0,1.0)"); assertCalculationFailure("gamma(0)"); assertCalculationFailure("gamma()"); assertCalculationFailure("gamma(2, 2, 2, 2)"); assertCalculationFailure("gegenbauerC(1.0)"); assertCalculationFailure("gegenbauerC(1.0,1.0,1.0,1.0)"); assertCalculationFailure("glaisher()"); assertCalculationFailure("glaisher(5, 5)"); assertCalculationFailure("glaisher(0)"); assertCalculationFailure("glaisher(-1)"); assertCalculationFailure("glaisher(0.5)"); assertCalculationFailure("glaisher(i)"); assertCalculationFailure("harmonicNumber()"); assertCalculationFailure("harmonicNumber(-1)"); assertCalculationFailure("harmonicNumber(-1,1)"); assertCalculationFailure("harmonicNumber(1.0,1.0,1.0)"); assertCalculationFailure("hermiteH(1.0)"); assertCalculationFailure("hermiteH(1.0,1.0,1.0)"); assertCalculationFailure("hypergeometric0F1(0)"); assertCalculationFailure("hypergeometric0F1(0,0)"); assertCalculationFailure("hypergeometric0F1(0,0,0)"); assertCalculationFailure("hypergeometric0F1Regularized(0)"); assertCalculationFailure("hypergeometric0F1Regularized(0,0,0)"); assertCalculationFailure("hypergeometric1F1(0,0)"); assertCalculationFailure("hypergeometric1F1(1,0,0)"); assertCalculationFailure("hypergeometric1F1(0,0,0,0)"); assertCalculationFailure("hypergeometric1F1Regularized(0,0)"); assertCalculationFailure("hypergeometric1F1Regularized(0,0,0,0)"); assertCalculationFailure("hypergeometric2F1(0,0,0)"); assertCalculationFailure("hypergeometric2F1(1,2,0,0)"); assertCalculationFailure("hypergeometric2F1(0,0,0,0,0)"); assertCalculationFailure("hypergeometric2F1Regularized(0,0,0)"); assertCalculationFailure("hypergeometric2F1Regularized(0,0,0,0,0)"); assertCalculationFailure("hypergeometricU(0,0)"); assertCalculationFailure("hypergeometricU(0,0,0,0)"); assertCalculationFailure("fmod(2, i)"); assertCalculationFailure("fmod(2)"); assertCalculationFailure("fmod(2, 2, 2)"); assertCalculationFailure("hypot(2, i)"); assertCalculationFailure("hypot(2)"); assertCalculationFailure("hypot(2, 2, 2)"); assertCalculationFailure("inverseErf()"); assertCalculationFailure("inverseErf(-1.0)"); assertCalculationFailure("inverseErf(1.0)"); assertCalculationFailure("inverseErf(2.0)"); assertCalculationFailure("inverseErf(0.5i)"); assertCalculationFailure("inverseErf(0.5,0.5)"); assertCalculationFailure("inverseErfc()"); assertCalculationFailure("inverseErfc(0)"); assertCalculationFailure("inverseErfc(2.0)"); assertCalculationFailure("inverseErfc(3.0)"); assertCalculationFailure("inverseErfc(0.5i)"); assertCalculationFailure("inverseErfc(0.5,0.5)"); assertCalculationFailure("inverseRoot(2.0, i)"); assertCalculationFailure("inverseRoot(2.0, 1/2)"); assertCalculationFailure("inverseRoot(2, 2)"); assertCalculationFailure("inverseRoot(2)"); assertCalculationFailure("inverseRoot(2.0, 1, i)"); assertCalculationFailure("inverseRoot(2.0, i, 1)"); assertCalculationFailure("inverseRoot(2.0, i, i)"); assertCalculationFailure("inverseRoot(2.0, 2, 2, 2)"); assertCalculationFailure("jacobiP(1.0,1.0,1.0)"); assertCalculationFailure("jacobiP(1.0,1.0,1.0,1.0,1.0)"); assertCalculationFailure("khinchin()"); assertCalculationFailure("khinchin(5, 5)"); assertCalculationFailure("khinchin(0)"); assertCalculationFailure("khinchin(-1)"); assertCalculationFailure("khinchin(0.5)"); assertCalculationFailure("khinchin(i)"); assertCalculationFailure("laguerreL(1.0)"); assertCalculationFailure("laguerreL(1.0,1.0,1.0,1.0)"); assertCalculationFailure("legendreP(1.0)"); assertCalculationFailure("legendreP(1.0,1.0,1.0,1.0)"); assertCalculationFailure("legendreQ(1.0)"); assertCalculationFailure("legendreQ(1.0,1.0,1.0,1.0)"); assertCalculationFailure("logGamma(0)"); assertCalculationFailure("logGamma(-1)"); assertCalculationFailure("logGamma()"); assertCalculationFailure("logGamma(2,2)"); assertCalculationFailure("logIntegral()"); assertCalculationFailure("logIntegral(1.0,1.0)"); assertCalculationFailure("logisticSigmoid()"); assertCalculationFailure("logisticSigmoid(2.0,2.0)"); assertCalculationFailure("n(1.23456, i)"); assertCalculationFailure("n(1.23456, 0.5)"); assertCalculationFailure("n(1.23456)"); assertCalculationFailure("n(1.23456, 2, 2)"); assertCalculationFailure("pochhammer(1.0)"); assertCalculationFailure("pochhammer(1.0,1.0,1.0)"); assertCalculationFailure("pochhammer(1/3,1/4)"); assertCalculationFailure("polygamma(1)"); assertCalculationFailure("polygamma(-1,1.0)"); assertCalculationFailure("polygamma(1,1.0,1.0)"); assertCalculationFailure("polylog(0.5)"); assertCalculationFailure("polylog(0.5,0.5,0.5)"); assertCalculationFailure("root(2, 2)"); assertCalculationFailure("root(2)"); assertCalculationFailure("root(2, i)"); assertCalculationFailure("root(2, 1, i)"); assertCalculationFailure("root(2, i, 1)"); assertCalculationFailure("root(2, i, i)"); assertCalculationFailure("root(4.0, 2, 2, 2)"); assertCalculationFailure("round(2)"); assertCalculationFailure("round(2, 0)"); assertCalculationFailure("round(2, 0.5)"); assertCalculationFailure("round(2, i)"); assertCalculationFailure("round(i, 2)"); assertCalculationFailure("round(2, 2, 2)"); assertCalculationFailure("roundToPrecision(2)"); assertCalculationFailure("roundToPrecision(2, 0)"); assertCalculationFailure("roundToPrecision(2, 0.5)"); assertCalculationFailure("roundToPrecision(2, i)"); assertCalculationFailure("roundToPrecision(i, 2)"); assertCalculationFailure("roundToPrecision(2, 2, 2)"); assertCalculationFailure("roundToInteger()"); assertCalculationFailure("roundToInteger(i)"); assertCalculationFailure("roundToInteger(2, 0)"); assertCalculationFailure("roundToPlaces(2)"); assertCalculationFailure("roundToPlaces(2, 0.5)"); assertCalculationFailure("roundToPlaces(2, i)"); assertCalculationFailure("roundToPlaces(i, 2)"); assertCalculationFailure("roundToPlaces(2, 2, 2)"); assertCalculationFailure("roundToMultiple(2)"); assertCalculationFailure("roundToMultiple(2, 0)"); assertCalculationFailure("roundToMultiple(2, i)"); assertCalculationFailure("roundToMultiple(i, 2)"); assertCalculationFailure("roundToMultiple(2, 2, 2)"); assertCalculationFailure("scale(1.23456, i)"); assertCalculationFailure("scale(1.23456, 0.5)"); assertCalculationFailure("scale(1.23456)"); assertCalculationFailure("scale(1.23456, 2, 2)"); assertCalculationFailure("sinc()"); assertCalculationFailure("sinc(1.0,1.0)"); assertCalculationFailure("sinIntegral()"); assertCalculationFailure("sinIntegral(1.0,1.0)"); assertCalculationFailure("sinhIntegral()"); assertCalculationFailure("sinhIntegral(1.0,1.0)"); assertCalculationFailure("sphericalHarmonicY(1.0,1.0,1.0)"); assertCalculationFailure("sphericalHarmonicY(1.0,1.0,1.0,1.0,1.0)"); assertCalculationFailure("sqrt(2)"); assertCalculationFailure("sqrt()"); assertCalculationFailure("sqrt(4, 2)"); assertCalculationFailure("truncate(i)"); assertCalculationFailure("truncate()"); assertCalculationFailure("truncate(2, 2)"); assertCalculationFailure("toDegrees(2)"); assertCalculationFailure("toDegrees(i)"); assertCalculationFailure("toDegrees()"); assertCalculationFailure("toDegrees(2, 2)"); assertCalculationFailure("toRadians(2)"); assertCalculationFailure("toRadians(i)"); assertCalculationFailure("toRadians()"); assertCalculationFailure("toRadians(2, 2)"); assertCalculationFailure("zeta(1)"); assertCalculationFailure("zeta(2,0)"); assertCalculationFailure("zeta(2,-1)"); assertCalculationFailure("zeta()"); assertCalculationFailure("zeta(2,3,4)"); assertCalculationFailure("acos()"); assertCalculationFailure("acos(1, 1)"); assertCalculationFailure("acosh()"); assertCalculationFailure("acosh(1, 1)"); assertCalculationFailure("asin()"); assertCalculationFailure("asin(1, 1)"); assertCalculationFailure("asinh()"); assertCalculationFailure("asinh(1, 1)"); assertCalculationFailure("atan()"); assertCalculationFailure("atan(1, 1)"); assertCalculationFailure("atanh()"); assertCalculationFailure("atanh(1, 1)"); assertCalculationFailure("atan2(1)"); assertCalculationFailure("atan2(i, i)"); assertCalculationFailure("atan2(1, 1, 1)"); assertCalculationFailure("cos()"); assertCalculationFailure("cos(1, 1)"); assertCalculationFailure("cosh()"); assertCalculationFailure("cosh(1, 1)"); assertCalculationFailure("sin()"); assertCalculationFailure("sin(1, 1)"); assertCalculationFailure("sinh()"); assertCalculationFailure("sinh(1, 1)"); assertCalculationFailure("tan()"); assertCalculationFailure("tan(1, 1)"); assertCalculationFailure("tanh()"); assertCalculationFailure("tanh(1, 1)"); assertCalculationFailure("e()"); assertCalculationFailure("e(0)"); assertCalculationFailure("e(-1)"); assertCalculationFailure("e(0.5)"); assertCalculationFailure("e(i)"); assertCalculationFailure("e(1, 1)"); assertCalculationFailure("euler()"); assertCalculationFailure("euler(0)"); assertCalculationFailure("euler(-1)"); assertCalculationFailure("euler(0.5)"); assertCalculationFailure("euler(i)"); assertCalculationFailure("euler(1, 1)"); assertCalculationFailure("exp()"); assertCalculationFailure("exp(1, 1)"); assertCalculationFailure("log()"); assertCalculationFailure("log(1, 1, 1)"); assertCalculationFailure("max()"); assertCalculationFailure("max(1)"); assertCalculationFailure("max(1, 1, 1)"); assertCalculationFailure("max(i, i)"); assertCalculationFailure("min()"); assertCalculationFailure("min(1)"); assertCalculationFailure("min(1, 1, 1)"); assertCalculationFailure("min(i, i)"); assertCalculationFailure("nextAfter(1)"); assertCalculationFailure("nextAfter(1, 2, 3)"); assertCalculationFailure("nextAfter(1, i)"); assertCalculationFailure("nextUp()"); assertCalculationFailure("nextUp(1, 1)"); assertCalculationFailure("nextUp(i)"); assertCalculationFailure("nextDown()"); assertCalculationFailure("nextDown(2, 2)"); assertCalculationFailure("nextDown(i)"); assertCalculationFailure("ulp()"); assertCalculationFailure("ulp(2, 2)"); assertCalculationFailure("arg()"); assertCalculationFailure("arg(1, 1)"); assertCalculationFailure("conj()"); assertCalculationFailure("conj(1, 1)"); assertCalculationFailure("imag()"); assertCalculationFailure("imag(1, 1)"); assertCalculationFailure("real()"); assertCalculationFailure("real(1, 1)"); assertCalculationFailure("agm(1)"); assertCalculationFailure("agm(1, 1, 1)"); assertCalculationFailure("w(1, 1, 1)"); assertCalculationFailure("w(1, i)"); assertCalculationFailure("w(1, 1.5)"); assertCalculationFailure("w(1, 2/3)"); assertCalculationFailure("gcd(2, i)"); assertCalculationFailure("gcd(2, 2/3)"); assertCalculationFailure("gcd(1)"); assertCalculationFailure("gcd(1, 1, 1)"); assertCalculationFailure("lcm(2, i)"); assertCalculationFailure("lcm(2, 2/3)"); assertCalculationFailure("lcm(1)"); assertCalculationFailure("lcm(1, 1, 1)"); assertCalculationFailure("pi(i)"); assertCalculationFailure("pi(0.5)"); assertCalculationFailure("pi()"); assertCalculationFailure("pi(1, 1)"); assertCalculationFailure("random(i)"); assertCalculationFailure("random(0.5)"); assertCalculationFailure("random()"); assertCalculationFailure("random(1, 1)"); assertCalculationFailure("randomGaussian(i)"); assertCalculationFailure("randomGaussian(0.5)"); assertCalculationFailure("randomGaussian()"); assertCalculationFailure("randomGaussian(1, 1)"); assertCalculationFailure("add(2)"); assertCalculationFailure("add(2, 2, 2)"); assertCalculationFailure("subtract(2)"); assertCalculationFailure("subtract(2, 2, 2)"); assertCalculationFailure("multiply(2)"); assertCalculationFailure("multiply(2, 2, 2)"); assertCalculationFailure("divide(2)"); assertCalculationFailure("divide(2, 2, 2)"); assertCalculationFailure("negate()"); assertCalculationFailure("negate(2, 2)"); assertCalculationFailure("mod(2, i)"); assertCalculationFailure("mod(2)"); assertCalculationFailure("mod(2, 2, 2)"); assertCalculationFailure("pow(2)"); assertCalculationFailure("pow(2, 2, 2)"); assertCalculationFailure("bogusfunc(5)"); } public static void testArguments() throws ParseException { assertCalculation("1.4142", "sqrt(2.)", "-i", "5"); assertCalculation("0.5", "1/2", "-p", "-i", "1"); assertCalculation("0.5", "1.0/2.0", "-p"); assertCalculation("0.915966", "catalan()", "-p", "-i", "6"); assertCalculation("2.71828", "e()", "-i", "6"); assertCalculation("0.577216", "euler()", "-p", "-i", "6"); assertCalculation("1.28243", "glaisher()", "-i", "6"); assertCalculation("2.68545", "khinchin()", "-p", "-i", "6"); assertCalculation("3.14159", "pi()", "-i", "6"); assertCalculationMatch("0|[1-9]e-1", "random()", "-i", "1"); assertCalculationMatch("0|-?([1-5]|[1-9]e-1)", "randomGaussian()", "-i", "1"); assertCalculation("1.5708", "acos(0)", "-p", "-i", "6"); assertCalculation("1.5708i", "acosh(0)", "-p", "-i", "6"); assertCalculation("0.355028", "airyAi(0)", "-p", "-i", "6"); assertCalculation("-0.258819", "airyAiPrime(0)", "-p", "-i", "6"); assertCalculation("0.614927", "airyBi(0)", "-p", "-i", "6"); assertCalculation("0.448288", "airyBiPrime(0)", "-p", "-i", "6"); assertCalculation("-7.09216", "bernoulliB(16, 0)", "-i", "6"); assertCalculation("1.5708", "ellipticE(0)", "-p", "-i", "6"); assertCalculation("1.5708", "ellipticK(0)", "-p", "-i", "6"); assertCalculation("58098.1", "eulerE(15, 0)", "-p", "-i", "6"); } private static final String NEWLINE = System.lineSeparator(); } apfloat-1.14.0/apfloat-jscience/000077500000000000000000000000001461767713300164515ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/pom.xml000066400000000000000000000050411461767713300177660ustar00rootroot00000000000000 4.0.0 org.apfloat apfloat-parent 1.14.0 apfloat-jscience apfloat-jscience JScience wrapper for apfloat http://www.apfloat.org org.apfloat apfloat org.jscience jscience junit junit test org.apfloat apfloat test-jar test biz.aQute.bnd bnd-maven-plugin generate-osgi-manifest bnd-process org.apache.maven.plugins maven-jar-plugin ${project.build.outputDirectory}/META-INF/MANIFEST.MF org.apache.maven.plugins maven-shade-plugin shade org.apfloat:apfloat-jscience ${project.build.directory}/apfloat-jscience.jar apfloat-1.14.0/apfloat-jscience/src/000077500000000000000000000000001461767713300172405ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/main/000077500000000000000000000000001461767713300201645ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/main/java/000077500000000000000000000000001461767713300211055ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/main/java/org/000077500000000000000000000000001461767713300216745ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/000077500000000000000000000000001461767713300233225ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/jscience/000077500000000000000000000000001461767713300251055ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/jscience/AbstractField.java000066400000000000000000000127631461767713300304700ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import javolution.text.Text; import org.apfloat.Apcomplex; import org.apfloat.ApcomplexMath; import org.jscience.mathematics.number.Number; import org.jscience.mathematics.structure.Field; /** * This class represents an arbitrary precision field object. * * @param The type of the field. * @param The type of the underlying value. * * @since 1.8.0 * @version 1.8.0 * @author Mikko Tommila */ public abstract class AbstractField, V extends Apcomplex> extends Number implements Field { /** * Constructs a new field object with the specified value. * * @param value The value. */ protected AbstractField(V value) { if (value == null) { throw new NullPointerException("Value can't be null"); } this.value = value; } /** * Returns the sum of this object with the one specified. * * @param that The addend. * * @return this + that */ @Override public abstract T plus(T that); /** * Returns the additive inverse of this object. * * @return -this */ @Override public abstract T opposite(); /** * Returns the product of this object with the one specified. * * @param that The multiplicand. * * @return this * that */ @Override public abstract T times(T that); /** * Returns the multiplicative inverse of this object. * * @return 1 / this * * @exception ArithmeticException If the divisor is zero. */ @Override public abstract T inverse() throws ArithmeticException; /** * Returns a copy of this object. * * @return A copy of this object. */ @Override public abstract T copy(); /** * Compares the absolute value of this number * with the absolute value of the number specified. * * @param that The number to be compared with. * * @return |this| > |that| */ @Override public boolean isLargerThan(T that) { return ApcomplexMath.abs(value()).compareTo(ApcomplexMath.abs(that.value())) > 0; } /** * Returns the value of this number as the underlying type. * * @return The value. */ public V value() { return this.value; } /** * Returns the value of this number as a double. * * @return The value. */ @Override public double doubleValue() { return value().doubleValue(); } /** * Returns the value of this number as a long. * * @return The value. */ @Override public long longValue() { return value().longValue(); } /** * Returns the text representation of this number. * * @return The string representation of this number as a Text. */ @Override public Text toText() { return Text.valueOf(value().toString()); } /** * Compares this number to another number. * * @param that The number to be compared with. * * @return -1, 0, or 1 depending on the ordering. */ @Override public int compareTo(T that) { int result = value().real().compareTo(that.value().real()); if (result == 0) { result = value().imag().compareTo(that.value().imag()); } return result; } /** * Returns the hash code for this number. * * @return The hash code value. */ @Override public int hashCode() { return value().hashCode(); } /** * Compares for equality. * * @return If the objects are equal. */ @Override public boolean equals(Object obj) { if (obj instanceof AbstractField) { AbstractField that = (AbstractField) obj; return value().equals(that.value()); } return false; } private static final long serialVersionUID = -7725271295007354895L; private V value; } apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/jscience/ApcomplexField.java000066400000000000000000000054171461767713300306530ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import org.apfloat.Apcomplex; import org.apfloat.ApcomplexMath; /** * This class represents an arbitrary precision complex number.

* * The precision of each calculation is determined separately, which means * that loss of precision can easily accumulate in complicated calculations * (e.g. matrix inversion). If this should be avoided, and a fixed precision is * required, then it may be better to use {@link FixedPrecisionApcomplexField} * instead. * * @since 1.8.0 * @version 1.8.0 * @author Mikko Tommila */ public class ApcomplexField extends AbstractField { /** * Constructs a new complex field object with the specified value. * * @param value The value. */ public ApcomplexField(Apcomplex value) { super(value); } @Override public ApcomplexField plus(ApcomplexField that) { return new ApcomplexField(value().add(that.value())); } @Override public ApcomplexField opposite() { return new ApcomplexField(value().negate()); } @Override public ApcomplexField times(ApcomplexField that) { return new ApcomplexField(value().multiply(that.value())); } @Override public ApcomplexField inverse() throws ArithmeticException { return new ApcomplexField(ApcomplexMath.inverseRoot(value(), 1)); } @Override public ApcomplexField copy() { return new ApcomplexField(value()); } private static final long serialVersionUID = -6242843580910131563L; } apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/jscience/ApfloatField.java000066400000000000000000000053621461767713300303100ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import org.apfloat.Apfloat; import org.apfloat.ApfloatMath; /** * This class represents an arbitrary precision floating-point number.

* * The precision of each calculation is determined separately, which means * that loss of precision can easily accumulate in complicated calculations * (e.g. matrix inversion). If this should be avoided, and a fixed precision is * required, then it may be better to use {@link FixedPrecisionApfloatField} * instead. * * @since 1.8.0 * @version 1.8.0 * @author Mikko Tommila */ public class ApfloatField extends AbstractField { /** * Constructs a new floating-point field object with the specified value. * * @param value The value. */ public ApfloatField(Apfloat value) { super(value); } @Override public ApfloatField plus(ApfloatField that) { return new ApfloatField(value().add(that.value())); } @Override public ApfloatField opposite() { return new ApfloatField(value().negate()); } @Override public ApfloatField times(ApfloatField that) { return new ApfloatField(value().multiply(that.value())); } @Override public ApfloatField inverse() throws ArithmeticException { return new ApfloatField(ApfloatMath.inverseRoot(value(), 1)); } @Override public ApfloatField copy() { return new ApfloatField(value()); } private static final long serialVersionUID = -901594332306254700L; } apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/jscience/AprationalField.java000066400000000000000000000051001461767713300310020ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import org.apfloat.Aprational; /** * This class represents an arbitrary precision rational number. * * @since 1.8.0 * @version 1.8.0 * @author Mikko Tommila */ public class AprationalField extends AbstractField { /** * Constructs a new rational field object with the specified value. * * @param value The value. */ public AprationalField(Aprational value) { super(value); } @Override public AprationalField plus(AprationalField that) { return new AprationalField(value().add(that.value())); } @Override public AprationalField opposite() { return new AprationalField(value().negate()); } @Override public AprationalField times(AprationalField that) { return new AprationalField(value().multiply(that.value())); } @Override public AprationalField inverse() throws ArithmeticException { if (value().signum() == 0) { throw new ArithmeticException("Inverse of zero"); } return new AprationalField(new Aprational(value().denominator(), value().numerator())); } @Override public AprationalField copy() { return new AprationalField(value()); } private static final long serialVersionUID = -4642791345140583865L; } apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/jscience/FixedPrecisionApcomplexField.java000066400000000000000000000067301461767713300335060ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import org.apfloat.Apcomplex; import org.apfloat.FixedPrecisionApcomplexHelper; /** * This class represents a fixed-precision complex number. The precision * is reset after each computation using the provided FixedPrecisionApcomplexHelper. * This can help avoid accumulating round-off errors and loss of precision * in complicated computations such as matrix inversion. * * @since 1.8.0 * @version 1.8.0 * @author Mikko Tommila */ public class FixedPrecisionApcomplexField extends AbstractField { /** * Constructs a new complex field object with the specified value and precision helper. * * @param value The value. * @param helper The precision helper. */ public FixedPrecisionApcomplexField(Apcomplex value, FixedPrecisionApcomplexHelper helper) { super(value); if (helper == null) { throw new NullPointerException("Helper can't be null"); } this.helper = helper; } @Override public FixedPrecisionApcomplexField plus(FixedPrecisionApcomplexField that) { return new FixedPrecisionApcomplexField(helper().add(value(), that.value()), helper()); } @Override public FixedPrecisionApcomplexField opposite() { return new FixedPrecisionApcomplexField(helper().negate(value()), helper()); } @Override public FixedPrecisionApcomplexField times(FixedPrecisionApcomplexField that) { return new FixedPrecisionApcomplexField(helper().multiply(value(), that.value()), helper()); } @Override public FixedPrecisionApcomplexField inverse() throws ArithmeticException { return new FixedPrecisionApcomplexField(helper().inverseRoot(value(), 1), helper()); } @Override public FixedPrecisionApcomplexField copy() { return new FixedPrecisionApcomplexField(value(), helper()); } /** * Return the precision helper. * * @return The precision helper. */ public FixedPrecisionApcomplexHelper helper() { return this.helper; } private static final long serialVersionUID = -2069599698604093434L; private FixedPrecisionApcomplexHelper helper; } apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/jscience/FixedPrecisionApfloatField.java000066400000000000000000000066431461767713300331470ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import org.apfloat.Apfloat; import org.apfloat.FixedPrecisionApfloatHelper; /** * This class represents a fixed-precision floating-point number. The precision * is reset after each computation using the provided FixedPrecisionApfloatHelper. * This can help avoid accumulating round-off errors and loss of precision * in complicated computations such as matrix inversion. * * @since 1.8.0 * @version 1.8.0 * @author Mikko Tommila */ public class FixedPrecisionApfloatField extends AbstractField { /** * Constructs a new floating-point field object with the specified value. * * @param value The value. * @param helper The precision helper. */ public FixedPrecisionApfloatField(Apfloat value, FixedPrecisionApfloatHelper helper) { super(value); if (helper == null) { throw new NullPointerException("Helper can't be null"); } this.helper = helper; } @Override public FixedPrecisionApfloatField plus(FixedPrecisionApfloatField that) { return new FixedPrecisionApfloatField(helper().add(value(), that.value()), helper()); } @Override public FixedPrecisionApfloatField opposite() { return new FixedPrecisionApfloatField(helper().negate(value()), helper()); } @Override public FixedPrecisionApfloatField times(FixedPrecisionApfloatField that) { return new FixedPrecisionApfloatField(helper().multiply(value(), that.value()), helper()); } @Override public FixedPrecisionApfloatField inverse() throws ArithmeticException { return new FixedPrecisionApfloatField(helper().inverseRoot(value(), 1), helper()); } @Override public FixedPrecisionApfloatField copy() { return new FixedPrecisionApfloatField(value(), helper()); } /** * Return the precision helper. * * @return The precision helper. */ public FixedPrecisionApfloatHelper helper() { return this.helper; } private static final long serialVersionUID = -8969242537753892317L; private FixedPrecisionApfloatHelper helper; } apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/jscience/ModuloApintField.java000066400000000000000000000107051461767713300311520ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import javolution.context.LocalContext; import org.apfloat.Apint; import org.apfloat.ApintMath; /** * This class represents an arbitrary precision modulo integer. * The modulus must be set with {@link #setModulus(Apint)}; otherwise * the modulo reduction is not done. * * @since 1.8.0 * @version 1.8.0 * @author Mikko Tommila */ public class ModuloApintField extends AbstractField { /** * Constructs a new integer field object with the specified value. * * @param value The value. */ public ModuloApintField(Apint value) { super(reduce(value)); } /** * Returns the modulus or null if modulo reduction is not done. * The modulus can be set in a thread-specific way using * {@link javolution.context.LocalContext}. * * @return The local modulus or null if modulo reduction is not done. * * @see #setModulus */ public static Apint getModulus() { return MODULUS.get(); } /** * Sets the modulus. * The modulus can be set in a thread-specific way using * {@link javolution.context.LocalContext}. * * @param modulus The modulus or null if modulo reduction is not done. * * @throws IllegalArgumentException If modulus is not positive. */ public static void setModulus(Apint modulus) { if (modulus != null && modulus.signum() <= 0) { throw new IllegalArgumentException("Modulus has to be greater than zero"); } MODULUS.set(modulus); } /** * Reduce the value with the current modulus. * * @param value The value. * * @return The value mod the current modulus. */ public static Apint reduce(Apint value) { Apint modulus = MODULUS.get(); if (modulus != null) { value = value.mod(modulus); if (value.signum() < 0) // The modulus is always positive, so reduce values to positive { value = value.add(modulus); } } return value; } @Override public ModuloApintField plus(ModuloApintField that) { return new ModuloApintField(value().add(that.value())); } @Override public ModuloApintField opposite() { return new ModuloApintField(value().negate()); } @Override public ModuloApintField times(ModuloApintField that) { return new ModuloApintField(value().multiply(that.value())); } @Override public ModuloApintField inverse() throws ArithmeticException { Apint modulus = MODULUS.get(); if (modulus == null) { throw new ArithmeticException("Modulus is not set"); } return new ModuloApintField(ApintMath.modPow(value(), new Apint(-1), modulus)); } @Override public ModuloApintField copy() { return new ModuloApintField(value()); } private static final long serialVersionUID = 5308452222350777004L; private static final LocalContext.Reference MODULUS = new LocalContext.Reference(); } apfloat-1.14.0/apfloat-jscience/src/main/java/org/apfloat/jscience/package-info.java000066400000000000000000000026401461767713300302760ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** JScience wrapper for apfloat.

This package contains classes that allow using the apfloat library classes with the JScience library. For example, it's possible to perform arbitrary-precision matrix or polynomial operations. */ package org.apfloat.jscience; apfloat-1.14.0/apfloat-jscience/src/test/000077500000000000000000000000001461767713300202175ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/test/java/000077500000000000000000000000001461767713300211405ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/test/java/org/000077500000000000000000000000001461767713300217275ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/test/java/org/apfloat/000077500000000000000000000000001461767713300233555ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/test/java/org/apfloat/jscience/000077500000000000000000000000001461767713300251405ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/test/java/org/apfloat/jscience/ApcomplexFieldTest.java000066400000000000000000000125401461767713300315410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import java.util.HashSet; import org.apfloat.*; import org.jscience.mathematics.function.*; import org.jscience.mathematics.vector.*; import javolution.text.*; import junit.framework.TestSuite; /** * @since 1.8.0 * @version 1.9.0 * @author Mikko Tommila */ public class ApcomplexFieldTest extends ApfloatTestCase { public ApcomplexFieldTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApcomplexFieldTest("testBasic")); suite.addTest(new ApcomplexFieldTest("testMatrixInverse")); suite.addTest(new ApcomplexFieldTest("testRationalFunction")); return suite; } public static void testBasic() { ApcomplexField a = valueOf("(0,100)"); ApcomplexField b = valueOf("(0,200)"); ApcomplexField c = valueOf("(0,200)"); ApcomplexField zero = valueOf("0"); assertEquals("100 + 200", valueOf("(0,300)"), a.plus(b)); assertEquals("-100", valueOf("(0,-100)"), a.opposite()); assertEquals("100 - 200", valueOf("(0,-100)"), a.minus(b)); assertEquals("100 * 200", valueOf("-20000"), a.times(b)); assertEquals("1 / 100", valueOf("(0,-0.01)"), a.inverse()); assertEquals("copy", a, a.copy()); assertEquals("doubleValue", 0.0, a.doubleValue()); assertEquals("longValue", 0L, a.longValue()); assertEquals("String", "(0, 1e2)", a.toString()); assertEquals("Text", new Text("(0, 1e2)"), a.toText()); assertTrue("isLargerThan", b.isLargerThan(a)); assertEquals("compareTo", -1, a.compareTo(b)); HashSet set = new HashSet<>(); set.add(b); set.add(c); assertEquals("hashCode", 1, set.size()); try { zero.inverse(); fail("Zero divisor accepted"); } catch (ArithmeticException ae) { // OK, modulus is not set } try { new ApcomplexField(null); fail("null accepted"); } catch (NullPointerException npe) { // OK, illegal } } public static void testMatrixInverse() { ApcomplexField[][] elements = { { valueOf("1"), valueOf("(0,2)"), valueOf("3") }, { valueOf("4"), valueOf("5"), valueOf("(0,6)") }, { valueOf("(0,7)"), valueOf("8"), valueOf("9") } }; Matrix m = DenseMatrix.valueOf(elements); Vector vectorization = m.minus(m.inverse().inverse()).vectorization(); Apfloat sum = Apfloat.ZERO; for (int i = 0; i < vectorization.getDimension(); i++) { sum = sum.add(ApcomplexMath.abs(vectorization.get(i).value())); } assertEquals("Double inverse error", Apfloat.ZERO, sum, new Apfloat(5e-27)); } public static void testRationalFunction() { Variable.Local x = new Variable.Local("x"); Polynomial dividend = Polynomial.valueOf(valueOf("(1,2)"), Term.valueOf(x, 2)).plus(Polynomial.valueOf(valueOf("(3,4)"), x)); Polynomial divisor = Polynomial.valueOf(valueOf("(5,6)"), x).plus(valueOf("(7,8)")); RationalFunction function = RationalFunction.valueOf(dividend, divisor); assertEquals("Function value", new Apcomplex("(0.570962479608482871125611745514,0.983686786296900489396411092985)"), function.evaluate(valueOf("(2,3)")).value(), new Apfloat("5e-30")); assertEquals("Function plus inverse, value", new Apcomplex("(1.01232439638023570845221956392,0.22328325540156631537371248012)"), function.plus(function.inverse()).evaluate(valueOf("(2,3)")).value(), new Apfloat("5e-29")); } private static ApcomplexField valueOf(String value) { return new ApcomplexField(new Apcomplex(value).precision(30)); } } apfloat-1.14.0/apfloat-jscience/src/test/java/org/apfloat/jscience/ApfloatFieldTest.java000066400000000000000000000122141461767713300311750ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import java.util.HashSet; import org.apfloat.*; import org.jscience.mathematics.function.*; import org.jscience.mathematics.vector.*; import javolution.text.*; import junit.framework.TestSuite; /** * @since 1.8.0 * @version 1.9.0 * @author Mikko Tommila */ public class ApfloatFieldTest extends ApfloatTestCase { public ApfloatFieldTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApfloatFieldTest("testMatrixInverse")); suite.addTest(new ApfloatFieldTest("testRationalFunction")); suite.addTest(new ApfloatFieldTest("testBasic")); return suite; } public static void testBasic() { ApfloatField a = valueOf("100"); ApfloatField b = valueOf("200"); ApfloatField c = valueOf("200"); ApfloatField zero = valueOf("0"); assertEquals("100 + 200", valueOf("300"), a.plus(b)); assertEquals("-100", valueOf("-100"), a.opposite()); assertEquals("100 - 200", valueOf("-100"), a.minus(b)); assertEquals("100 * 200", valueOf("20000"), a.times(b)); assertEquals("1 / 100", valueOf("0.01"), a.inverse()); assertEquals("copy", a, a.copy()); assertEquals("doubleValue", 100.0, a.doubleValue(), 0.00000000000005); assertEquals("longValue", 100L, a.longValue()); assertEquals("String", "1e2", a.toString()); assertEquals("Text", new Text("1e2"), a.toText()); assertTrue("isLargerThan", b.isLargerThan(a)); assertEquals("compareTo", -1, a.compareTo(b)); HashSet set = new HashSet<>(); set.add(b); set.add(c); assertEquals("hashCode", 1, set.size()); try { zero.inverse(); fail("Zero divisor accepted"); } catch (ArithmeticException ae) { // OK, modulus is not set } try { new ApfloatField(null); fail("null accepted"); } catch (NullPointerException npe) { // OK, illegal } } public static void testMatrixInverse() { ApfloatField[][] elements = { { valueOf("1"), valueOf("2"), valueOf("3") }, { valueOf("4"), valueOf("5"), valueOf("6") }, { valueOf("7"), valueOf("8"), valueOf("10") } }; Matrix m = DenseMatrix.valueOf(elements); Vector vectorization = m.minus(m.inverse().inverse()).vectorization(); Apfloat sum = Apfloat.ZERO; for (int i = 0; i < vectorization.getDimension(); i++) { sum = sum.add(ApfloatMath.abs(vectorization.get(i).value())); } assertEquals("Double inverse error", Apfloat.ZERO, sum, new Apfloat(5e-25)); } public static void testRationalFunction() { Variable.Local x = new Variable.Local("x"); Polynomial dividend = Polynomial.valueOf(valueOf("2"), Term.valueOf(x, 2)).plus(Polynomial.valueOf(valueOf("3"), x)); Polynomial divisor = Polynomial.valueOf(valueOf("5"), x).plus(valueOf("6")); RationalFunction function = RationalFunction.valueOf(dividend, divisor); assertEquals("Function value", new Apfloat("0.875"), function.evaluate(valueOf("2")).value(), new Apfloat("5e-30")); assertEquals("Function plus inverse, value", new Apfloat("2.017857142857142857142857142857"), function.plus(function.inverse()).evaluate(valueOf("2")).value(), new Apfloat("5e-29")); } private static ApfloatField valueOf(String value) { return new ApfloatField(new Apfloat(value, 30)); } } apfloat-1.14.0/apfloat-jscience/src/test/java/org/apfloat/jscience/AprationalFieldTest.java000066400000000000000000000125641461767713300317110ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import java.util.HashSet; import org.apfloat.*; import org.jscience.mathematics.function.*; import org.jscience.mathematics.vector.*; import javolution.text.*; import junit.framework.TestSuite; /** * @since 1.8.0 * @version 1.9.0 * @author Mikko Tommila */ public class AprationalFieldTest extends ApfloatTestCase { public AprationalFieldTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new AprationalFieldTest("testMatrixInverse")); suite.addTest(new AprationalFieldTest("testRationalFunction")); suite.addTest(new AprationalFieldTest("testBasic")); return suite; } public static void testBasic() { AprationalField a = valueOf("100"); AprationalField b = valueOf("200"); AprationalField c = valueOf("200"); AprationalField zero = valueOf("0"); assertEquals("100 + 200", valueOf("300"), a.plus(b)); assertEquals("-100", valueOf("-100"), a.opposite()); assertEquals("100 - 200", valueOf("-100"), a.minus(b)); assertEquals("100 * 200", valueOf("20000"), a.times(b)); assertEquals("1 / 100", valueOf("1/100"), a.inverse()); assertEquals("copy", a, a.copy()); assertEquals("doubleValue", 100.0, a.doubleValue(), 0.00000000000005); assertEquals("longValue", 100L, a.longValue()); assertEquals("String", "100", a.toString()); assertEquals("Text", new Text("100"), a.toText()); assertTrue("isLargerThan", b.isLargerThan(a)); assertEquals("compareTo", -1, a.compareTo(b)); HashSet set = new HashSet<>(); set.add(b); set.add(c); assertEquals("hashCode", 1, set.size()); try { zero.inverse(); fail("Zero divisor accepted"); } catch (ArithmeticException ae) { // OK, modulus is not set } try { new AprationalField(null); fail("null accepted"); } catch (NullPointerException npe) { // OK, illegal } } public static void testMatrixInverse() { AprationalField[][] elements = { { valueOf("1"), valueOf("1/2"), valueOf("1/3"), valueOf("1/4"), valueOf("1/5") }, { valueOf("1/2"), valueOf("1/3"), valueOf("1/4"), valueOf("1/5"), valueOf("1/6") }, { valueOf("1/3"), valueOf("1/4"), valueOf("1/5"), valueOf("1/6"), valueOf("1/7") }, { valueOf("1/4"), valueOf("1/5"), valueOf("1/6"), valueOf("1/7"), valueOf("1/8") }, { valueOf("1/5"), valueOf("1/6"), valueOf("1/7"), valueOf("1/8"), valueOf("1/9") } }; Matrix m = DenseMatrix.valueOf(elements); Vector vectorization = m.minus(m.inverse().inverse()).vectorization(); for (int i = 0; i < vectorization.getDimension(); i++) { assertEquals("Element " + i, 0, vectorization.get(i).value().signum()); } } public static void testRationalFunction() { Variable.Local x = new Variable.Local("x"); Polynomial dividend = Polynomial.valueOf(valueOf("1/2"), Term.valueOf(x, 2)).plus(Polynomial.valueOf(valueOf("2/3"), x)); Polynomial divisor = Polynomial.valueOf(valueOf("3/4"), x).plus(valueOf("5/6")); RationalFunction function = RationalFunction.valueOf(dividend, divisor); assertEquals("Function value", valueOf("10/7"), function.evaluate(valueOf("2"))); assertEquals("Function plus inverse, value", valueOf("149/70"), function.plus(function.inverse()).evaluate(valueOf("2"))); } private static AprationalField valueOf(String value) { return new AprationalField(new Aprational(value)); } } FixedPrecisionApcomplexFieldTest.java000066400000000000000000000140051461767713300343140ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/test/java/org/apfloat/jscience/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import java.util.HashSet; import org.apfloat.*; import org.jscience.mathematics.function.*; import org.jscience.mathematics.vector.*; import javolution.text.*; import junit.framework.TestSuite; /** * @since 1.8.0 * @version 1.9.0 * @author Mikko Tommila */ public class FixedPrecisionApcomplexFieldTest extends ApfloatTestCase { public FixedPrecisionApcomplexFieldTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new FixedPrecisionApcomplexFieldTest("testBasic")); suite.addTest(new FixedPrecisionApcomplexFieldTest("testMatrixInverse")); suite.addTest(new FixedPrecisionApcomplexFieldTest("testRationalFunction")); return suite; } public static void testBasic() { FixedPrecisionApcomplexField a = valueOf("(0,100)"); FixedPrecisionApcomplexField b = valueOf("(0,200)"); FixedPrecisionApcomplexField c = valueOf("(0,200)"); FixedPrecisionApcomplexField zero = valueOf("0"); assertEquals("100 + 200", valueOf("(0,300)"), a.plus(b)); assertEquals("-100", valueOf("(0,-100)"), a.opposite()); assertEquals("100 - 200", valueOf("(0,-100)"), a.minus(b)); assertEquals("100 * 200", valueOf("-20000"), a.times(b)); assertEquals("1 / 100", valueOf("(0,-0.01)"), a.inverse()); assertEquals("copy", a, a.copy()); assertEquals("doubleValue", 0.0, a.doubleValue()); assertEquals("longValue", 0L, a.longValue()); assertEquals("String", "(0, 1e2)", a.toString()); assertEquals("Text", new Text("(0, 1e2)"), a.toText()); assertTrue("isLargerThan", b.isLargerThan(a)); assertEquals("compareTo", -1, a.compareTo(b)); HashSet set = new HashSet<>(); set.add(b); set.add(c); assertEquals("hashCode", 1, set.size()); try { zero.inverse(); fail("Zero divisor accepted"); } catch (ArithmeticException ae) { // OK, modulus is not set } try { new FixedPrecisionApcomplexField(null, HELPER); fail("null value accepted"); } catch (NullPointerException npe) { // OK, illegal } try { new FixedPrecisionApcomplexField(Apcomplex.ZERO, null); fail("null helper accepted"); } catch (NullPointerException npe) { // OK, illegal } } public static void testMatrixInverse() { FixedPrecisionApcomplexField[][] elements = { { valueOf("1"), valueOf("(0,2)"), valueOf("3") }, { valueOf("4"), valueOf("5"), valueOf("(0,6)") }, { valueOf("(0,7)"), valueOf("8"), valueOf("9") } }; Matrix m = DenseMatrix.valueOf(elements); Vector vectorization = m.minus(m.inverse().inverse()).vectorization(); Apfloat sum = Apfloat.ZERO; for (int i = 0; i < vectorization.getDimension(); i++) { sum = sum.add(ApcomplexMath.abs(vectorization.get(i).value())); } assertEquals("Double inverse error", Apfloat.ZERO, sum, new Apfloat(5e-28)); } public static void testRationalFunction() { Variable.Local x = new Variable.Local("x"); Polynomial dividend = Polynomial.valueOf(valueOf("(1,2)"), Term.valueOf(x, 2)).plus(Polynomial.valueOf(valueOf("(3,4)"), x)); Polynomial divisor = Polynomial.valueOf(valueOf("(5,6)"), x).plus(valueOf("(7,8)")); RationalFunction function = RationalFunction.valueOf(dividend, divisor); assertEquals("Function value", new Apcomplex("(0.570962479608482871125611745514,0.983686786296900489396411092985)"), function.evaluate(valueOf("(2,3)")).value(), new Apfloat("5e-30")); assertEquals("Function plus inverse, value", new Apcomplex("(1.01232439638023570845221956392,0.22328325540156631537371248012)"), function.plus(function.inverse()).evaluate(valueOf("(2,3)")).value(), new Apfloat("5e-29")); } private static FixedPrecisionApcomplexField valueOf(String value) { return new FixedPrecisionApcomplexField(new Apcomplex(value), HELPER); } private static final FixedPrecisionApcomplexHelper HELPER = new FixedPrecisionApcomplexHelper(30); } FixedPrecisionApfloatFieldTest.java000066400000000000000000000134651461767713300337630ustar00rootroot00000000000000apfloat-1.14.0/apfloat-jscience/src/test/java/org/apfloat/jscience/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import java.util.HashSet; import org.apfloat.*; import org.jscience.mathematics.function.*; import org.jscience.mathematics.vector.*; import javolution.text.*; import junit.framework.TestSuite; /** * @since 1.8.0 * @version 1.9.0 * @author Mikko Tommila */ public class FixedPrecisionApfloatFieldTest extends ApfloatTestCase { public FixedPrecisionApfloatFieldTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new FixedPrecisionApfloatFieldTest("testBasic")); suite.addTest(new FixedPrecisionApfloatFieldTest("testMatrixInverse")); suite.addTest(new FixedPrecisionApfloatFieldTest("testRationalFunction")); return suite; } public static void testBasic() { FixedPrecisionApfloatField a = valueOf("100"); FixedPrecisionApfloatField b = valueOf("200"); FixedPrecisionApfloatField c = valueOf("200"); FixedPrecisionApfloatField zero = valueOf("0"); assertEquals("100 + 200", valueOf("300"), a.plus(b)); assertEquals("-100", valueOf("-100"), a.opposite()); assertEquals("100 - 200", valueOf("-100"), a.minus(b)); assertEquals("100 * 200", valueOf("20000"), a.times(b)); assertEquals("1 / 100", valueOf("0.01"), a.inverse()); assertEquals("copy", a, a.copy()); assertEquals("doubleValue", 100.0, a.doubleValue(), 0.00000000000005); assertEquals("longValue", 100L, a.longValue()); assertEquals("String", "1e2", a.toString()); assertEquals("Text", new Text("1e2"), a.toText()); assertTrue("isLargerThan", b.isLargerThan(a)); assertEquals("compareTo", -1, a.compareTo(b)); HashSet set = new HashSet<>(); set.add(b); set.add(c); assertEquals("hashCode", 1, set.size()); try { zero.inverse(); fail("Zero divisor accepted"); } catch (ArithmeticException ae) { // OK, modulus is not set } try { new FixedPrecisionApfloatField(null, HELPER); fail("null value accepted"); } catch (NullPointerException npe) { // OK, illegal } try { new FixedPrecisionApfloatField(Apcomplex.ZERO, null); fail("null helper accepted"); } catch (NullPointerException npe) { // OK, illegal } } public static void testMatrixInverse() { FixedPrecisionApfloatField[][] elements = { { valueOf("1"), valueOf("2"), valueOf("3") }, { valueOf("4"), valueOf("5"), valueOf("6") }, { valueOf("7"), valueOf("8"), valueOf("10") } }; Matrix m = DenseMatrix.valueOf(elements); Vector vectorization = m.minus(m.inverse().inverse()).vectorization(); Apfloat sum = Apfloat.ZERO; for (int i = 0; i < vectorization.getDimension(); i++) { sum = sum.add(ApfloatMath.abs(vectorization.get(i).value())); } assertEquals("Double inverse error", Apfloat.ZERO, sum, new Apfloat(5e-28)); } public static void testRationalFunction() { Variable.Local x = new Variable.Local("x"); Polynomial dividend = Polynomial.valueOf(valueOf("2"), Term.valueOf(x, 2)).plus(Polynomial.valueOf(valueOf("3"), x)); Polynomial divisor = Polynomial.valueOf(valueOf("5"), x).plus(valueOf("6")); RationalFunction function = RationalFunction.valueOf(dividend, divisor); assertEquals("Function value", new Apfloat("0.875"), function.evaluate(valueOf("2")).value(), new Apfloat("5e-30")); assertEquals("Function plus inverse, value", new Apfloat("2.017857142857142857142857142857"), function.plus(function.inverse()).evaluate(valueOf("2")).value(), new Apfloat("5e-29")); } private static FixedPrecisionApfloatField valueOf(String value) { return new FixedPrecisionApfloatField(new Apfloat(value), HELPER); } private static final FixedPrecisionApfloatHelper HELPER = new FixedPrecisionApfloatHelper(30); } apfloat-1.14.0/apfloat-jscience/src/test/java/org/apfloat/jscience/ModuloApintFieldTest.java000066400000000000000000000136161461767713300320510ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.jscience; import java.util.HashSet; import org.apfloat.*; import org.jscience.mathematics.function.*; import org.jscience.mathematics.vector.*; import javolution.text.*; import junit.framework.TestSuite; /** * @since 1.8.0 * @version 1.9.0 * @author Mikko Tommila */ public class ModuloApintFieldTest extends ApfloatTestCase { public ModuloApintFieldTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ModuloApintFieldTest("testBasic")); suite.addTest(new ModuloApintFieldTest("testNoModulus")); suite.addTest(new ModuloApintFieldTest("testMatrixInverse")); suite.addTest(new ModuloApintFieldTest("testRationalFunction")); return suite; } public static void testBasic() { ModuloApintField.setModulus(new Apint(65537)); ModuloApintField a = valueOf(100); ModuloApintField b = valueOf(200); ModuloApintField c = valueOf(200); ModuloApintField zero = valueOf(0); assertEquals("100 + 200", valueOf(300), a.plus(b)); assertEquals("-100", valueOf(65537 - 100), a.opposite()); assertEquals("100 - 200", valueOf(65537 - 100), a.minus(b)); assertEquals("100 * 200", valueOf(20000), a.times(b)); assertEquals("1 / 100", valueOf(17695), a.inverse()); assertEquals("copy", a, a.copy()); assertEquals("doubleValue", 100.0, a.doubleValue(), 0.00000000000005); assertEquals("longValue", 100L, a.longValue()); assertEquals("String", "100", a.toString()); assertEquals("Text", new Text("100"), a.toText()); assertTrue("isLargerThan", b.isLargerThan(a)); assertEquals("compareTo", -1, a.compareTo(b)); HashSet set = new HashSet<>(); set.add(b); set.add(c); assertEquals("hashCode", 1, set.size()); try { zero.inverse(); fail("Zero divisor accepted"); } catch (ArithmeticException ae) { // OK, modulus is not set } try { new ModuloApintField(null); fail("null accepted"); } catch (NullPointerException npe) { // OK, illegal } } public static void testNoModulus() { ModuloApintField.setModulus(null); ModuloApintField a = valueOf(100), b = valueOf(200); assertEquals("100 + 200", valueOf(300), a.plus(b)); assertEquals("-100", valueOf(-100), a.opposite()); assertEquals("100 - 200", valueOf(-100), a.minus(b)); assertEquals("100 * 200", valueOf(20000), a.times(b)); assertEquals("copy", a, a.copy()); try { a.inverse(); fail("No divisor accepted"); } catch (ArithmeticException ae) { // OK, modulus is not set } } public static void testMatrixInverse() { ModuloApintField.setModulus(new Apint(43)); ModuloApintField[][] elements = { { valueOf(1), valueOf(2), valueOf(3) }, { valueOf(4), valueOf(5), valueOf(6) }, { valueOf(7), valueOf(8), valueOf(10) } }; Matrix m = DenseMatrix.valueOf(elements); Vector vectorization = m.minus(m.inverse().inverse()).vectorization(); for (int i = 0; i < vectorization.getDimension(); i++) { assertEquals("Element " + i, 0, vectorization.get(i).value().signum()); } } public static void testRationalFunction() { ModuloApintField.setModulus(new Apint(43)); Variable.Local x = new Variable.Local("x"); Polynomial dividend = Polynomial.valueOf(valueOf(17), Term.valueOf(x, 2)).plus(Polynomial.valueOf(valueOf(23), x)); Polynomial divisor = Polynomial.valueOf(valueOf(37), x).plus(valueOf(26)); RationalFunction function = RationalFunction.valueOf(dividend, divisor); assertEquals("Function value", new Apint(2), function.evaluate(valueOf(2)).value()); assertEquals("Function plus inverse, value", new Apint(24), function.plus(function.inverse()).evaluate(valueOf(2)).value()); } private static ModuloApintField valueOf(int value) { return new ModuloApintField(new Apint(value)); } } apfloat-1.14.0/apfloat-samples/000077500000000000000000000000001461767713300163325ustar00rootroot00000000000000apfloat-1.14.0/apfloat-samples/pom.xml000066400000000000000000000106121461767713300176470ustar00rootroot00000000000000 4.0.0 org.apfloat apfloat-parent 1.14.0 apfloat-samples apfloat-samples Sample programs for apfloat for calculating pi http://www.apfloat.org org.apfloat apfloat org.apfloat apfloat-aparapi true org.apfloat apfloat-calc true junit junit test org.apache.maven.plugins maven-compiler-plugin * org.apache.maven.plugins maven-jar-plugin true org.apfloat.samples.PiParallelGUI org.apfloat.samples org.apache.maven.plugins maven-shade-plugin custom-jar shade org.apfloat:apfloat-samples ${project.build.directory}/samples.jar apfloat.jar signed-applet shade org.apfloat:apfloat org.apfloat:apfloat-calc org.apfloat:apfloat-samples ${project.build.directory}/signedapplet.jar org.apache.maven.plugins maven-jarsigner-plugin sign ${project.build.directory}/signedapplet.jar mykey password src/main/resources cluster.properties apfloat-1.14.0/apfloat-samples/src/000077500000000000000000000000001461767713300171215ustar00rootroot00000000000000apfloat-1.14.0/apfloat-samples/src/main/000077500000000000000000000000001461767713300200455ustar00rootroot00000000000000apfloat-1.14.0/apfloat-samples/src/main/java/000077500000000000000000000000001461767713300207665ustar00rootroot00000000000000apfloat-1.14.0/apfloat-samples/src/main/java/org/000077500000000000000000000000001461767713300215555ustar00rootroot00000000000000apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/000077500000000000000000000000001461767713300232035ustar00rootroot00000000000000apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/000077500000000000000000000000001461767713300246475ustar00rootroot00000000000000apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/ApfloatHolder.java000066400000000000000000000045421461767713300302430ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.io.Serializable; import org.apfloat.Apfloat; /** * Simple JavaBean to hold one {@link org.apfloat.Apfloat}. * This class can also be thought of as a pointer to an {@link Apfloat}. * * @version 1.9.0 * @author Mikko Tommila */ public class ApfloatHolder implements Serializable { /** * Construct an ApfloatHolder containing null. */ public ApfloatHolder() { this(null); } /** * Construct an ApfloatHolder containing the specified apfloat. * * @param apfloat The number to hold. */ public ApfloatHolder(Apfloat apfloat) { this.apfloat = apfloat; } /** * Return the apfloat contained in this bean. * * @return The apfloat contained in this bean. */ public Apfloat getApfloat() { return this.apfloat; } /** * Set the apfloat contained in this bean. * * @param apfloat The apfloat. */ public void setApfloat(Apfloat apfloat) { this.apfloat = apfloat; } private static final long serialVersionUID = 1L; private Apfloat apfloat; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/BackgroundOperation.java000066400000000000000000000064721461767713300314630ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import java.util.concurrent.ExecutionException; import org.apfloat.ApfloatContext; /** * Class for running an {@link Operation} in the background in a separate thread. * The operation is executed using the ExecutorService retrieved from * {@link ApfloatContext#getExecutorService()}. * * @version 1.14.0 * @author Mikko Tommila */ public class BackgroundOperation { /** * Runs an operation in the background in a separate thread. * The execution is started immediately. * * @param operation The operation to execute. */ public BackgroundOperation(Operation operation) { ApfloatContext ctx = ApfloatContext.getContext(); ExecutorService executorService = ctx.getExecutorService(); FutureTask futureTask = new FutureTask<>(operation::execute); executorService.execute(futureTask); this.future = futureTask; } /** * Check if the operation has been completed. * * @return true if the execution of the operation has been completed, otherwise false. */ public boolean isFinished() { return this.future.isDone(); } /** * Cancel the operation by interrupting the thread executing it. * * @since 1.14.0 */ public void cancel() { this.future.cancel(true); } /** * Get the result of the operation. * This method blocks until the operation has been completed. * * @return Result of the operation. * * @exception RuntimeException If an exception was thrown by the executed operation. */ public T getResult() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.wait(this.future); try { return this.future.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } private Future future; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/LocalOperationExecutor.java000066400000000000000000000046431461767713300321530ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; /** * Class to execute {@link Operation}s locally. * The execution is done in the current JVM. * * @version 1.9.0 * @author Mikko Tommila */ public class LocalOperationExecutor implements OperationExecutor { /** * Default constructor. */ public LocalOperationExecutor() { } /** * Execute an operation immediately. * This method will block until the operation is complete. * * @param operation The operation to execute. * * @return The result of the operation. */ @Override public T execute(Operation operation) { return operation.execute(); } /** * Execute an operation in the background. * This method starts a new thread executing the operation and returns immediately. * * @param operation The operation to execute in the background. * * @return A {@link BackgroundOperation} for retrieving the result of the operation later. */ @Override public BackgroundOperation executeBackground(Operation operation) { return new BackgroundOperation<>(operation); } @Override public int getWeight() { return 1; } } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/Operation.java000066400000000000000000000030651461767713300274560ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.io.Serializable; /** * Interface for implementing arbitrary operations to be executed. * * @version 1.9.0 * @author Mikko Tommila */ @FunctionalInterface public interface Operation extends Serializable { /** * Executes some code, returning a value. * * @return Return value of the operation. */ public T execute(); } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/OperationExecutor.java000066400000000000000000000045101461767713300311710ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; /** * Interface for implementing objects that can execute {@link Operation}s. * An operation can e.g. be executed locally or remotely. * * @version 1.1 * @author Mikko Tommila */ public interface OperationExecutor { /** * Executes some code, returning a value. * * @param Return value type of the operation. * @param operation The operation to execute. * * @return Return value of the operation. */ public T execute(Operation operation); /** * Starts executing some code in the background. * * @param Return value type of the operation. * @param operation The operation to execute in the background. * * @return An object for retrieving the result of the operation later. */ public BackgroundOperation executeBackground(Operation operation); /** * Returns the relative weight of this executor. * The weights of different operation executors can be used * to distribute work more equally. * * @return The relative weight of this operation executor. */ public int getWeight(); } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/OperationServer.java000066400000000000000000000206051461767713300306440ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.nio.channels.Channels; import java.nio.channels.Selector; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.nio.channels.ServerSocketChannel; import java.net.InetSocketAddress; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.BufferedOutputStream; import java.io.IOException; import java.util.Set; import java.util.Iterator; import java.util.concurrent.Executor; import java.util.concurrent.Executors; /** * Server for executing {@link Operation}s from remote calls. The client * should simply send a class implementing the {@link Operation} * interface serialized through a socket connection. Obviously, the * class must exist also in the server's classpath. The server will then * simply call {@link Operation#execute()} on the operation, and send * the resulting object back in the socket, serialized. If an exception * occurs during the operation execution, nothing is returned and * the socket connection is closed. * * @version 1.9.0 * @author Mikko Tommila */ public class OperationServer { private static class Request implements Runnable { public Request(SocketChannel channel) { this.channel = channel; } @Override public void run() { try (SocketChannel channel = this.channel) { info("Request processing started"); ObjectInputStream in = new ObjectInputStream(Channels.newInputStream(this.channel)); info("Ready to receive input data"); Operation operation = (Operation) in.readObject(); info("Executing operation"); Object result = operation.execute(); ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(Channels.newOutputStream(this.channel), BUFFER_SIZE)); info("Ready to write output data"); out.writeObject(result); out.flush(); info("Request processing complete"); } catch (Exception e) { // Avoid exiting the thread warning("Request processing failed", e); } } private SocketChannel channel; } private OperationServer() { } /** * Command-line entry point. * * @param args Command-line parameters. * * @exception IOException In case of unexpected network error. */ public static void main(String[] args) throws IOException { int port, workerThreads = 1; if (args.length < 1) { System.err.println("USAGE: OperationServer port [workerThreads] [messageLevel]"); return; } try { port = Integer.parseInt(args[0]); } catch (NumberFormatException nfe) { System.err.println("Invalid port: " + args[0]); return; } try { if (args.length > 1) { workerThreads = Integer.parseInt(args[1]); if (workerThreads <= 0) { throw new NumberFormatException(); } } } catch (NumberFormatException nfe) { System.err.println("Invalid number of workerThreads: " + args[0]); return; } try { if (args.length > 2) { messageLevel = Integer.parseInt(args[2]); } } catch (NumberFormatException nfe) { System.err.println("Invalid messageLevel: " + args[0]); return; } // Create a selector object to monitor all open client connections. Selector selector = Selector.open(); // Create a new non-blocking ServerSocketChannel, bind it to a port, and register it with the Selector ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); // Open channel serverSocketChannel.configureBlocking(false); // Set non-blocking mode serverSocketChannel.socket().bind(new InetSocketAddress(port)); // Bind to port SelectionKey serverKey = serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // Create a pool of worker threads that will run independently Executor executor = Executors.newFixedThreadPool(workerThreads); info("Waiting for connections to port " + port); while (true) // The main server loop. The server runs forever. { // This call blocks until there is activity on one of the registered channels selector.select(); // Get a java.util.Set containing the SelectionKey objects for all channels that are ready for I/O Set keys = selector.selectedKeys(); // Use a java.util.Iterator to loop through the selected keys for (Iterator i = keys.iterator(); i.hasNext(); ) { SelectionKey key = i.next(); i.remove(); // Remove the key from the set of selected keys // Check whether this key is the SelectionKey we got when we registered the ServerSocketChannel if (key == serverKey) { // Activity on the ServerSocketChannel means a client is trying to connect to the server if (key.isAcceptable()) { // Accept the client connection // Note that the client channel is in blocking mode; a separate thread will use it SocketChannel clientSocketChannel = serverSocketChannel.accept(); info("New connection accepted"); // Put a new request to the queue so a worker thread can pick it up from there executor.execute(new Request(clientSocketChannel)); } } } } } private static void warning(String message, Exception e) { if (messageLevel >= WARNING) { System.err.println("WARNING: " + Thread.currentThread().getName() + ": " + message); e.printStackTrace(System.err); } } private static void info(String message) { if (messageLevel >= INFO) { System.err.println("INFO: " + Thread.currentThread().getName() + ": " + message); } } private static void debug(String message) { if (messageLevel >= DEBUG) { System.err.println("DEBUG: " + Thread.currentThread().getName() + ": " + message); } } private static final int BUFFER_SIZE = 8192; private static final int ERROR = 0; private static final int WARNING = 1; private static final int INFO = 2; private static final int DEBUG = 3; private static int messageLevel = WARNING; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/Pi.java000066400000000000000000001002121461767713300260560ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.io.Serializable; import java.io.PrintWriter; import java.io.IOException; import java.util.concurrent.atomic.AtomicLong; import org.apfloat.Apfloat; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatMath; import org.apfloat.ApfloatRuntimeException; /** * Calculates pi using four different algorithms. * * @version 1.14.0 * @author Mikko Tommila */ public class Pi { // Implementation note: we use printf() for printing, because it flushes the output (print() does not) /** * Terms for the binary splitting series. */ protected static interface BinarySplittingSeries extends Serializable { /** * Binary splitting term. * * @param n The term. * * @return The value. */ public Apfloat a(long n) throws ApfloatRuntimeException; /** * Binary splitting term. * * @param n The term. * * @return The value. */ public Apfloat p(long n) throws ApfloatRuntimeException; /** * Binary splitting term. * * @param n The term. * * @return The value. */ public Apfloat q(long n) throws ApfloatRuntimeException; } /** * Abstract base class for the binary splitting series. */ protected static abstract class AbstractBinarySplittingSeries implements BinarySplittingSeries { /** * Construct a binary splitting series with the specified precision and radix. * * @param precision The target precision. * @param radix The radix to be used. */ protected AbstractBinarySplittingSeries(long precision, int radix) { this.precision = precision; this.radix = radix; } /** * Target precision. */ protected long precision; /** * Radix to be used. */ protected int radix; private static final long serialVersionUID = 1L; } /** * Chudnovskys' algorithm terms for the binary splitting series. */ protected static class ChudnovskyBinarySplittingSeries extends AbstractBinarySplittingSeries { /** * Basic constructor. * * @param precision The precision. * @param radix The radix. */ public ChudnovskyBinarySplittingSeries(long precision, int radix) { super(precision, radix); this.A = new Apfloat(13591409, precision, radix); this.B = new Apfloat(545140134, precision, radix); this.J = new Apfloat(10939058860032000L, precision, radix); this.ONE = new Apfloat(1, precision, radix); this.TWO = new Apfloat(2, precision, radix); this.FIVE = new Apfloat(5, precision, radix); this.SIX = new Apfloat(6, precision, radix); } @Override public Apfloat a(long n) throws ApfloatRuntimeException { Apfloat s = new Apfloat(n, Apfloat.INFINITE, this.radix), v = this.A.add(this.B.multiply(s)); v = ((n & 1) == 0 ? v : v.negate()); return v; } @Override public Apfloat p(long n) throws ApfloatRuntimeException { Apfloat v; if (n == 0) { v = this.ONE; } else { Apfloat f = new Apfloat(n, Apfloat.INFINITE, this.radix), sixf = this.SIX.multiply(f); v = sixf.subtract(this.ONE).multiply(this.TWO.multiply(f).subtract(this.ONE)).multiply(sixf.subtract(this.FIVE)); } return v; } @Override public Apfloat q(long n) throws ApfloatRuntimeException { Apfloat v; if (n == 0) { v = this.ONE; } else { Apfloat f = new Apfloat(n, Apfloat.INFINITE, this.radix); v = this.J.multiply(f.multiply(f).multiply(f)); } return v; } private static final long serialVersionUID = 1L; private final Apfloat A; private final Apfloat B; private final Apfloat J; private final Apfloat ONE; private final Apfloat TWO; private final Apfloat FIVE; private final Apfloat SIX; } /** * Ramanujan's algorithm terms for the binary splitting series. */ protected static class RamanujanBinarySplittingSeries extends AbstractBinarySplittingSeries { /** * Basic constructor. * * @param precision The precision. * @param radix The radix. */ public RamanujanBinarySplittingSeries(long precision, int radix) { super(precision, radix); this.A = new Apfloat(1103, precision, radix); this.B = new Apfloat(26390, precision, radix); this.J = new Apfloat(3073907232L, precision, radix); this.ONE = new Apfloat(1, precision, radix); this.TWO = new Apfloat(2, precision, radix); this.THREE = new Apfloat(3, precision, radix); this.FOUR = new Apfloat(4, precision, radix); } @Override public Apfloat a(long n) throws ApfloatRuntimeException { Apfloat s = new Apfloat(n, Apfloat.INFINITE, this.radix), v = this.A.add(this.B.multiply(s)); return v; } @Override public Apfloat p(long n) throws ApfloatRuntimeException { Apfloat v; if (n == 0) { v = this.ONE; } else { Apfloat f = new Apfloat(n, Apfloat.INFINITE, this.radix), fourf = this.FOUR.multiply(f); v = fourf.subtract(this.ONE).multiply(this.TWO.multiply(f).subtract(this.ONE)).multiply(fourf.subtract(this.THREE)); } return v; } @Override public Apfloat q(long n) throws ApfloatRuntimeException { Apfloat v; if (n == 0) { v = this.ONE; } else { Apfloat f = new Apfloat(n, Apfloat.INFINITE, this.radix); v = this.J.multiply(f.multiply(f).multiply(f)); } return v; } private static final long serialVersionUID = 1L; private final Apfloat A; private final Apfloat B; private final Apfloat J; private final Apfloat ONE; private final Apfloat TWO; private final Apfloat THREE; private final Apfloat FOUR; } /** * Class for implementing the binary splitting algorithm. */ protected static class BinarySplittingPiCalculator implements Serializable { /** * Construct a pi calculator with the specified precision and radix. * * @param series The binary splitting series to be used. */ public BinarySplittingPiCalculator(BinarySplittingSeries series) { this.series = series; } /** * Entry point for the binary splitting algorithm. * * @param n1 Start term. * @param n2 End term. * @param T Algorithm parameter. * @param Q Algorithm parameter. * @param P Algorithm parameter. * @param progressIndicator Class to print out the progress of the calculation. */ public void r(long n1, long n2, ApfloatHolder T, ApfloatHolder Q, ApfloatHolder P, BinarySplittingProgressIndicator progressIndicator) throws ApfloatRuntimeException { assert (n1 != n2); long length = n2 - n1; if (length == 1) { Apfloat p0 = p(n1); T.setApfloat(a(n1).multiply(p0)); Q.setApfloat(q(n1)); if (P != null) P.setApfloat(p0); } else { long nMiddle = n1 + n2 >> 1; ApfloatHolder LT = new ApfloatHolder(), LQ = new ApfloatHolder(), LP = new ApfloatHolder(); r(n1, nMiddle, LT, LQ, LP, progressIndicator); r(nMiddle, n2, T, Q, P, progressIndicator); T.setApfloat(Q.getApfloat().multiply(LT.getApfloat()).add(LP.getApfloat().multiply(T.getApfloat()))); Q.setApfloat(LQ.getApfloat().multiply(Q.getApfloat())); if (P != null) P.setApfloat(LP.getApfloat().multiply(P.getApfloat())); } if (progressIndicator != null) { progressIndicator.progress(n1, n2); } } private Apfloat a(long n) throws ApfloatRuntimeException { return this.series.a(n); } private Apfloat p(long n) throws ApfloatRuntimeException { return this.series.p(n); } private Apfloat q(long n) throws ApfloatRuntimeException { return this.series.q(n); } private static final long serialVersionUID = 1L; private BinarySplittingSeries series; } /** * Basic class for calculating pi using the Chudnovskys' binary splitting algorithm. */ public static class ChudnovskyPiCalculator implements Operation { /** * Construct a pi calculator with the specified precision and radix. * * @param precision The target precision. * @param radix The radix to be used. */ public ChudnovskyPiCalculator(long precision, int radix) throws ApfloatRuntimeException { this(new BinarySplittingPiCalculator(new ChudnovskyBinarySplittingSeries(precision, radix)), precision, radix); } /** * Construct a pi calculator with the specified binary splitting algorithm. * * @param calculator The binary splitting algorithm to be used. * @param precision The target precision. * @param radix The radix to be used. */ protected ChudnovskyPiCalculator(BinarySplittingPiCalculator calculator, long precision, int radix) throws ApfloatRuntimeException { this.calculator = calculator; this.precision = precision; this.radix = radix; } /** * Calculate pi using the Chudnovskys' binary splitting algorithm. */ @Override public Apfloat execute() { Pi.err.println("Using the Chudnovsky brothers' binary splitting algorithm"); ApfloatHolder T = new ApfloatHolder(), Q = new ApfloatHolder(); // Perform the calculation of T, Q and P to requested precision only, to improve performance long terms = (long) ((double) this.precision * Math.log((double) this.radix) / 32.654450041768516); long time = System.currentTimeMillis(); this.calculator.r(0, terms + 1, T, Q, null, new BinarySplittingProgressIndicator(terms)); time = System.currentTimeMillis() - time; Pi.err.println("100% complete, elapsed time " + time / 1000.0 + " seconds"); Pi.err.printf("Final value "); time = System.currentTimeMillis(); Apfloat t = T.getApfloat(), q = Q.getApfloat(); Apfloat factor = ApfloatMath.inverseRoot(new Apfloat(1823176476672000L, this.precision, this.radix), 2); Apfloat pi = ApfloatMath.inverseRoot(factor.multiply(t), 1).multiply(q); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); return pi; } private static final long serialVersionUID = 1L; private BinarySplittingPiCalculator calculator; private long precision; private int radix; } /** * Basic class for calculating pi using the Ramanujan binary splitting algorithm. */ public static class RamanujanPiCalculator implements Operation { /** * Construct a pi calculator with the specified precision and radix. * * @param precision The target precision. * @param radix The radix to be used. */ public RamanujanPiCalculator(long precision, int radix) throws ApfloatRuntimeException { this(new BinarySplittingPiCalculator(new RamanujanBinarySplittingSeries(precision, radix)), precision, radix); } /** * Construct a pi calculator with the specified binary splitting algorithm. * * @param calculator The binary splitting algorithm to be used. * @param precision The target precision. * @param radix The radix to be used. */ protected RamanujanPiCalculator(BinarySplittingPiCalculator calculator, long precision, int radix) throws ApfloatRuntimeException { this.calculator = calculator; this.precision = precision; this.radix = radix; } /** * Calculate pi using the Ramanujan binary splitting algorithm. */ @Override public Apfloat execute() { Pi.err.println("Using the Ramanujan binary splitting algorithm"); ApfloatHolder T = new ApfloatHolder(), Q = new ApfloatHolder(); // Perform the calculation of T, Q and P to requested precision only, to improve performance long terms = (long) ((double) this.precision * Math.log((double) this.radix) / 18.38047940053836); long time = System.currentTimeMillis(); this.calculator.r(0, terms + 1, T, Q, null, new BinarySplittingProgressIndicator(terms)); time = System.currentTimeMillis() - time; Pi.err.println("100% complete, elapsed time " + time / 1000.0 + " seconds"); Pi.err.printf("Final value "); time = System.currentTimeMillis(); Apfloat t = T.getApfloat(), q = Q.getApfloat(); Apfloat factor = ApfloatMath.inverseRoot(new Apfloat(8, this.precision, this.radix), 2); Apfloat pi = ApfloatMath.inverseRoot(t, 1).multiply(factor).multiply(new Apfloat(9801, Apfloat.INFINITE, this.radix)).multiply(q); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); return pi; } private static final long serialVersionUID = 1L; private BinarySplittingPiCalculator calculator; private long precision; private int radix; } /** * Indicates progress of the pi calculation using * the binary splitting algorithm.

* * This implementation is thread safe for multiple * threads to use concurrently. */ public static class BinarySplittingProgressIndicator implements Serializable { /** * Construct a progress indicator with the specified * number of terms of the series. * * @param terms Total number of terms to be calculated. */ public BinarySplittingProgressIndicator(long terms) { this.totalElements = (long) (terms * (Math.log((double) terms) / Math.log(2.0) + 1.0)) + 1; this.currentElements = new AtomicLong(); // Use atomic long for thread safe but non-blocking access } /** * Advances the progress. * * @param n1 First term that has been calculated. * @param n2 Last term that has been calculated, minus one. */ public void progress(long n1, long n2) { long length = n2 - n1; // For small ranges the amount of progress is advanced in one chunk, including the progress of all the recursive steps long addedElements; if (length < PROGRESS_RECURSION_THRESHOLD >> 1) { // Sub-range of a small range, was progressed already return; } else if (length < PROGRESS_RECURSION_THRESHOLD) { // Small range, calculate the recursive progress addedElements = recursiveLength(length); } else { // Large range, calculate just this step addedElements = length; } long oldElements = this.currentElements.getAndAdd(addedElements); long elements = oldElements + addedElements; int oldPercentComplete = (int) (100 * oldElements / this.totalElements); int percentComplete = (int) (100 * elements / this.totalElements); if (percentComplete != oldPercentComplete) { Pi.err.printf(percentComplete + "%% complete\r"); } } private long recursiveLength(long length) { long recursiveLength; if (length == 1) { recursiveLength = 1; } else if (length == PROGRESS_RECURSION_THRESHOLD - 1) { // Borderline case, half of this will be calculated separately recursiveLength = recursiveLength(length >> 1) + length; } else { long halfLength = length >> 1; recursiveLength = recursiveLength(halfLength) + recursiveLength(length - halfLength) + length; } return recursiveLength; } private static final long serialVersionUID = 1L; private static final long PROGRESS_RECURSION_THRESHOLD = 32; private long totalElements; private AtomicLong currentElements; } /** * Calculates pi using the Gauss-Legendre algorithm. */ public static class GaussLegendrePiCalculator implements Operation { /** * Construct a pi calculator with the specified precision and radix. * * @param precision The target precision. * @param radix The radix to be used. */ public GaussLegendrePiCalculator(long precision, int radix) { this.precision = precision; this.radix = radix; } /** * Calculate pi using the Gauss-Legendre iteration. */ @Override public Apfloat execute() { Pi.err.println("Using the Gauss-Legendre iteration"); int iterations = 0; while (gaussLegendrePrecision(iterations, 4, this.radix) < this.precision) { iterations++; } Pi.err.println("Total " + iterations + " iterations"); Pi.err.printf("Initial values "); long time = System.currentTimeMillis(); Apfloat two = new Apfloat(2, this.precision, this.radix), four = new Apfloat(4, this.precision, this.radix), a = new Apfloat(1, this.precision, this.radix), b = ApfloatMath.inverseRoot(two, 2), t = a.divide(four); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); for (int i = 0; i < iterations; i++) { Pi.err.printf("Iteration " + (i + 1) + " "); time = System.currentTimeMillis(); Apfloat tmp = a; a = a.add(b).divide(two); b = tmp.multiply(b); b = ApfloatMath.sqrt(b); t = t.subtract(new Apfloat(1L << i, this.precision, this.radix).multiply(ApfloatMath.pow(tmp.subtract(a), 2))); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); } Pi.err.printf("Final value "); time = System.currentTimeMillis(); a = a.add(b); t = four.multiply(t); Apfloat pi = ApfloatMath.pow(a, 2).divide(t); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); return pi; } // What precision is achieved with k Gauss-Legendre iterations private static long gaussLegendrePrecision(int k, int r, int radix) { return (long) ((Math.pow(2.0, (double) k) * Math.sqrt((double) r) * Math.PI - Math.log(16.0 * Math.sqrt((double) r)) - k * Math.log(2.0)) / Math.log((double) radix)); } private static final long serialVersionUID = 1L; private long precision; private int radix; } /** * Calculates pi using the Borweins' quartic algorithm. */ public static class BorweinPiCalculator implements Operation { /** * Construct a pi calculator with the specified precision and radix. * * @param precision The target precision. * @param radix The radix to be used. */ public BorweinPiCalculator(long precision, int radix) { this.precision = precision; this.radix = radix; } /** * Calculate pi using the Borweins' quartic iteration. */ @Override public Apfloat execute() { Pi.err.println("Using the Borweins' quartic iteration"); int iterations = 0; while (borweinPrecision(iterations, 4, this.radix) < this.precision) { iterations++; } Pi.err.println("Total " + iterations + " iterations"); Pi.err.printf("Initial values "); long time = System.currentTimeMillis(); Apfloat one = new Apfloat(1, this.precision, this.radix), two = new Apfloat(2, this.precision, this.radix), four = new Apfloat(4, this.precision, this.radix), y = ApfloatMath.sqrt(two).subtract(one), a = two.subtract(four.multiply(y)); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); for (int i = 0; i < iterations; i++) { Pi.err.printf("Iteration " + (i + 1) + " "); time = System.currentTimeMillis(); Apfloat tmp = ApfloatMath.pow(y, 4); y = one.subtract(tmp); y = ApfloatMath.inverseRoot(y, 4); y = y.subtract(one).divide(y.add(one)); tmp = ApfloatMath.pow(y.add(one), 2); a = a.multiply(tmp).multiply(tmp); a = a.subtract(new Apfloat(1L << (2 * i + 3), this.precision, this.radix).multiply(y).multiply(tmp.subtract(y))); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); } Pi.err.printf("Final value "); time = System.currentTimeMillis(); Apfloat pi = one.divide(a); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); return pi; } // What precision is achieved with k Borweins' quartic iterations private static long borweinPrecision(int k, int r, int radix) { return (long) ((Math.pow(4.0, (double) k) * Math.sqrt((double) r) * Math.PI - Math.log(16.0 * Math.sqrt((double) r)) - k * Math.log(4.0)) / Math.log((double) radix)); } private static final long serialVersionUID = 1L; private long precision; private int radix; } /** * Parse a long from an argument. * * @param arg The string to be parsed. * @param name Description of the argument. * @param minValue Minimum allowed value. * @param maxValue Maximum allowed value. * * @return Valid long. */ protected static long getLong(String arg, String name, long minValue, long maxValue) { long value = 0; try { value = Long.parseLong(arg); if (value < minValue || value > maxValue) { throw new NumberFormatException(); } } catch (NumberFormatException nfe) { System.err.println("Invalid " + name + ": " + arg); System.exit(1); } return value; } /** * Parse an integer from an argument. * * @param arg The string to be parsed. * @param name Description of the argument. * @param minValue Minimum allowed value. * @param maxValue Maximum allowed value. * * @return Valid integer. */ protected static int getInt(String arg, String name, int minValue, int maxValue) { return (int) getLong(arg, name, minValue, maxValue); } /** * Parse the precision from an argument. * * @param arg The string to be parsed. * * @return Valid precision. */ protected static long getPrecision(String arg) { return getLong(arg, "digits", 1, Apfloat.INFINITE - 1); } /** * Parse the radix from an argument. * * @param arg The string to be parsed. * * @return Valid radix. */ protected static int getRadix(String arg) { return getInt(arg, "radix", Character.MIN_RADIX, Character.MAX_RADIX); } private static void dump() { ApfloatContext ctx = ApfloatContext.getContext(); Pi.err.println("builderFactory = " + ctx.getBuilderFactory().getClass().getName()); Pi.err.println("maxMemoryBlockSize = " + ctx.getMaxMemoryBlockSize()); Pi.err.println("cacheL1Size = " + ctx.getCacheL1Size()); Pi.err.println("cacheL2Size = " + ctx.getCacheL2Size()); Pi.err.println("cacheBurst = " + ctx.getCacheBurst()); Pi.err.println("memoryThreshold = " + ctx.getMemoryThreshold()); Pi.err.println("sharedMemoryTreshold = " + ctx.getSharedMemoryTreshold()); Pi.err.println("blockSize = " + ctx.getBlockSize()); Pi.err.println("numberOfProcessors = " + ctx.getNumberOfProcessors()); } /** * Execute an operation and display some additional information. * The return value of the operation is written to {@link #out}. * * @param precision The precision to be used. * @param radix The radix to be used. * @param operation The operation to execute. * * @exception IOException In case writing the output fails. */ public static void run(long precision, int radix, Operation operation) throws IOException, ApfloatRuntimeException { dump(); Pi.err.println("Calculating pi to " + precision + " radix-" + radix + " digits"); long time = System.currentTimeMillis(); Apfloat pi = operation.execute(); time = System.currentTimeMillis() - time; pi.writeTo(Pi.out, true); Pi.out.println(); Pi.err.println("Total elapsed time " + time / 1000.0 + " seconds"); } /** * Set the output stream for the result printout. * * @param out The output stream. */ public static void setOut(PrintWriter out) { Pi.out = out; } /** * Get the output stream for the result printout. * * @return The output stream. */ public static PrintWriter getOut() { return Pi.out; } /** * Set the output stream for status messages printout. * * @param err The output stream. */ public static void setErr(PrintWriter err) { Pi.err = err; } /** * Get the output stream for status messages printout. * * @return The output stream. */ public static PrintWriter getErr() { return Pi.err; } Pi() { } /** * Command-line entry point. * * @param args Command-line parameters. * * @exception IOException In case writing the output fails. */ public static void main(String[] args) throws IOException, ApfloatRuntimeException { if (args.length < 1) { System.err.println("USAGE: Pi digits [method] [radix]"); System.err.println(" method: 0 = Chudnovskys' binsplit"); System.err.println(" 1 = Ramanujan binsplit"); System.err.println(" 2 = Gauss-Legendre"); System.err.println(" 3 = Borweins' quartic"); System.err.println(" radix must be 2...36"); return; } long precision = getPrecision(args[0]); int method = (args.length > 1 ? getInt(args[1], "method", 0, 3) : 0), radix = (args.length > 2 ? getRadix(args[2]) : ApfloatContext.getContext().getDefaultRadix()); Operation operation; switch (method) { case 0: operation = new ChudnovskyPiCalculator(precision, radix); break; case 1: operation = new RamanujanPiCalculator(precision, radix); break; case 2: operation = new GaussLegendrePiCalculator(precision, radix); break; default: operation = new BorweinPiCalculator(precision, radix); } setOut(new PrintWriter(System.out, true)); setErr(new PrintWriter(System.err, true)); run(precision, radix, operation); } /** * Output stream for the result printout. */ protected static PrintWriter out; /** * Output stream for status messages printout. */ protected static PrintWriter err; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/PiAWT.java000066400000000000000000000362401461767713300264430ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.awt.GridBagLayout; import java.awt.GridBagConstraints; import java.awt.Insets; import java.awt.Container; import java.awt.Panel; import java.awt.Label; import java.awt.Choice; import java.awt.Checkbox; import java.awt.CheckboxGroup; import java.awt.TextField; import java.awt.TextArea; import java.awt.Button; import java.util.List; import java.util.ServiceLoader; import java.util.ArrayList; import java.util.Iterator; import java.util.Collections; import java.io.StringWriter; import java.io.PrintWriter; import org.apfloat.Apfloat; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatInterruptedException; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.BuilderFactory; /** * Graphical AWT elements for calculating pi using four different algorithms. * * @version 1.14.0 * @author Mikko Tommila */ public class PiAWT extends Panel { /** * Interface to indicate an error status in the application. */ public static interface StatusIndicator { /** * Show the specified error status. * * @param status The status. */ public void showStatus(String status); } /** * Construct a panel with graphical elements. * * @param statusIndicator Handler for showing error messages in the application. */ public PiAWT(StatusIndicator statusIndicator) { this.statusIndicator = statusIndicator; initGUI(); } // Initialize the container and add the graphical elements to it private void initGUI() { ApfloatContext ctx = ApfloatContext.getContext(); setLayout(new GridBagLayout()); GridBagConstraints constraints = new GridBagConstraints(); constraints.anchor = GridBagConstraints.NORTHWEST; constraints.insets = new Insets(5, 5, 5, 5); constraints.weightx = 1; constraints.weighty = 1; this.precisionLabel = new Label("Precision:"); add(this.precisionLabel, constraints); this.precisionField = new TextField("1000000", 12); add(this.precisionField, constraints); this.radixLabel = new Label("Radix:"); add(this.radixLabel, constraints); this.radixChoice = new Choice(); for (int i = Character.MIN_RADIX; i <= Character.MAX_RADIX; i++) { this.radixChoice.add(String.valueOf(i)); } this.radixChoice.select(ctx.getProperty(ApfloatContext.DEFAULT_RADIX)); constraints.gridwidth = GridBagConstraints.REMAINDER; add(this.radixChoice, constraints); this.methodLabel = new Label("Method:"); constraints.gridwidth = 1; constraints.gridheight = 3; add(this.methodLabel, constraints); Panel panel = new Panel(new GridBagLayout()); GridBagConstraints panelConstraints = new GridBagConstraints(); panelConstraints.gridwidth = GridBagConstraints.REMAINDER; panelConstraints.anchor = GridBagConstraints.NORTHWEST; panelConstraints.weightx = 1; panelConstraints.weighty = 1; this.methods = new CheckboxGroup(); this.chudnovsky = new Checkbox("Chudnovsky", true, this.methods); panel.add(this.chudnovsky, panelConstraints); this.ramanujan = new Checkbox("Ramanujan", false, this.methods); panel.add(this.ramanujan, panelConstraints); this.gaussLegendre = new Checkbox("Gauss-Legendre", false, this.methods); panel.add(this.gaussLegendre, panelConstraints); this.borwein = new Checkbox("Borwein", false, this.methods); panel.add(this.borwein, panelConstraints); add(panel, constraints); this.implementationLabel = new Label("Implementation:"); constraints.gridwidth = 1; constraints.gridheight = 1; add(this.implementationLabel, constraints); this.implementationChoice = new Choice(); this.builderFactories = new ArrayList<>(); String defaultBuilderFactoryClassName = ApfloatContext.getContext().getBuilderFactory().getClass().getName(); Iterator providers = ServiceLoader.load(org.apfloat.spi.BuilderFactory.class).iterator(); if (!providers.hasNext()) { BuilderFactory builderFactory = ApfloatContext.getContext().getBuilderFactory(); providers = Collections.singleton(builderFactory).iterator(); } for (int i = 0; providers.hasNext(); i++) { BuilderFactory builderFactory = providers.next(); String builderFactoryClassName = builderFactory.getClass().getName(); this.builderFactories.add(builderFactory); this.implementationChoice.add(builderFactoryClassName); if (builderFactoryClassName.equals(defaultBuilderFactoryClassName)) { this.implementationChoice.select(i); } } constraints.gridwidth = GridBagConstraints.REMAINDER; add(this.implementationChoice, constraints); constraints.gridwidth = 1; initThreads(this, constraints); this.goButton = new Button("Go!"); constraints.gridwidth = 1; add(this.goButton, constraints); this.abortButton = new Button("Abort!"); this.abortButton.setEnabled(false); constraints.gridwidth = GridBagConstraints.REMAINDER; add(this.abortButton, constraints); this.statusLabel = new Label("Status:"); add(this.statusLabel, constraints); this.statusArea = new TextArea(null, 5, 60, TextArea.SCROLLBARS_VERTICAL_ONLY); this.statusArea.setEditable(false); constraints.fill = GridBagConstraints.HORIZONTAL; add(this.statusArea, constraints); this.resultLabel = new Label("Result:"); constraints.fill = GridBagConstraints.NONE; add(this.resultLabel, constraints); this.resultArea = new TextArea(null, 5, 60, TextArea.SCROLLBARS_VERTICAL_ONLY); this.resultArea.setEditable(false); constraints.fill = GridBagConstraints.HORIZONTAL; add(this.resultArea, constraints); this.goButton.addActionListener((actionEvent) -> { if (isInputValid()) { PiAWT.this.statusArea.setText(null); PiAWT.this.resultArea.setText(null); PiAWT.this.goButton.setEnabled(false); startThread(); } }); this.abortButton.addActionListener((actionEvent) -> { PiAWT.this.abortButton.setEnabled(false); stopThread(); }); } /** * Initialize the "threads" section GUI elements. * Elements should be added for the remainder of the width of the container. * * @param container The container where the elements are to be added. * @param constraints The constraints with which the elements are to be added to the container. */ protected void initThreads(Container container, GridBagConstraints constraints) { constraints.gridwidth = GridBagConstraints.REMAINDER; container.add(new Label(), constraints); } /** * Validates the input fields. * * @return true if all input fields contain valid values, otherwise false. */ protected boolean isInputValid() { String precisionString = this.precisionField.getText(); try { long precision = Long.parseLong(precisionString); if (precision <= 0) { throw new NumberFormatException(); } showStatus(null); return true; } catch (NumberFormatException nfe) { showStatus("Invalid precision: " + precisionString); this.precisionField.requestFocus(); return false; } } /** * Show the specified error status. * * @param status The status. */ protected void showStatus(String status) { this.statusIndicator.showStatus(status); } // Prints output to a text area private static class FlushStringWriter extends StringWriter { public FlushStringWriter(TextArea dst) { this.dst = dst; this.length = 0; this.position = 0; this.lastLinefeedPosition = 0; } @Override public void flush() { super.flush(); StringBuffer buffer = getBuffer(); String text = buffer.toString(); String lineSeparator = System.lineSeparator(); boolean endsWithLineSeparator = text.endsWith(lineSeparator), endsWithCarriageReturn = text.endsWith("\r"); if (endsWithLineSeparator) { // Convert trailing line separator to \n to increase compatibility between platforms text = text.substring(0, text.length() - lineSeparator.length()) + '\n'; } else if (endsWithCarriageReturn) { // Strip trailing carriage return text = text.substring(0, text.length() - 1); } this.dst.replaceRange(text, this.position, this.length); this.position += text.length(); this.length = this.position; if (endsWithLineSeparator) { this.lastLinefeedPosition = this.position; } else if (endsWithCarriageReturn) { this.position = this.lastLinefeedPosition; } buffer.setLength(0); } private TextArea dst; private int length, position, lastLinefeedPosition; } /** * Get the calculation operation to execute. * * @param precision The precision to be used. * @param radix The radix to be used. * * @return The calculation operation to execute. */ protected Operation getOperation(long precision, int radix) throws ApfloatRuntimeException { if (this.chudnovsky.getState()) { return new Pi.ChudnovskyPiCalculator(precision, radix); } else if (this.ramanujan.getState()) { return new Pi.RamanujanPiCalculator(precision, radix); } else if (this.gaussLegendre.getState()) { return new Pi.GaussLegendrePiCalculator(precision, radix); } else { return new Pi.BorweinPiCalculator(precision, radix); } } private void startThread() { // Writer for writing standard output to the result area Pi.setOut(new PrintWriter(new FlushStringWriter(this.resultArea), true)); // Writer for writing standard error output to the status area Pi.setErr(new PrintWriter(new FlushStringWriter(this.statusArea), true)); // Set the selected builder factory ApfloatContext ctx = ApfloatContext.getContext(); BuilderFactory builderFactory = this.builderFactories.get(this.implementationChoice.getSelectedIndex()); ctx.setBuilderFactory(builderFactory); // Thread for calculating pi and showing the result this.calculatorThread = new Thread() { @Override public void run() { long precision = Long.parseLong(PiAWT.this.precisionField.getText()); int radix = Integer.parseInt(PiAWT.this.radixChoice.getSelectedItem()); Operation operation = getOperation(precision, radix); try { Pi.run(precision, radix, operation); } catch (ApfloatInterruptedException aie) { aborted(); } catch (AssertionError ae) { crashed(ae); } catch (Exception e) { crashed(e); } finally { end(); } } }; this.calculatorThread.start(); this.abortButton.setEnabled(true); } private void stopThread() { this.calculatorThread.interrupt(); } private void aborted() { Pi.getErr().println("Aborted"); } private void crashed(Throwable cause) { Pi.getErr().println("Crashed with " + cause); cause.printStackTrace(); } private void end() { this.abortButton.setEnabled(false); this.goButton.setEnabled(true); ApfloatContext ctx = ApfloatContext.getContext(); BuilderFactory builderFactory = ctx.getBuilderFactory(); builderFactory.gc(); // Garbage collection may not have run perfectly by this point } private static final long serialVersionUID = 1L; private StatusIndicator statusIndicator; private Label precisionLabel; private TextField precisionField; private Label radixLabel; private Choice radixChoice; private Label methodLabel; private CheckboxGroup methods; private Checkbox chudnovsky; private Checkbox ramanujan; private Checkbox gaussLegendre; private Checkbox borwein; private Label implementationLabel; private Choice implementationChoice; private Button goButton; private Button abortButton; private Label statusLabel; private TextArea statusArea; private Label resultLabel; private TextArea resultArea; private List builderFactories; private Thread calculatorThread; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/PiApplet.java000066400000000000000000000110371461767713300272320ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.applet.Applet; import java.awt.Container; import java.io.File; import java.security.AccessControlException; import org.apfloat.ApfloatContext; import org.apfloat.spi.FilenameGenerator; /** * Applet for calculating pi using four different algorithms. * * @version 1.10.0 * @author Mikko Tommila */ public class PiApplet extends Applet implements PiAWT.StatusIndicator { /** * Default constructor. */ public PiApplet() { } /** * Initialize this applet. */ @Override public void init() { add(getContents()); // Recreate the executor service in case the old thread group was destroyed by reloading the applet ApfloatContext ctx = ApfloatContext.getContext(); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); try { // The applet may not be able to write files to the current directory, but probably can write to the temp directory String path = System.getProperty("java.io.tmpdir"); if (path != null && !path.endsWith(File.separator)) { path = path + File.separator; } FilenameGenerator filenameGenerator = new FilenameGenerator(path, null, null); ctx.setFilenameGenerator(filenameGenerator); } catch (AccessControlException ace) { // Ignore - reading the system property may not be allowed in unsigned applets } } /** * Get the graphical elements of this applet. * * @return The graphical elements of this applet. */ protected Container getContents() { return new PiAWT(this); } /** * Called when this applet is destroyed. */ @Override public void destroy() { removeAll(); } /** * Get information about this applet. * * @return Information about this applet. */ @Override public String getAppletInfo() { Object builderFactory = ApfloatContext.getContext().getBuilderFactory(); Package specificationPackage = ApfloatContext.class.getPackage(), implementationPackage = builderFactory.getClass().getPackage(); String lineSeparator = System.lineSeparator(); return "Pi calculation applet" + lineSeparator + "Written by Mikko Tommila 2002 - 2023" + lineSeparator + "Specification-Title: " + specificationPackage.getSpecificationTitle() + lineSeparator + "Specification-Version: " + specificationPackage.getSpecificationVersion() + lineSeparator + "Specification-Vendor: " + specificationPackage.getSpecificationVendor() + lineSeparator + "Implementation-Title: " + implementationPackage.getImplementationTitle() + lineSeparator + "Implementation-Version: " + implementationPackage.getImplementationVersion() + lineSeparator + "Implementation-Vendor: " + implementationPackage.getImplementationVendor() + lineSeparator + "Java version: " + System.getProperty("java.version") + lineSeparator + "Java Virtual Machine: " + System.getProperty("java.vm.name"); } private static final long serialVersionUID = 1L; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/PiDistributed.java000066400000000000000000001017471461767713300302770ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.io.PrintWriter; import java.io.IOException; import java.util.Arrays; import java.util.List; import java.util.LinkedList; import java.util.ArrayList; import java.util.SortedSet; import java.util.TreeSet; import java.util.Enumeration; import java.util.ResourceBundle; import java.util.MissingResourceException; import org.apfloat.Apfloat; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatMath; import org.apfloat.ApfloatRuntimeException; /** * Calculates pi using a cluster of servers. * The servers should be running {@link OperationServer}. * * The names and ports of the cluster nodes are read from the file * cluster.properties, or a ResourceBundle * by the name "cluster". The format of the property file is as * follows: * *

 * server1=hostname.company.com:1234
 * server2=hostname2.company.com:2345
 * server3=hostname3.company.com:3456
 * weight1=100
 * weight2=110
 * weight3=50
 * 
* * The server addresses are specified as hostname:port. Weights can * (but don't have to) be assigned to nodes to indicate the relative * performance of each node, to allow distributing a suitable amount * of work for each node. For example, weight2 is the * relative performance of server2 etc. The weights must * be integers in the range 1...1000.

* * Guidelines for configuring the servers: * *

*

* * Similarly as with {@link PiParallel}, if some nodes have multiple * CPUs, to get any performance gain from running many * threads in parallel, the JVM must be executing native threads. * If the JVM is running in green threads mode, there is no * advantage of having multiple threads, as the JVM will in fact * execute just one thread and divide its time to multiple * simulated threads. * * @version 1.9.0 * @author Mikko Tommila */ public class PiDistributed extends PiParallel { /** * Distributed version of the binary splitting algorithm. * Uses multiple computers to calculate pi in parallel. */ protected static class DistributedBinarySplittingPiCalculator extends ParallelBinarySplittingPiCalculator { /** * Construct a distributed pi calculator with the specified precision and radix. * * @param series The binary splitting series to be used. */ public DistributedBinarySplittingPiCalculator(BinarySplittingSeries series) { super(series); } /** * Entry point for the distributed binary splitting algorithm. * * @param n1 Start term. * @param n2 End term. * @param T Algorithm parameter. * @param Q Algorithm parameter. * @param P Algorithm parameter. * @param F Pointer to inverse square root parameter. * @param nodes The operation executors to be used for the calculation. */ public void r(long n1, long n2, ApfloatHolder T, ApfloatHolder Q, ApfloatHolder P, ApfloatHolder F, Node[] nodes) throws ApfloatRuntimeException { if (nodes.length == 1) { // End of splitting work between nodes // Calculate remaining terms on the node // Splitting of work continues on the server node using multiple threads if (DEBUG) Pi.err.println("PiDistributed.r(" + n1 + ", " + n2 + ") transferring to server side node " + nodes[0]); ApfloatHolder[] TQP = nodes[0].execute(() -> { // Continue splitting by threads on server side r(n1, n2, T, Q, P, null); return new ApfloatHolder[] { T, Q, P }; }); T.setApfloat(TQP[0].getApfloat()); Q.setApfloat(TQP[1].getApfloat()); if (P != null) P.setApfloat(TQP[2].getApfloat()); } else { // Multiple nodes available; split work in ratio of node weights and execute in parallel // This split is done on the client side Object[] objs = splitNodes(nodes); Node[] nodes1 = (Node[]) objs[0], nodes2 = (Node[]) objs[2]; long weight1 = (Long) objs[1], weight2 = (Long) objs[3]; long nMiddle = n1 + (n2 - n1) * weight1 / (weight1 + weight2); ApfloatHolder LT = new ApfloatHolder(), LQ = new ApfloatHolder(), LP = new ApfloatHolder(); if (DEBUG) Pi.err.println("PiDistributed.r(" + n1 + ", " + n2 + ") splitting " + formatArray(nodes) + " to r(" + n1 + ", " + nMiddle + ") " + formatArray(nodes1) + ", r(" + nMiddle + ", " + n2 + ") " + formatArray(nodes2)); BackgroundOperation operation; // Call recursively this r() method to further split the term calculation operation = new BackgroundOperation<>(() -> { r(n1, nMiddle, LT, LQ, LP, null, nodes1); return null; }); r(nMiddle, n2, T, Q, P, null, nodes2); operation.getResult(); // Waits for operation to complete // Calculate the combining multiplies using available nodes in parallel // Up to 4 calculations will be executed in parallel // If more than 4 nodes (threads) are available, each calculation can use multiple nodes (threads) assert (P == null || F == null); int numberNeeded = (P != null || F != null ? 1 : 0) + 3; nodes = recombineNodes(nodes, numberNeeded); Operation sqrtOperation = () -> ApfloatMath.inverseRoot(F.getApfloat(), 2), T1operation = () -> Q.getApfloat().multiply(LT.getApfloat()), T2operation = () -> LP.getApfloat().multiply(T.getApfloat()), Toperation = () -> T1operation.execute().add(T2operation.execute()), Qoperation = () -> LQ.getApfloat().multiply(Q.getApfloat()), Poperation = () -> LP.getApfloat().multiply(P.getApfloat()); Operation QPoperation = () -> new Apfloat[] { Qoperation.execute(), P == null ? null : Poperation.execute() }; int availableNodes = nodes.length; BackgroundOperation sqrtBackgroundOperation = null, operation1, operation2, operation3 = null; if (F != null && availableNodes > 1) { if (DEBUG) Pi.err.println("PiDistributed.r(" + n1 + ", " + n2 + ") calculating isqrt on node " + nodes[availableNodes - 1]); sqrtBackgroundOperation = nodes[availableNodes - 1].executeBackground(sqrtOperation); availableNodes--; } Apfloat t = null, q = null, p = null; switch (availableNodes) { case 1: { t = nodes[0].execute(Toperation); q = nodes[0].execute(Qoperation); if (P != null) p = nodes[0].execute(Poperation); break; } case 2: { operation1 = nodes[1].executeBackground(T1operation); Apfloat tmp1 = nodes[0].execute(T2operation), tmp2 = operation1.getResult(); operation1 = nodes[1].executeBackground(Qoperation); t = executeAdd(nodes[0], tmp1, tmp2); if (P != null) p = nodes[0].execute(Poperation); q = operation1.getResult(); break; } case 3: { BackgroundOperation operation1a; operation1a = nodes[2].executeBackground(QPoperation); operation2 = nodes[1].executeBackground(T1operation); Apfloat tmp1 = nodes[0].execute(T2operation), tmp2 = operation2.getResult(); t = executeAdd(nodes[1], tmp1, tmp2); Apfloat[] QP = operation1a.getResult(); q = QP[0]; if (P != null) p = QP[1]; break; } default: { operation1 = nodes[availableNodes - 1].executeBackground(T1operation); operation2 = nodes[availableNodes - 3].executeBackground(Qoperation); if (P != null) operation3 = nodes[availableNodes - 4].executeBackground(Poperation); Apfloat tmp1 = nodes[availableNodes - 2].execute(T2operation), tmp2 = operation1.getResult(); t = executeAdd(nodes[availableNodes - 1], tmp1, tmp2); q = operation2.getResult(); if (P != null) p = operation3.getResult(); break; } } T.setApfloat(t); Q.setApfloat(q); if (P != null) P.setApfloat(p); if (sqrtBackgroundOperation != null) { F.setApfloat(sqrtBackgroundOperation.getResult()); } } } /** * Get the available set of operation executor nodes. * This implementation returns {@link RemoteOperationExecutor}s, * which execute operations on the cluster's nodes. * * @return The nodes of the cluster. */ public Node[] getNodes() { ResourceBundle resourceBundle = null; try { resourceBundle = ResourceBundle.getBundle("cluster"); } catch (MissingResourceException mre) { System.err.println("ResourceBundle \"cluster\" not found"); System.exit(1); } Node[] nodes = null; List list = new ArrayList<>(); long totalWeight = 0; int weightedNodes = 0; // Loop through all properties in the file Enumeration keys = resourceBundle.getKeys(); while (keys.hasMoreElements()) { String key = keys.nextElement(); // Only process the server properties if (key.startsWith("server")) { int weight = -1; // -1 means unspecified here // Check if a weight is specified for this server try { String weightString = resourceBundle.getString("weight" + key.substring(6)); try { weight = Integer.parseInt(weightString); if (weight < MIN_WEIGHT || weight > MAX_WEIGHT) { throw new NumberFormatException(weightString); } weightedNodes++; } catch (NumberFormatException nfe) { System.err.println("Invalid weight: " + nfe.getMessage()); System.exit(1); } totalWeight += weight; } catch (MissingResourceException mre) { // Weight not specified, OK } // Parse hostname and port String server = resourceBundle.getString(key); int index = server.indexOf(':'); if (index < 0) { System.err.println("No port specified for server: " + server); System.exit(1); } String host = server.substring(0, index), portString = server.substring(index + 1); int port = 0; try { port = Integer.parseInt(portString); } catch (NumberFormatException nfe) { System.err.println("Invalid port for host " + host + ": " + portString); System.exit(1); } list.add(new Node(host, port, weight)); } } if (list.size() == 0) { System.err.println("No nodes for cluster specified"); System.exit(1); } nodes = list.toArray(new Node[list.size()]); // If no weights were specified at all, all nodes have same weight int averageWeight = (weightedNodes == 0 ? 1 : (int) (totalWeight / weightedNodes)); // Loop through all nodes and set average weight for all nodes that don't have a weight specified for (Node node : nodes) { if (node.getWeight() == -1) { node.setWeight(averageWeight); } } // Sort nodes in weight order (smallest first) Arrays.sort(nodes); // Get the available number of threads for each node for (Node node : nodes) { int numberOfProcessors = node.execute(() -> ApfloatContext.getGlobalContext().getNumberOfProcessors()); node.setNumberOfProcessors(numberOfProcessors); } if (DEBUG) Pi.err.println("PiDistributed.getNodes " + formatArray(nodes)); return nodes; } /** * Attempt to combine or split nodes to form the needed number * of nodes. The returned number of nodes is something between * the number of nodes input and the number of nodes requested. * The requested number of nodes can be less than or greater than * the number of input nodes. * * @param nodes The nodes to recombine. * @param numberNeeded The requested number of nodes. * * @return The set of recombined nodes. */ public Node[] recombineNodes(Node[] nodes, int numberNeeded) { if (numberNeeded <= nodes.length) { // Method is running on client side // RemoteOperationExecutors can't be combined since they don't exist on the same machine like threads if (DEBUG) Pi.err.println("PiDistributed.recombineNodes unable to recombine nodes " + formatArray(nodes) + " (" + numberNeeded + " <= " + nodes.length + ")"); return nodes; } else { // Split RemoteOperationExecutors to executors that don't use all threads available on the server SortedSet allNodes = new TreeSet<>(), splittableNodes = new TreeSet<>(); for (Node node : nodes) { (node.getNumberOfProcessors() > 1 ? splittableNodes : allNodes).add(node); } // Continue splitting heaviest node until no more splits can be made or we have the needed number of nodes while (splittableNodes.size() > 0 && allNodes.size() + splittableNodes.size() < numberNeeded) { // Get heaviest splittable node Node node = splittableNodes.last(); int numberOfProcessors = node.getNumberOfProcessors(), numberOfProcessors1 = numberOfProcessors / 2, numberOfProcessors2 = (numberOfProcessors + 1) / 2; Node node1 = new Node(node.getHost(), node.getPort(), node.getWeight() * numberOfProcessors1 / numberOfProcessors, numberOfProcessors1), node2 = new Node(node.getHost(), node.getPort(), node.getWeight() * numberOfProcessors2 / numberOfProcessors, numberOfProcessors2); splittableNodes.remove(node); (node1.getNumberOfProcessors() > 1 ? splittableNodes : allNodes).add(node1); (node2.getNumberOfProcessors() > 1 ? splittableNodes : allNodes).add(node2); } allNodes.addAll(splittableNodes); Node[] newNodes = allNodes.toArray(new Node[allNodes.size()]); if (DEBUG) Pi.err.println("PiDistributed.recombineNodes recombined " + formatArray(nodes) + " to " + formatArray(newNodes) + " (requested " + numberNeeded + ")"); return newNodes; } } // Split nodes to two sets that have roughly the same total weights private Object[] splitNodes(Node[] nodes) { List list1 = new LinkedList<>(), list2 = new LinkedList<>(); long weight1 = 0, weight2 = 0; // Start from heaviest node to make maximally equal split for (int i = nodes.length; --i >= 0;) { if (weight1 < weight2) { list1.add(0, nodes[i]); weight1 += nodes[i].getWeight(); } else { list2.add(0, nodes[i]); weight2 += nodes[i].getWeight(); } } return new Object[] { list1.toArray(new Node[list1.size()]), weight1, list2.toArray(new Node[list2.size()]), weight2 }; } private Apfloat executeAdd(Node node, Apfloat x, Apfloat y) { return node.execute(() -> x.add(y)); } private static final long serialVersionUID = 1L; } /** * Class for calculating pi using the distributed Chudnovskys' binary splitting algorithm. */ public static class DistributedChudnovskyPiCalculator extends ParallelChudnovskyPiCalculator { /** * Construct a pi calculator with the specified precision and radix. * * @param precision The target precision. * @param radix The radix to be used. */ public DistributedChudnovskyPiCalculator(long precision, int radix) throws ApfloatRuntimeException { this(new DistributedBinarySplittingPiCalculator(new ChudnovskyBinarySplittingSeries(precision, radix)), precision, radix); } private DistributedChudnovskyPiCalculator(DistributedBinarySplittingPiCalculator calculator, long precision, int radix) throws ApfloatRuntimeException { super(calculator, precision, radix); this.calculator = calculator; this.precision = precision; this.radix = radix; } @Override public Apfloat execute() { Pi.err.println("Using the Chudnovsky brothers' binary splitting algorithm"); Node[] nodes = this.calculator.getNodes(); if (nodes.length > 1) { Pi.err.println("Using up to " + nodes.length + " parallel operations for calculation"); } Apfloat f = new Apfloat(1823176476672000L, this.precision, this.radix); ApfloatHolder T = new ApfloatHolder(), Q = new ApfloatHolder(), F = new ApfloatHolder(f); // Perform the calculation of T, Q and P to requested precision only, to improve performance long terms = (long) ((double) this.precision * Math.log((double) this.radix) / 32.65445004177); long time = System.currentTimeMillis(); this.calculator.r(0, terms + 1, T, Q, null, F, nodes); time = System.currentTimeMillis() - time; Pi.err.println("Series terms calculation complete, elapsed time " + time / 1000.0 + " seconds"); Pi.err.printf("Final value "); nodes = this.calculator.recombineNodes(nodes, 1); time = System.currentTimeMillis(); Apfloat pi = nodes[nodes.length - 1].execute(() -> { Apfloat t = T.getApfloat(), q = Q.getApfloat(), factor = F.getApfloat(); if (factor == f) { factor = ApfloatMath.inverseRoot(f, 2); } return ApfloatMath.inverseRoot(factor.multiply(t), 1).multiply(q); }); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); return pi; } private static final long serialVersionUID = 1L; private DistributedBinarySplittingPiCalculator calculator; private long precision; private int radix; } /** * Class for calculating pi using the distributed Ramanujan's binary splitting algorithm. */ public static class DistributedRamanujanPiCalculator extends ParallelRamanujanPiCalculator { /** * Construct a pi calculator with the specified precision and radix. * * @param precision The target precision. * @param radix The radix to be used. */ public DistributedRamanujanPiCalculator(long precision, int radix) throws ApfloatRuntimeException { this(new DistributedBinarySplittingPiCalculator(new RamanujanBinarySplittingSeries(precision, radix)), precision, radix); } private DistributedRamanujanPiCalculator(DistributedBinarySplittingPiCalculator calculator, long precision, int radix) throws ApfloatRuntimeException { super(calculator, precision, radix); this.calculator = calculator; this.precision = precision; this.radix = radix; } @Override public Apfloat execute() { Pi.err.println("Using the Ramanujan binary splitting algorithm"); Node[] nodes = this.calculator.getNodes(); if (nodes.length > 1) { Pi.err.println("Using up to " + nodes.length + " parallel operations for calculation"); } Apfloat f = new Apfloat(8, this.precision, this.radix); ApfloatHolder T = new ApfloatHolder(), Q = new ApfloatHolder(), F = new ApfloatHolder(f); // Perform the calculation of T, Q and P to requested precision only, to improve performance long terms = (long) ((double) this.precision * Math.log((double) this.radix) / 18.38047940053836); long time = System.currentTimeMillis(); this.calculator.r(0, terms + 1, T, Q, null, F, nodes); time = System.currentTimeMillis() - time; Pi.err.println("Series terms calculation complete, elapsed time " + time / 1000.0 + " seconds"); Pi.err.printf("Final value "); nodes = this.calculator.recombineNodes(nodes, 1); time = System.currentTimeMillis(); Apfloat pi = nodes[nodes.length - 1].execute(() -> { Apfloat t = T.getApfloat(), q = Q.getApfloat(), factor = F.getApfloat(); if (factor == f) { factor = ApfloatMath.inverseRoot(f, 2); } return ApfloatMath.inverseRoot(t, 1).multiply(factor).multiply(new Apfloat(9801, Apfloat.INFINITE, DistributedRamanujanPiCalculator.this.radix)).multiply(q); }); time = System.currentTimeMillis() - time; Pi.err.println("took " + time / 1000.0 + " seconds"); return pi; } private static final long serialVersionUID = 1L; private DistributedBinarySplittingPiCalculator calculator; private long precision; private int radix; } /** * RemoteOperationExecutor that implements the weight property. */ protected static class Node extends RemoteOperationExecutor implements Comparable { /** * Construct a Node with the specified parameters and one processor. * * @param host The remote host. * @param port The remote port. * @param weight The weight. */ public Node(String host, int port, int weight) { this(host, port, weight, 1); } /** * Construct a Node with the specified parameters. * * @param host The remote host. * @param port The remote port. * @param weight The weight. * @param numberOfProcessors The number of processors. */ public Node(String host, int port, int weight, int numberOfProcessors) { super(host, port); this.weight = weight; this.numberOfProcessors = numberOfProcessors; } @Override public T execute(Operation operation) { return super.execute(new ThreadLimitedOperation<>(operation, this.numberOfProcessors)); } @Override public BackgroundOperation executeBackground(Operation operation) { return super.executeBackground(new ThreadLimitedOperation<>(operation, this.numberOfProcessors)); } /** * Set the weight. * * @param weight The weight. */ public void setWeight(int weight) { this.weight = weight; } @Override public int getWeight() { return this.weight; } /** * Set the number of processors. * * @param numberOfProcessors The number of processors. */ public void setNumberOfProcessors(int numberOfProcessors) { this.numberOfProcessors = numberOfProcessors; } /** * Get the number of processors. * * @return The number of processors. */ public int getNumberOfProcessors() { return this.numberOfProcessors; } /** * Compare this Node to another Node. * * @param that The other node to compare to. * * @return A number less than zero if this Node should be ordered before the other node, or gerater than zero for the reverse order. Should not return zero. */ @Override public int compareTo(Node that) { // Must differentiate objects with same weight but that are not the same int weightDifference = this.weight - that.weight; return (weightDifference != 0 ? weightDifference : this.hashCode() - that.hashCode()); // This is not rock solid... } /** * Convert to String. * * @return The string representation. */ @Override public String toString() { return this.weight + "/" + this.numberOfProcessors; } private int weight; private int numberOfProcessors; } PiDistributed() { } /** * Command-line entry point. * * @param args Command-line parameters. * * @exception IOException In case writing the output fails. */ public static void main(String[] args) throws IOException, ApfloatRuntimeException { if (args.length < 1) { System.err.println("USAGE: PiDistributed digits [method] [radix]"); System.err.println(" radix must be 2...36"); return; } long precision = getPrecision(args[0]); int method = (args.length > 1 ? getInt(args[1], "method", 0, 1) : 0), radix = (args.length > 2 ? getRadix(args[2]) : ApfloatContext.getContext().getDefaultRadix()); Operation operation; switch (method) { case 0: operation = new DistributedChudnovskyPiCalculator(precision, radix); break; default: operation = new DistributedRamanujanPiCalculator(precision, radix); } setOut(new PrintWriter(System.out, true)); setErr(new PrintWriter(System.err, true)); run(precision, radix, operation); } private static String formatArray(Object[] array) { StringBuilder buffer = new StringBuilder(); buffer.append("{ "); for (int i = 0; i < array.length; i++) { buffer.append(i == 0 ? "" : ", "); buffer.append(array[i]); } buffer.append(" }"); return buffer.toString(); } private static final int MIN_WEIGHT = 1, MAX_WEIGHT = 1000; private static final boolean DEBUG = false; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/PiGUI.java000066400000000000000000000054651461767713300264410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.awt.Container; import java.awt.Frame; import java.awt.BorderLayout; import java.awt.Label; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; /** * AWT client application for calculating pi using four different algorithms. * * @version 1.9.0 * @author Mikko Tommila */ public class PiGUI extends Frame implements PiAWT.StatusIndicator { /** * Default constructor. */ protected PiGUI() { super("Pi calculator"); setSize(720, 540); addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent windowEvent) { setVisible(false); dispose(); System.exit(0); } }); setLayout(new BorderLayout()); this.statusLabel = new Label(); add(getContents(), BorderLayout.NORTH); add(this.statusLabel, BorderLayout.SOUTH); setVisible(true); } @Override public void showStatus(String status) { this.statusLabel.setText(status); } /** * Get the graphical elements of this frame. * * @return The graphical elements of this frame. */ protected Container getContents() { return new PiAWT(this); } /** * Command-line entry point. * * @param args Command-line parameters. */ public static void main(String[] args) { new PiGUI(); } private static final long serialVersionUID = 1L; private Label statusLabel; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/PiParallel.java000066400000000000000000000337401461767713300275460ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.io.PrintWriter; import java.io.IOException; import org.apfloat.Apfloat; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatInterruptedException; import org.apfloat.ApfloatRuntimeException; /** * Calculates pi using multiple threads in parallel.

* * Note that to get any performance gain from running many * threads in parallel, the JVM must be executing native threads. * If the JVM is running in green threads mode, there is no * advantage of having multiple threads, as the JVM will in fact * execute just one thread and divide its time to multiple * simulated threads. * * @version 1.14.0 * @author Mikko Tommila */ public class PiParallel extends Pi { /** * Parallel version of the binary splitting algorithm. * Uses multiple threads to calculate pi in parallel. */ protected static class ParallelBinarySplittingPiCalculator extends BinarySplittingPiCalculator { /** * Construct a parallel pi calculator with the specified precision and radix. * * @param series The binary splitting series to be used. */ public ParallelBinarySplittingPiCalculator(BinarySplittingSeries series) throws ApfloatRuntimeException { super(series); } @Override public void r(long n1, long n2, ApfloatHolder T, ApfloatHolder Q, ApfloatHolder P, BinarySplittingProgressIndicator progressIndicator) throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); if (n1 == n2) { // Pathological case where available threads > terms needed T.setApfloat(Apfloat.ZERO); Q.setApfloat(Apfloat.ONE); if (P != null) P.setApfloat(Apfloat.ONE); } else if (numberOfProcessors == 1) { // End of splitting work between threads // calculate remaining terms on the current thread super.r(n1, n2, T, Q, P, progressIndicator); } else { // Multiple threads available ApfloatHolder LT = new ApfloatHolder(), LQ = new ApfloatHolder(), LP = new ApfloatHolder(); if (split(n1, n2, numberOfProcessors)) { // Split work in ratio of number of threads and execute in parallel int numberOfProcessors1 = numberOfProcessors / 2, numberOfProcessors2 = numberOfProcessors - numberOfProcessors1; long nMiddle = n1 + (n2 - n1) * numberOfProcessors1 / numberOfProcessors; if (DEBUG) Pi.err.println("PiParallel.r(" + n1 + ", " + n2 + ") splitting " + numberOfProcessors + " threads to r(" + n1 + ", " + nMiddle + ") " + numberOfProcessors1 + " threads, r(" + nMiddle + ", " + n2 + ") " + numberOfProcessors2 + " threads"); // Call recursively this r() method to further split the term calculation Operation operation1 = () -> { r(n1, nMiddle, LT, LQ, LP, progressIndicator); return null; }; Operation operation2 = () -> { r(nMiddle, n2, T, Q, P, progressIndicator); return null; }; BackgroundOperation backgroundOperation = new BackgroundOperation<>(new ThreadLimitedOperation<>(operation1, numberOfProcessors1)); Operation directOperation = () -> { try { operation2.execute(); } catch (ApfloatInterruptedException aie) { backgroundOperation.cancel(); throw aie; } return backgroundOperation.getResult(); // Waits for the background operation to complete, must be run within the thread-limited context }; new ThreadLimitedOperation<>(directOperation, numberOfProcessors2).execute(); } else { // Do not split at this point if (DEBUG) Pi.err.println("PiParallel.r(" + n1 + ", " + n2 + ") not splitting " + numberOfProcessors + " threads"); long nMiddle = (n1 + n2) / 2; r(n1, nMiddle, LT, LQ, LP, progressIndicator); r(nMiddle, n2, T, Q, P, progressIndicator); } // Combine recursed results whether split in parallel or not, using all threads available here T.setApfloat(Q.getApfloat().multiply(LT.getApfloat()).add(LP.getApfloat().multiply(T.getApfloat()))); Q.setApfloat(LQ.getApfloat().multiply(Q.getApfloat())); if (P != null) P.setApfloat(LP.getApfloat().multiply(P.getApfloat())); if (progressIndicator != null) { progressIndicator.progress(n1, n2); } } } private static boolean split(long n1, long n2, int numberOfProcessors) { long termsPerThread = (n2 - n1) / numberOfProcessors; if (DEBUG) Pi.err.println("PiParallel.r(" + n1 + ", " + n2 + ") terms per thread " + termsPerThread); ApfloatContext ctx = ApfloatContext.getContext(); long threshold = ctx.getSharedMemoryTreshold() / 32; // Heuristically chosen value return termsPerThread < threshold; } private static final long serialVersionUID = 1L; } /** * Class for calculating pi using the parallel Chudnovskys' binary splitting algorithm. */ public static class ParallelChudnovskyPiCalculator extends ChudnovskyPiCalculator { /** * Construct a pi calculator with the specified precision and radix. * * @param precision The target precision. * @param radix The radix to be used. */ public ParallelChudnovskyPiCalculator(long precision, int radix) throws ApfloatRuntimeException { this(new ParallelBinarySplittingPiCalculator(new ChudnovskyBinarySplittingSeries(precision, radix)), precision, radix); } /** * Construct a pi calculator with the specified binary splitting algorithm. * * @param calculator The binary splitting algorithm to be used. * @param precision The target precision. * @param radix The radix to be used. */ protected ParallelChudnovskyPiCalculator(BinarySplittingPiCalculator calculator, long precision, int radix) throws ApfloatRuntimeException { super(calculator, precision, radix); } @Override public Apfloat execute() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); if (numberOfProcessors > 1) { Pi.err.println("Using up to " + numberOfProcessors + " parallel operations for calculation"); } return super.execute(); } private static final long serialVersionUID = 1L; } /** * Class for calculating pi using the parallel Ramanujan's binary splitting algorithm. */ public static class ParallelRamanujanPiCalculator extends RamanujanPiCalculator { /** * Construct a pi calculator with the specified precision and radix. * * @param precision The target precision. * @param radix The radix to be used. */ public ParallelRamanujanPiCalculator(long precision, int radix) throws ApfloatRuntimeException { this(new ParallelBinarySplittingPiCalculator(new RamanujanBinarySplittingSeries(precision, radix)), precision, radix); } /** * Construct a pi calculator with the specified binary splitting algorithm. * * @param calculator The binary splitting algorithm to be used. * @param precision The target precision. * @param radix The radix to be used. */ protected ParallelRamanujanPiCalculator(BinarySplittingPiCalculator calculator, long precision, int radix) throws ApfloatRuntimeException { super(calculator, precision, radix); } @Override public Apfloat execute() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); if (numberOfProcessors > 1) { Pi.err.println("Using up to " + numberOfProcessors + " parallel operations for calculation"); } return super.execute(); } private static final long serialVersionUID = 1L; } /** * Class to execute operations while setting {@link ApfloatContext#setNumberOfProcessors(int)} * to some value. */ protected static class ThreadLimitedOperation implements Operation { /** * Wrap an existing operation to a thread limited context. * * @param operation The operation whose execution will have a limited number of threads available. * @param numberOfProcessors The maximum number of threads that can be used in the execution. */ public ThreadLimitedOperation(Operation operation, int numberOfProcessors) { this.operation = operation; this.numberOfProcessors = numberOfProcessors; } /** * Execute the operation. * * @return Result of the operation. */ @Override public T execute() { ApfloatContext threadCtx = ApfloatContext.getThreadContext(); ApfloatContext ctx = (ApfloatContext) ApfloatContext.getContext().clone(); ctx.setNumberOfProcessors(this.numberOfProcessors); ApfloatContext.setThreadContext(ctx); T result = this.operation.execute(); if (threadCtx != null) { ApfloatContext.setThreadContext(threadCtx); } else { ApfloatContext.removeThreadContext(); } return result; } private static final long serialVersionUID = 1L; private Operation operation; private int numberOfProcessors; } PiParallel() { } /** * Command-line entry point. * * @param args Command-line parameters. * * @exception IOException In case writing the output fails. */ public static void main(String[] args) throws IOException, ApfloatRuntimeException { if (args.length < 1) { System.err.println("USAGE: PiParallel digits [method] [threads] [radix]"); System.err.println(" radix must be 2...36"); return; } long precision = getPrecision(args[0]); int method = (args.length > 1 ? getInt(args[1], "method", 0, 1) : 0), numberOfProcessors = (args.length > 2 ? getInt(args[2], "threads", 1, Integer.MAX_VALUE) : ApfloatContext.getContext().getNumberOfProcessors()), radix = (args.length > 3 ? getRadix(args[3]) : ApfloatContext.getContext().getDefaultRadix()); // Also set the executor service to use the corresponding number of threads ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(numberOfProcessors); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); Operation operation; switch (method) { case 0: operation = new ParallelChudnovskyPiCalculator(precision, radix); break; default: operation = new ParallelRamanujanPiCalculator(precision, radix); } setOut(new PrintWriter(System.out, true)); setErr(new PrintWriter(System.err, true)); run(precision, radix, operation); } private static final boolean DEBUG = false; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/PiParallelAWT.java000066400000000000000000000101011461767713300301040ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.awt.Container; import java.awt.GridBagConstraints; import java.awt.Label; import java.awt.TextField; import org.apfloat.Apfloat; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; /** * Graphical AWT elements for calculating pi using multiple threads in parallel. * * @version 1.9.0 * @author Mikko Tommila */ public class PiParallelAWT extends PiAWT { /** * Construct a panel with graphical elements. * * @param statusIndicator Handler for showing error messages in the application. */ public PiParallelAWT(StatusIndicator statusIndicator) { super(statusIndicator); } @Override protected void initThreads(Container container, GridBagConstraints constraints) { this.threadsLabel = new Label("Threads:"); container.add(this.threadsLabel, constraints); this.threadsField = new TextField(ApfloatContext.getContext().getProperty(ApfloatContext.NUMBER_OF_PROCESSORS), 5); constraints.gridwidth = GridBagConstraints.REMAINDER; container.add(this.threadsField, constraints); } @Override protected boolean isInputValid() { if (!super.isInputValid()) { return false; } else { String threadsString = this.threadsField.getText(); try { int threads = Integer.parseInt(threadsString); if (threads <= 0) { throw new NumberFormatException(); } showStatus(null); return true; } catch (NumberFormatException nfe) { showStatus("Invalid number of threads: " + threadsString); this.threadsField.requestFocus(); return false; } } } @Override protected Operation getOperation(long precision, int radix) throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = Integer.parseInt(this.threadsField.getText()); ctx.setNumberOfProcessors(numberOfProcessors); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); Operation operation = super.getOperation(precision, radix); if (operation instanceof Pi.ChudnovskyPiCalculator) { operation = new PiParallel.ParallelChudnovskyPiCalculator(precision, radix); } else if (operation instanceof Pi.RamanujanPiCalculator) { operation = new PiParallel.ParallelRamanujanPiCalculator(precision, radix); } return operation; } private static final long serialVersionUID = 1L; private Label threadsLabel; private TextField threadsField; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/PiParallelApplet.java000066400000000000000000000032111461767713300307020ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.awt.Container; /** * Applet for calculating pi using multiple threads in parallel. * * @version 1.9.0 * @author Mikko Tommila */ public class PiParallelApplet extends PiApplet { /** * Default constructor. */ public PiParallelApplet() { } @Override protected Container getContents() { return new PiParallelAWT(this); } private static final long serialVersionUID = 1L; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/PiParallelGUI.java000066400000000000000000000035301461767713300301050ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.awt.Container; /** * AWT client application for calculating pi using multiple threads in parallel. * * @version 1.9.0 * @author Mikko Tommila */ public class PiParallelGUI extends PiGUI { /** * Default constructor. */ protected PiParallelGUI() { } @Override protected Container getContents() { return new PiParallelAWT(this); } /** * Command-line entry point. * * @param args Command-line parameters. */ public static void main(String[] args) { new PiParallelGUI(); } private static final long serialVersionUID = 1L; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/RemoteOperationExecutor.java000066400000000000000000000101671461767713300323520ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.samples; import java.net.InetSocketAddress; import java.nio.channels.Channels; import java.nio.channels.SocketChannel; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.BufferedOutputStream; import java.io.IOException; /** * Class to call an {@link OperationServer} to execute {@link Operation}s remotely. * * @version 1.9.0 * @author Mikko Tommila */ public class RemoteOperationExecutor implements OperationExecutor { /** * Create a new client that will connect to the server * running at the specified host and port. * * @param host Hostname of the remote server. * @param port Port of the remote server. */ public RemoteOperationExecutor(String host, int port) { this.host = host; this.port = port; } /** * Execute an operation remotely. * This method will block until the return value has been received. * * @param operation The operation to execute remotely. * * @return The result of the operation. * * @exception RuntimeException In case of network error or if the return value class is unknown. */ @Override public T execute(Operation operation) { T result; try (SocketChannel channel = SocketChannel.open(new InetSocketAddress(this.host, this.port))) { ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(Channels.newOutputStream(channel), BUFFER_SIZE)); out.writeObject(operation); out.flush(); ObjectInputStream in = new ObjectInputStream(Channels.newInputStream(channel)); @SuppressWarnings("unchecked") T obj = (T) in.readObject(); result = obj; } catch (IOException | ClassNotFoundException e) { throw new RuntimeException(e); } return result; } /** * Execute an operation remotely. * This method starts a new thread running the remote call and returns immediately. * * @param operation The operation to execute remotely. * * @return A {@link BackgroundOperation} for retrieving the result of the operation later. */ @Override public BackgroundOperation executeBackground(Operation operation) { return new BackgroundOperation<>(() -> RemoteOperationExecutor.this.execute(operation)); } @Override public int getWeight() { return 1; } /** * Returns the host name. * * @return The host name. */ public String getHost() { return this.host; } /** * Returns the host port. * * @return The host port. */ public int getPort() { return this.port; } private static final int BUFFER_SIZE = 8192; private String host; private int port; } apfloat-1.14.0/apfloat-samples/src/main/java/org/apfloat/samples/package-info.java000066400000000000000000000061621461767713300300430ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** Sample applications demonstrating apfloat use.

Three different versions of an application for calculating π are included. The simplest, {@link org.apfloat.samples.Pi} runs on one computer using one processor (and one thread) only. {@link org.apfloat.samples.PiParallel} executes multiple threads in parallel and has vastly better performance on multi-core computers. Finally, {@link org.apfloat.samples.PiDistributed} can use multiple separate computers for calculating pi with even greater processing power.

As a curiosity, two applets are provided for running {@link org.apfloat.samples.Pi} and {@link org.apfloat.samples.PiParallel} through a graphical user interface: {@link org.apfloat.samples.PiApplet} and {@link org.apfloat.samples.PiParallelApplet}, correspondingly. These programs can also be run as stand-alone Java applications: {@link org.apfloat.samples.PiGUI} and {@link org.apfloat.samples.PiParallelGUI}.

Compared to the C++ version of apfloat, the Java version pi calculation program is usually just as fast. Even in worst cases the Java version achieves roughly 50% of the performance of the assembler-optimized C++ versions of apfloat. Modern JVMs are nearly as efficient as optimizing C++ compilers in code generation. The advantage that JVMs have over native C++ compilers is obviously that the JVM generates optimal code for every target architecture and runtime profile automatically, from an intermediate portable binary executable format. With C++, the source code must be compiled and profiled manually for every target architecture, which can be difficult and tedious.

On multi-core computers the Java parallel pi calculator is often significantly faster than the C++ parallel version. The same applies to the distributed pi calculator. Multi-threaded and distributed applications are more efficient to implement in Java due to C++'s historical lack of standard libraries for threading and networking. */ package org.apfloat.samples; apfloat-1.14.0/apfloat-samples/src/main/resources/000077500000000000000000000000001461767713300220575ustar00rootroot00000000000000apfloat-1.14.0/apfloat-samples/src/main/resources/cluster.properties000066400000000000000000000003561461767713300256620ustar00rootroot00000000000000# The format of the file is # # server1=hostname:port # server2=hostname2:port # server3=hostname3:port # # Optionally, relative weights can be specified for the server nodes, e.g. # # weight1=100 # weight2=150 # weight3=200 apfloat-1.14.0/apfloat-tools/000077500000000000000000000000001461767713300160265ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/pom.xml000066400000000000000000000101241461767713300173410ustar00rootroot00000000000000 4.0.0 org.apfloat apfloat-parent 1.14.0-SNAPSHOT apfloat-tools apfloat Tools for generating apfloat constants http://www.apfloat.org org.apfloat apfloat org.apache.maven.plugins maven-antrun-plugin generate-sources generate-sources run org.codehaus.mojo build-helper-maven-plugin add-sources generate-sources add-source target/generated-sources/main apfloat-1.14.0/apfloat-tools/src/000077500000000000000000000000001461767713300166155ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/000077500000000000000000000000001461767713300175415ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/java/000077500000000000000000000000001461767713300204625ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/java/org/000077500000000000000000000000001461767713300212515ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/java/org/apfloat/000077500000000000000000000000001461767713300226775ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/java/org/apfloat/tools/000077500000000000000000000000001461767713300240375ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/java/org/apfloat/tools/CreateRadixConstants.java000066400000000000000000000077221461767713300310020ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.tools; /** * This utility class can be used to generate the file * RadixConstants.java. * * @version 1.1 * @author Mikko Tommila */ public class CreateRadixConstants { public static void main(String[] args) { StringBuilder radixFactors = new StringBuilder("{ "); for (int i = 0 ; i <= Character.MAX_RADIX; i++) { StringBuilder buffer = new StringBuilder("{ "); int factors = 0; for (int j = 2; j <= i; j++) { if (i % j == 0 && isPrime(j)) { buffer.append(factors > 0 ? ", " : "").append(j); factors++; } } buffer.append(" }"); radixFactors.append(i > 0 ? ", " : "").append(i >= Character.MIN_RADIX ? buffer : null); } radixFactors.append(" };"); StringBuilder floatPrecision = new StringBuilder("{ "); for (int i = 0 ; i <= Character.MAX_RADIX; i++) { int precision = (int) Math.ceil(Math.log(16777216.0) / Math.log((double) i)); floatPrecision.append(i > 0 ? ", " : "").append(i >= Character.MIN_RADIX ? precision : -1); } floatPrecision.append(" };"); StringBuilder doublePrecision = new StringBuilder("{ "); for (int i = 0 ; i <= Character.MAX_RADIX; i++) { int precision = (int) Math.ceil(Math.log(9007199254740992.0) / Math.log((double) i)); doublePrecision.append(i > 0 ? ", " : "").append(i >= Character.MIN_RADIX ? precision : -1); } doublePrecision.append(" };"); StringBuilder longPrecision = new StringBuilder("{ "); for (int i = 0 ; i <= Character.MAX_RADIX; i++) { int precision = (int) Math.ceil(Math.log(9223372036854775808.0) / Math.log((double) i)); longPrecision.append(i > 0 ? ", " : "").append(i >= Character.MIN_RADIX ? precision : -1); } longPrecision.append(" };"); System.out.println("package org.apfloat.spi;"); System.out.println(""); System.out.println("public interface RadixConstants"); System.out.println("{"); System.out.println(" public static final int RADIX_FACTORS[][] = " + radixFactors); System.out.println(""); System.out.println(" public static final int FLOAT_PRECISION[] = " + floatPrecision); System.out.println(" public static final int DOUBLE_PRECISION[] = " + doublePrecision); System.out.println(" public static final int LONG_PRECISION[] = " + longPrecision); System.out.println("}"); } private static boolean isPrime(int p) { return java.math.BigInteger.valueOf(p).isProbablePrime(128); } } apfloat-1.14.0/apfloat-tools/src/main/java/org/apfloat/tools/PrimitiveRoot.java000066400000000000000000000055361461767713300275270ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.tools; import org.apfloat.internal.LongModMath; /** * This tool can be used to generate a primitive root * for a prime modulus. * * @version 1.0 * @author Mikko Tommila */ public class PrimitiveRoot extends LongModMath { private PrimitiveRoot(long p) { setModulus(p); } public static void main(String[] args) { if (args.length < 1) { System.err.println("Usage: PrimitiveRoot p"); System.err.println(" where p must be prime"); return; } long p = Long.parseLong(args[0]); System.out.println(new PrimitiveRoot(p).findPrimitiveRoot()); } private long findPrimitiveRoot() { long p1 = getModulus() - 1, root = 1; int i; long[] factors = factorize(p1); do { root++; for (i = 0; i < factors.length; i++) { if (modPow(root, p1 / factors[i]) == 1) { break; } } } while (i < factors.length); return root; } private static long[] factorize(long n) { long[] factors = new long[64]; int i; for (i = 0; (n & 1) == 0; i++) { factors[i] = 2; n /= 2; } for (long f = 3; n > 1; f += 2) { for (; n % f == 0; i++) { factors[i] = f; n /= f; } } long[] buffer = new long[i]; System.arraycopy(factors, 0, buffer, 0, i); return buffer; } } apfloat-1.14.0/apfloat-tools/src/main/template/000077500000000000000000000000001461767713300213545ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/template/org/000077500000000000000000000000001461767713300221435ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/template/org/apfloat/000077500000000000000000000000001461767713300235715ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/template/org/apfloat/tools/000077500000000000000000000000001461767713300247315ustar00rootroot00000000000000apfloat-1.14.0/apfloat-tools/src/main/template/org/apfloat/tools/RawtypeConvolutionTime.java000066400000000000000000000113451461767713300323120ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.tools; import java.util.Random; import org.apfloat.Apfloat; import org.apfloat.ApfloatContext; import org.apfloat.spi.ConvolutionBuilder; import org.apfloat.spi.NTTBuilder; import org.apfloat.internal.RawtypeBuilderFactory; import org.apfloat.internal.RawtypeKaratsubaConvolutionStrategy; import org.apfloat.internal.RawtypeMediumConvolutionStrategy; import org.apfloat.internal.ParallelThreeNTTConvolutionStrategy; /** * This tool can be used to test whether the simple O(n2), * Karatsuba or the triple-NTT convolution algorithm is fastest for * specified multiplicand sizes. Tuning the algorithm selection * properly is crucial for a {@link ConvolutionBuilder} to work * efficiently. * * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeConvolutionTime { public static void main(String[] args) { if (args.length < 2) { System.err.println("Usage: RawtypeConvolutionTime n m [repetitions]"); System.err.println(" where the convolution size is n + m digits"); return; } NTTBuilder nttBuilder = ApfloatContext.getContext().getBuilderFactory().getNTTBuilder(); float mediumTime = run(args, "medium", (radix, size1, size2, resultSize) -> new RawtypeMediumConvolutionStrategy(radix)); float karatsubaTime = run(args, "Karatsuba", (radix, size1, size2, resultSize) -> new RawtypeKaratsubaConvolutionStrategy(radix)); float nttTime = run(args, "3 NTT", (radix, size1, size2, resultSize) -> new ParallelThreeNTTConvolutionStrategy(radix, nttBuilder.createNTT(size1 + size2))); int n = Integer.parseInt(args[0]), m = Integer.parseInt(args[1]); System.out.println(n + " x " + m + " convolution medium " + mediumTime + " ms, Karatsuba " + karatsubaTime + " ms, NTT " + nttTime + " ms"); } private static float run(String[] args, String method, ConvolutionBuilder convolutionBuilder) { int n = Integer.parseInt(args[0]), m = Integer.parseInt(args[1]), reps = (args.length > 2 ? Integer.parseInt(args[2]) : 1), radix = ApfloatContext.getContext().getDefaultRadix(); Random random = new Random(); ApfloatContext.getContext().setBuilderFactory(new RawtypeBuilderFactory() { @Override public ConvolutionBuilder getConvolutionBuilder() { return convolutionBuilder; } }); ApfloatContext.getContext().setCacheL1Size(Integer.MAX_VALUE); // To use simple single-thread NTT only long minTime = Long.MAX_VALUE; int length = Math.max(n, m); StringBuilder buffer = new StringBuilder(length); for (int i = 0; i < length; i++) { buffer.append(Character.forDigit(random.nextInt(radix), radix)); } String s = buffer.toString(); Apfloat a = new Apfloat(s.substring(0, n), Apfloat.INFINITE), b = new Apfloat(s.substring(0, m), Apfloat.INFINITE); int c = 0; for (int i = 0; i < TESTS; i++) { long time = System.currentTimeMillis(); for (int j = 0; j < reps; j++) { c += System.identityHashCode(a.multiply(b)); } time = System.currentTimeMillis() - time; minTime = Math.min(time, minTime); } System.err.println("Check: " + c); return (float) minTime / reps; } private static final int TESTS = 5; } apfloat-1.14.0/apfloat-tools/src/main/template/org/apfloat/tools/RawtypeCreateRadixConstants.java000066400000000000000000000073331461767713300332460ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.tools; import static org.apfloat.internal.RawtypeModConstants.*; /** * This utility class can be used to generate the file * RawtypeRadixConstants.java. * * @version 1.2 * @author Mikko Tommila */ public class RawtypeCreateRadixConstants { public static void main(String[] args) { StringBuilder base = new StringBuilder("{ "); StringBuilder baseDigits = new StringBuilder("{ "); StringBuilder minimumForDigits = new StringBuilder("{ "); StringBuilder maxExponent = new StringBuilder("{ "); for (int i = 0 ; i <= Character.MAX_RADIX; i++) { int radixBaseDigits; long radixBase = 1; StringBuilder buffer = new StringBuilder("{ "); // MODULUS[2] must be the smallest of the moduli assert (MODULUS[1] <= MODULUS[0]); assert (MODULUS[2] <= MODULUS[1]); for (radixBaseDigits = 0; i >= Character.MIN_RADIX && radixBase <= MODULUS[2] / i; radixBaseDigits++, radixBase *= i) { buffer.append(radixBaseDigits > 0 ? ", " : "").append("(rawtype) ").append(radixBase).append('L'); } buffer.append(" }"); long exponent = (i >= Character.MIN_RADIX ? Long.MAX_VALUE / radixBaseDigits - 6: -1); // Leave enough slack e.g. for toString() base.append(i > 0 ? ", " : "").append("(rawtype) ").append(i >= Character.MIN_RADIX ? radixBase : -1).append('L'); baseDigits.append(i > 0 ? ", " : "").append(i >= Character.MIN_RADIX ? radixBaseDigits : -1); minimumForDigits.append(i > 0 ? ", " : "").append(i >= Character.MIN_RADIX ? buffer : null); maxExponent.append(i > 0 ? ", " : "").append(exponent).append('L'); } base.append(" };"); baseDigits.append(" };"); minimumForDigits.append(" };"); maxExponent.append(" };"); System.out.println("package org.apfloat.internal;"); System.out.println(""); System.out.println("public interface RawtypeRadixConstants"); System.out.println("{"); System.out.println(" public static final rawtype BASE[] = " + base); System.out.println(" public static final int BASE_DIGITS[] = " + baseDigits); System.out.println(" public static final rawtype MINIMUM_FOR_DIGITS[][] = " + minimumForDigits); System.out.println(" public static final long MAX_EXPONENT[] = " + maxExponent); System.out.println("}"); } } apfloat-1.14.0/apfloat-tools/src/main/template/org/apfloat/tools/RawtypeMatrixTime.java000066400000000000000000000075221461767713300312410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.tools; import org.apfloat.ApfloatContext; import org.apfloat.internal.RawtypeMatrixStrategy; import org.apfloat.internal.RawtypeMemoryArrayAccess; /** * This tool can be used for testing the matrix transposition * algorithm performance.

* * Note that you can't directly specify, which of the three * transposition algorithms is used internally in the matrix * class. You can specify it indirectly as follows: * *

    *
  • "L1 cache algorithm": set L1 cache size to a maximum value
  • *
  • "L2 cache algorithm": set L1 cache size to zero and L2 cache size to a maximum value
  • *
  • "main memory algorithm": set L1 cache size and L2 cache size to zero
  • *
* * Usually, the overall best performance is achieved by specifying * correctly the L1 and L2 cache sizes. If the L2 cache is very fast, * transposing matrixes that fit to the L2 cache entirely may be * faster using the "L1 cache algorithm". This can be done by (incorrectly) * setting the L1 cache size to the same value as the L2 cache size. * But with this setting transposing matrixes that do not fit to the * L2 cache is usually slower than when the L1 cache size is set correctly. * * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeMatrixTime { public static void main(String[] args) { if (args.length < 3) { System.err.println("Usage: RawtypeMatrixTime n L1CacheSize L2CacheSize [repetitions]"); System.err.println(" where the matrix size is n x n"); return; } int n = Integer.parseInt(args[0]), l1CacheSize = Integer.parseInt(args[1]), l2CacheSize = Integer.parseInt(args[2]), reps = (args.length > 3 ? Integer.parseInt(args[3]) : 1), size = n * n; ApfloatContext.getContext().setCacheL1Size(l1CacheSize); ApfloatContext.getContext().setCacheL2Size(l2CacheSize); RawtypeMemoryArrayAccess arrayAccess = new RawtypeMemoryArrayAccess(new rawtype[size], 0, size); RawtypeMatrixStrategy rawtypeMatrix = new RawtypeMatrixStrategy(); long minTime = Long.MAX_VALUE; for (int i = 0; i < TESTS; i++) { long time = System.currentTimeMillis(); for (int j = 0; j < reps; j++) { rawtypeMatrix.transpose(arrayAccess, n, n); } time = System.currentTimeMillis() - time; minTime = Math.min(time, minTime); } System.out.println(n + " x " + n + " matrix transposition " + (float) minTime / reps + " ms"); } private static final int TESTS = 3; } apfloat-1.14.0/apfloat/000077500000000000000000000000001461767713300146705ustar00rootroot00000000000000apfloat-1.14.0/apfloat/pom.xml000066400000000000000000000271421461767713300162130ustar00rootroot00000000000000 4.0.0 org.apfloat apfloat-parent 1.14.0 apfloat apfloat High performance arbitrary precision arithmetic library http://www.apfloat.org ${project.build.sourceDirectory}9 ${project.build.outputDirectory}/META-INF/versions/9 junit junit test org.apache.maven.plugins maven-antrun-plugin generate-sources generate-sources run generate-test-sources generate-test-sources run org.codehaus.mojo build-helper-maven-plugin add-sources generate-sources add-source target/generated-sources/main add-test-sources generate-test-sources add-test-source target/generated-sources/test org.apache.maven.plugins maven-compiler-plugin * default-testCompile testCompile 9 biz.aQute.bnd bnd-maven-plugin generate-osgi-manifest bnd-process org.apache.maven.plugins maven-jar-plugin test-jar ${project.build.outputDirectory}/META-INF/MANIFEST.MF org.apache.maven.plugins maven-shade-plugin shade ${project.build.directory}/apfloat.jar src/main/resources META-INF/** java9 !skipJava9 org.apache.maven.plugins maven-antrun-plugin compile-java9 compile run java9-test org.apache.maven.plugins maven-antrun-plugin copy-java9-classes compile run apfloat-1.14.0/apfloat/serialver.properties000066400000000000000000000145371461767713300210140ustar00rootroot00000000000000org.apfloat.Apcomplex.serialVersionUID=3642932980384250551L org.apfloat.Apfloat.serialVersionUID=-36707433458144439L org.apfloat.ApfloatRuntimeException.serialVersionUID=-7022924635011038776L org.apfloat.Apint.serialVersionUID=5409721945040465491L org.apfloat.Aprational.serialVersionUID=-224128535732558313L org.apfloat.internal.DiskDataStorage$FileStorage.serialVersionUID=2062430603153403341L org.apfloat.internal.DiskDataStorage.serialVersionUID=741984828408146034L org.apfloat.internal.DoubleAdditionStrategy.serialVersionUID=6863520700151824670L org.apfloat.internal.DoubleApfloatImpl.serialVersionUID=-4177541592360478544L org.apfloat.internal.DoubleBaseMath.serialVersionUID=4560898425815362356L org.apfloat.internal.DoubleCarryCRTSteps.serialVersionUID=2974874464027705533L org.apfloat.internal.DoubleDiskDataStorage.serialVersionUID=342871486421108657L org.apfloat.internal.DoubleDiskDataStorage$BlockIterator.serialVersionUID=-1996647087834590031L org.apfloat.internal.DoubleDiskDataStorage$DoubleDiskArrayAccess.serialVersionUID=-7097317279839657081L org.apfloat.internal.DoubleDiskDataStorage$MemoryArrayAccess.serialVersionUID=3646716922431352928L org.apfloat.internal.DoubleDiskDataStorage$TransposedMemoryArrayAccess.serialVersionUID=-3746109883682965310L org.apfloat.internal.DoubleKaratsubaConvolutionStrategy.serialVersionUID=3605808557478224821L org.apfloat.internal.DoubleMediumConvolutionStrategy.serialVersionUID=3566451570697893745L org.apfloat.internal.DoubleMemoryArrayAccess.serialVersionUID=-8917010087742357783L org.apfloat.internal.DoubleMemoryDataStorage.serialVersionUID=5093781604796636929L org.apfloat.internal.DoubleMemoryDataStorage$ReadWriteIterator=-9012199261873349608L org.apfloat.internal.DoubleMemoryDataStorage$ReadOnlyIterator=5449985546703735328L org.apfloat.internal.DoubleMemoryDataStorage$WriteOnlyIterator=3758519654059499404L org.apfloat.internal.DoubleShortConvolutionStrategy.serialVersionUID=-2048097533911386543L org.apfloat.internal.FloatAdditionStrategy.serialVersionUID=-8811571288007744481L org.apfloat.internal.FloatApfloatImpl.serialVersionUID=4198839366471670758L org.apfloat.internal.FloatBaseMath.serialVersionUID=-2321698097908304307L org.apfloat.internal.FloatCarryCRTSteps.serialVersionUID=3192182234524626533L org.apfloat.internal.FloatDiskDataStorage.serialVersionUID=1045290368963828503L org.apfloat.internal.FloatDiskDataStorage$BlockIterator.serialVersionUID=8503701548995236882L org.apfloat.internal.FloatDiskDataStorage$FloatDiskArrayAccess.serialVersionUID=1750388414420962922L org.apfloat.internal.FloatDiskDataStorage$MemoryArrayAccess.serialVersionUID=-3536582909010606907L org.apfloat.internal.FloatDiskDataStorage$TransposedMemoryArrayAccess.serialVersionUID=898289922606519237L org.apfloat.internal.FloatKaratsubaConvolutionStrategy.serialVersionUID=-4438101427690647475L org.apfloat.internal.FloatMediumConvolutionStrategy.serialVersionUID=-6697305140738370764L org.apfloat.internal.FloatMemoryArrayAccess.serialVersionUID=7704133670961317045L org.apfloat.internal.FloatMemoryDataStorage.serialVersionUID=-862001153825924236L org.apfloat.internal.FloatMemoryDataStorage$ReadWriteIterator=-5979620684548284607L org.apfloat.internal.FloatMemoryDataStorage$ReadOnlyIterator=-6693429125989500778L org.apfloat.internal.FloatMemoryDataStorage$WriteOnlyIterator=-5251200289176969505L org.apfloat.internal.FloatShortConvolutionStrategy.serialVersionUID=3839614758362699756L org.apfloat.internal.IntAdditionStrategy.serialVersionUID=-6156689494629604331L org.apfloat.internal.IntApfloatImpl.serialVersionUID=-3759805150008433996L org.apfloat.internal.IntBaseMath.serialVersionUID=2173589976837534455L org.apfloat.internal.IntCarryCRTSteps.serialVersionUID=7666237487091579201L org.apfloat.internal.IntDiskDataStorage.serialVersionUID=-1540087135754114721L org.apfloat.internal.IntDiskDataStorage$BlockIterator.serialVersionUID=4187202582650284101L org.apfloat.internal.IntDiskDataStorage$IntDiskArrayAccess.serialVersionUID=-88509093904437138L org.apfloat.internal.IntDiskDataStorage$MemoryArrayAccess.serialVersionUID=7690849230285450035L org.apfloat.internal.IntDiskDataStorage$TransposedMemoryArrayAccess.serialVersionUID=2990517367865486151L org.apfloat.internal.IntKaratsubaConvolutionStrategy.serialVersionUID=-4939884744147374897L org.apfloat.internal.IntMediumConvolutionStrategy.serialVersionUID=-1339358141859224649L org.apfloat.internal.IntMemoryArrayAccess.serialVersionUID=-1137159053668908693L org.apfloat.internal.IntMemoryDataStorage.serialVersionUID=4034264499027294039L org.apfloat.internal.IntMemoryDataStorage$ReadWriteIterator=6881950853858664947L org.apfloat.internal.IntMemoryDataStorage$ReadOnlyIterator=-6709295918596292159L org.apfloat.internal.IntMemoryDataStorage$WriteOnlyIterator=2753806793669098570L org.apfloat.internal.IntShortConvolutionStrategy.serialVersionUID=7238463434254768541L org.apfloat.internal.LongAdditionStrategy.serialVersionUID=4128390142053847289L org.apfloat.internal.LongApfloatImpl.serialVersionUID=-2151344673641680085L org.apfloat.internal.LongBaseMath.serialVersionUID=-6469225916787810664L org.apfloat.internal.LongCarryCRTSteps.serialVersionUID=-1851512769800204475L org.apfloat.internal.LongDiskDataStorage.serialVersionUID=4741507089425158620L org.apfloat.internal.LongDiskDataStorage$BlockIterator.serialVersionUID=-2804905180796718735L org.apfloat.internal.LongDiskDataStorage$LongDiskArrayAccess.serialVersionUID=-2591640502422276852L org.apfloat.internal.LongDiskDataStorage$MemoryArrayAccess.serialVersionUID=-1573539652919953016L org.apfloat.internal.LongDiskDataStorage$TransposedMemoryArrayAccess.serialVersionUID=-455915044370886962L org.apfloat.internal.LongKaratsubaConvolutionStrategy.serialVersionUID=-4812398042499004749L org.apfloat.internal.LongMediumConvolutionStrategy.serialVersionUID=1303060028106603429L org.apfloat.internal.LongMemoryArrayAccess.serialVersionUID=844248131988537796L org.apfloat.internal.LongMemoryDataStorage.serialVersionUID=-6031760912313925045L org.apfloat.internal.LongMemoryDataStorage$ReadWriteIterator=4304749820031861943L org.apfloat.internal.LongMemoryDataStorage$ReadOnlyIterator=-7988916595169322136L org.apfloat.internal.LongMemoryDataStorage$WriteOnlyIterator=5072203220986659720L org.apfloat.internal.LongShortConvolutionStrategy.serialVersionUID=1971685561366493327L org.apfloat.spi.DataStorage.serialVersionUID=1862028601696578467L apfloat-1.14.0/apfloat/src/000077500000000000000000000000001461767713300154575ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/000077500000000000000000000000001461767713300164035ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java/000077500000000000000000000000001461767713300173245ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java/apfloat.java000066400000000000000000000071721461767713300216240ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import java.util.ListResourceBundle; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; import org.apfloat.ApfloatContext; import org.apfloat.spi.Util; /** * Default initial settings for the global {@link ApfloatContext}. * * @version 1.9.0 * @author Mikko Tommila */ public class apfloat extends ListResourceBundle { @Override public Object[][] getContents() { return CONTENTS; } private static final Object[][] CONTENTS; static { // Try to use up to 80% of total memory and all processors long totalMemory; try { MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); MemoryUsage memoryUsage = memoryBean.getHeapMemoryUsage(); totalMemory = Math.max(memoryUsage.getCommitted(), memoryUsage.getMax()); } catch (NoClassDefFoundError ncdfe) { // The ManagementFactory class might be unavailable totalMemory = Runtime.getRuntime().maxMemory(); } long maxMemoryBlockSize = Util.round23down(totalMemory / 5 * 4); int numberOfProcessors = Runtime.getRuntime().availableProcessors(); long memoryThreshold = Math.max(maxMemoryBlockSize >> 10, 65536); int blockSize = Util.round2down((int) Math.min(memoryThreshold, Integer.MAX_VALUE)); Object[][] contents = { { ApfloatContext.BUILDER_FACTORY, "org.apfloat.internal.LongBuilderFactory" }, { ApfloatContext.DEFAULT_RADIX, "10" }, { ApfloatContext.MAX_MEMORY_BLOCK_SIZE, String.valueOf(maxMemoryBlockSize) }, { ApfloatContext.CACHE_L1_SIZE, "8192" }, { ApfloatContext.CACHE_L2_SIZE, "262144" }, { ApfloatContext.CACHE_BURST, "32" }, { ApfloatContext.MEMORY_THRESHOLD, String.valueOf(memoryThreshold) }, { ApfloatContext.SHARED_MEMORY_TRESHOLD, String.valueOf(maxMemoryBlockSize / numberOfProcessors / 32) }, { ApfloatContext.BLOCK_SIZE, String.valueOf(blockSize) }, { ApfloatContext.NUMBER_OF_PROCESSORS, String.valueOf(numberOfProcessors) }, { ApfloatContext.FILE_PATH, "" }, { ApfloatContext.FILE_INITIAL_VALUE, "0" }, { ApfloatContext.FILE_SUFFIX, ".ap" }, { ApfloatContext.CLEANUP_AT_EXIT, "true" } }; CONTENTS = contents; } } apfloat-1.14.0/apfloat/src/main/java/org/000077500000000000000000000000001461767713300201135ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java/org/apfloat/000077500000000000000000000000001461767713300215415ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java/org/apfloat/Apcomplex.java000066400000000000000000001005211461767713300243330ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.io.Serializable; import java.io.PushbackReader; import java.io.Writer; import java.io.IOException; import java.util.Comparator; import java.util.Formattable; import java.util.Formatter; import static java.util.FormattableFlags.*; /** * Arbitrary precision complex number class. An apcomplex consists of * a real and imaginary part of type {@link Apfloat}.

* * Note that although the Apcomplex class extends Number, * the methods inherited from Number return the value of * the real part of the complex number. Thus they are more meaningful * for the {@link Apfloat} class and its subclasses.

* * @see Apfloat * @see ApcomplexMath * * @version 1.13.0 * @author Mikko Tommila */ public class Apcomplex extends Number implements Formattable, Serializable { /** * Constant for zero. It is safe to use ZERO * in all addition, subtraction, multiplication, division and * comparison operations regardless of the radix used. */ public static final Apint ZERO = new Apint(0); /** * Constant for one. Note that this number is created using the * initial default radix. It is safe to use ONE * in all multiplication, division and equality comparison operations * regardless of the radix used. However, in subtraction and addition * it only works with numbers in the same radix. */ public static final Apint ONE = new Apint(1); /** * Imaginary unit. That is, Apcomplex(ZERO, ONE). * It is safe to use I in all multiplication, * division and equality comparison operations * regardless of the radix used. In addition and subtraction * it only works with numbers in the same radix. */ public static final Apcomplex I = new Apcomplex(ZERO, ONE); /** * Infinite precision or scale. Can be used as the precision argument * when constructing apfloats. */ public static final long INFINITE = Long.MAX_VALUE; /** * Default precision. Can be used as an argument when constructing apfloats. */ public static final long DEFAULT = 0x8000000000000000L; /** * Comparator for ordering by real part, and in case of a tie, by imaginary * part. */ public static final Comparator REAL_IMAG_ORDER = (z, w) -> { int result = z.real().compareTo(w.real()); if (result == 0) { result = z.imag().compareTo(w.imag()); } return result; }; /** * Comparator for ordering by real part, and in case of a tie, by the * absolute value of the imaginary part. If a tie persists, order by * imaginary part. */ public static final Comparator REAL_ABS_IMAG_ORDER = (z, w) -> { int result = z.real().compareTo(w.real()); if (result == 0) { result = ApfloatMath.abs(z.imag()).compareTo(ApfloatMath.abs(w.imag())); } if (result == 0) { result = Integer.compare(z.imag().signum(), w.imag().signum()); } return result; }; /** * Extra precision that is added in various apfloat internal * operations to avoid round-off errors. */ static final int EXTRA_PRECISION = 20; /** * Default constructor. To be used only by subclasses that * overload all needed methods. */ protected Apcomplex() { } /** * Construct a real apcomplex whose imaginary part is zero. * * @param real The real part of the number. */ public Apcomplex(Apfloat real) { this(real, ZEROS[real.radix()]); } /** * Construct an apcomplex with the specified real and imaginary part. * * @param real The real part of the number. * @param imag The imaginary part of the number. * * @exception IllegalArgumentException If the real part and imaginary part are not zero but have different radixes. */ public Apcomplex(Apfloat real, Apfloat imag) throws IllegalArgumentException { if (real.signum() != 0 && imag.signum() != 0 && real.radix() != imag.radix()) { throw new IllegalArgumentException("Real part and imaginary part must have the same radix"); } this.real = real; this.imag = imag; } /** * Constructs an apcomplex from a string.

* * The input must be of one of the formats

* * realPart
* "(" [whitespace] realPart [whitespace] ")"
* "(" [whitespace] realPart [whitespace] "," [whitespace] imaginaryPart [whitespace] ")"
* * @param value The input string. * * @exception NumberFormatException If the number is invalid. */ public Apcomplex(String value) throws NumberFormatException, ApfloatRuntimeException { if (!value.startsWith("(")) { this.real = new Apfloat(value); this.imag = ZEROS[this.real.radix()]; return; } if (!value.endsWith(")")) { throw new NumberFormatException("Missing end parenthesis"); } int index = value.indexOf(','); if (index < 0) { this.real = new Apfloat(value.substring(1, value.length() - 1).trim()); this.imag = ZEROS[this.real.radix()]; return; } this.real = new Apfloat(value.substring(1, index).trim()); this.imag = new Apfloat(value.substring(index + 1, value.length() - 1).trim()); } /** * Reads an apcomplex from a reader. The constructor stops reading * at the first character it doesn't understand. The reader must thus * be a PushbackReader so that the invalid character can * be returned back to the stream.

* * The input must be of one of the formats

* * realPart
* "(" [whitespace] realPart [whitespace] ")"
* "(" [whitespace] realPart [whitespace] "," [whitespace] imaginaryPart [whitespace] ")"
* * @param in The input stream. * * @exception IOException In case of I/O error reading from the stream. * @exception NumberFormatException If the number is invalid. */ public Apcomplex(PushbackReader in) throws IOException, NumberFormatException, ApfloatRuntimeException { if (!ApfloatHelper.readMatch(in, '(')) { this.real = new Apfloat(in); this.imag = ZEROS[this.real.radix()]; return; } ApfloatHelper.extractWhitespace(in); this.real = new Apfloat(in); ApfloatHelper.extractWhitespace(in); if (ApfloatHelper.readMatch(in, ',')) { ApfloatHelper.extractWhitespace(in); this.imag = new Apfloat(in); } else { this.imag = ZEROS[this.real.radix()]; } ApfloatHelper.extractWhitespace(in); if (!ApfloatHelper.readMatch(in, ')')) { throw new NumberFormatException("Missing end parenthesis"); } } /** * Radix of this apcomplex. * * @return Radix of this apcomplex. */ public int radix() { return (real().signum() == 0 ? (imag().signum() == 0 ? real().radix() : imag().radix()) : real().radix()); } /** * Returns the real part of this apcomplex. * * @return The real part of this apcomplex. */ public Apfloat real() { return this.real; } /** * Returns the imaginary part of this apcomplex. * * @return The imaginary part of this apcomplex. */ public Apfloat imag() { return this.imag; } /** * Returns the complex conjugate of this apcomplex. * * @return x - i y, where this apcomplex is x + i y. */ public Apcomplex conj() throws ApfloatRuntimeException { return new Apcomplex(real(), imag().negate()); } /** * Returns the precision of this apcomplex. * * @return The precision of this apcomplex in number of digits of the radix in which it's presented. */ public long precision() throws ApfloatRuntimeException { if (real().signum() == 0 || imag().signum() == 0) { return Math.min(real().precision(), imag().precision()); } else { long[] precisions = ApfloatHelper.getMatchingPrecisions(real(), imag()); return Math.max(precisions[0], precisions[1]); } } /** * Returns an apcomplex with the same value as this apcomplex accurate to the * specified precision.

* * If the requested precision less than this number's current precision, the * functionality is quite obvious: the precision is simply truncated, and e.g. * comparison and equality checking will work as expected. Some rounding errors * in e.g. addition and subtraction may still occur, as "invisible" trailing * digits can remain in the number.

* * If the requested precision more than this number's current precision, the * functionality is quite undefined: the digits up to this number's current * precision are guaranteed to be the same, but the "new" digits are undefined: * they may be zero, or they may be digits that have been previously discarded * with a call to precision() with a smaller number of digits, or they may be * something else, or any combination of these.

* * These limitations allow various performance optimizations to be made. * * @param precision Precision of the new apcomplex. * * @return An apcomplex with the specified precision and same value as this apcomplex. * * @exception IllegalArgumentException If precision is <= 0. * * @since 1.2 */ public Apcomplex precision(long precision) throws IllegalArgumentException, ApfloatRuntimeException { ApfloatHelper.checkPrecision(precision); Apcomplex z = new Apcomplex(real().precision(precision), imag().precision(precision)); if (real().signum() == 0 || imag().signum() == 0) { return z; } long[] precisions = ApfloatHelper.getMatchingPrecisions(z.real(), z.imag()); long realPrecision = precisions[0], imagPrecision = precisions[1]; return new Apcomplex(realPrecision > 0 ? z.real().precision(realPrecision) : ZEROS[real().radix()], imagPrecision > 0 ? z.imag().precision(imagPrecision) : ZEROS[imag().radix()]); } /** * Returns the scale of this apcomplex. The scale is the maximum of the scale of the real part and imaginary part.

* * Zero has a scale of -INFINITE. * * @return The exponent of this apcomplex in number of digits of the radix in which it's presented. * * @see Apfloat#scale() */ public long scale() throws ApfloatRuntimeException { return Math.max(real().scale(), imag().scale()); } /** * Returns the size of this apcomplex. The size is the maximum of the size of the real part and imaginary part.

* * Zero has a size of 0. * * @return The number of digits in this number, from the most significant digit to the least significant nonzero digit, in the radix in which it's presented. * * @see Apfloat#size() * * @since 1.6 */ public long size() throws ApfloatRuntimeException { return Math.max(real().size(), imag().size()); } /** * Returns if this number is zero. * * @return If this number is zero. * * @since 1.13.0 */ public boolean isZero() throws ApfloatRuntimeException { return real().signum() == 0 && imag().signum() == 0; } /** * Returns if this number has an integer value. Note that this does not * necessarily mean that this object is an instance of {@link Apint}. * Neither does it mean that the precision is infinite.

* * A complex number needs to have a zero imaginary part to be an integer. * * @return If this number's value is an integer. * * @since 1.9.0 */ public boolean isInteger() throws ApfloatRuntimeException { return imag().signum() == 0 && real().isInteger(); } /** * Negative value. * * @return -this. * * @since 1.1 */ public Apcomplex negate() throws ApfloatRuntimeException { return new Apcomplex(real().negate(), imag().negate()); } /** * Adds two apcomplex numbers. * * @param z The number to be added to this number. * * @return this + z. */ public Apcomplex add(Apcomplex z) throws ApfloatRuntimeException { return new Apcomplex(real().add(z.real()), imag().add(z.imag())); } /** * Subtracts two apcomplex numbers. * * @param z The number to be subtracted from this number. * * @return this - z. */ public Apcomplex subtract(Apcomplex z) throws ApfloatRuntimeException { return new Apcomplex(real().subtract(z.real()), imag().subtract(z.imag())); } /** * Multiplies two apcomplex numbers. * * @param z The number to be multiplied by this number. * * @return this * z. */ public Apcomplex multiply(Apcomplex z) throws ApfloatRuntimeException { return new Apcomplex(ApfloatMath.multiplySubtract(real(), z.real(), imag(), z.imag()), ApfloatMath.multiplyAdd(real(), z.imag(), imag(), z.real())); } /** * Divides two apcomplex numbers. * * @param z The number by which this number is to be divided. * * @return this / z. * * @exception ArithmeticException In case the divisor is zero. */ public Apcomplex divide(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (z.isZero()) { throw new ArithmeticException(isZero() ? "Zero divided by zero" : "Division by zero"); } Apfloat tmpReal, tmpImag; // Multiply both numbers by i if z is pure imaginary if (z.real().signum() == 0) { z = new Apcomplex(z.imag(), z.real().negate()); tmpReal = imag(); tmpImag = real().negate(); } else { tmpReal = real(); tmpImag = imag(); } if (tmpImag.signum() == 0) { if (tmpReal.signum() == 0) { // 0 / x = 0 return this; } else if (z.imag().signum() == 0) { // Real return tmpReal.divide(z.real()); } } else if (z.imag().signum() == 0) { if (z.real().equals(ONE)) { // x / 1 = x return new Apcomplex(tmpReal.precision(Math.min(tmpReal.precision(), z.real().precision())), tmpImag.precision(Math.min(tmpImag.precision(), z.real().precision()))); } else if (z.real().isShort()) { // If the divisor real and "short", it's faster to divide directly return new Apcomplex(tmpReal.divide(z.real()), tmpImag.divide(z.real())); } // If the divisor is real but not "short", it's faster to generate the inverse root (only once) and multiply by it long precision = Math.min(precision(), z.real().precision()); Apfloat inverse = ApfloatMath.inverseRoot(z.real(), 1, precision); return new Apcomplex(tmpReal.multiply(inverse), tmpImag.multiply(inverse)); } long precision = Math.min(precision(), z.precision()); Apcomplex zApprox = new Apcomplex(z.real().precision(Math.min(precision, z.real().precision())), z.imag().precision(Math.min(precision, z.imag().precision()))); return multiply(z.conj()).divide(ApcomplexMath.norm(zApprox)); } /** * Returns the value of the this number as a double. * Only takes the real part of this number. * * @see Apfloat#doubleValue() * * @return The numeric value represented by this object after conversion to type double. */ @Override public double doubleValue() { return real().doubleValue(); } /** * Returns the value of the this number as a float. * Only takes the real part of this number. * * @see Apfloat#floatValue() * * @return The numeric value represented by this object after conversion to type float. */ @Override public float floatValue() { return real().floatValue(); } /** * Returns the value of the this number as a byte. * Only takes the real part of this number. * * @see Apfloat#byteValue() * * @return The numeric value represented by this object after conversion to type byte. */ @Override public byte byteValue() { return real().byteValue(); } /** * Returns the value of the this number as a short. * Only takes the real part of this number. * * @see Apfloat#shortValue() * * @return The numeric value represented by this object after conversion to type short. */ @Override public short shortValue() { return real().shortValue(); } /** * Returns the value of the this number as an int. * Only takes the real part of this number. * * @see Apfloat#intValue() * * @return The numeric value represented by this object after conversion to type int. */ @Override public int intValue() { return real().intValue(); } /** * Returns the value of the this number as a long. * Only takes the real part of this number. * * @see Apfloat#longValue() * * @return The numeric value represented by this object after conversion to type long. */ @Override public long longValue() { return real().longValue(); } /** * Returns the value of the this number as a byte, checking * for lost information. If the value of this number is out of the range * of the byte type, then an ArithmeticException * is thrown. * * @return The numeric value represented by this object after conversion to type byte. * * @throws ArithmeticException If the value of this will not exactly fit in a byte or has a nonzero fractional part. * * @since 1.9.0 */ public byte byteValueExact() throws ArithmeticException { long value = longValueExact(); if (value > Byte.MAX_VALUE || value < Byte.MIN_VALUE) { throw new ArithmeticException("Out of range"); } return (byte) value; } /** * Returns the value of the this number as a short, checking * for lost information. If the value of this number is out of the range * of the short type, then an ArithmeticException * is thrown. * * @return The numeric value represented by this object after conversion to type short or has a nonzero fractional part. * * @throws ArithmeticException If the value of this will not exactly fit in a short. * * @since 1.9.0 */ public short shortValueExact() throws ArithmeticException { long value = longValueExact(); if (value > Short.MAX_VALUE || value < Short.MIN_VALUE) { throw new ArithmeticException("Out of range"); } return (short) value; } /** * Returns the value of the this number as an int, checking * for lost information. If the value of this number is out of the range * of the int type, then an ArithmeticException * is thrown. * * @return The numeric value represented by this object after conversion to type int. * * @throws ArithmeticException If the value of this will not exactly fit in an int or has a nonzero fractional part. * * @since 1.9.0 */ public int intValueExact() throws ArithmeticException { long value = longValueExact(); if (value > Integer.MAX_VALUE || value < Integer.MIN_VALUE) { throw new ArithmeticException("Out of range"); } return (int) value; } /** * Returns the value of the this number as a long, checking * for lost information. If the value of this number is out of the range * of the long type, then an ArithmeticException * is thrown. * * @return The numeric value represented by this object after conversion to type long. * * @throws ArithmeticException If the value of this will not exactly fit in a long or has a nonzero fractional part. * * @since 1.9.0 */ public long longValueExact() throws ArithmeticException { if (imag().signum() != 0) { throw new ArithmeticException("Out of range"); } return real().longValueExact(); } /** * Computes number of equal digits.

* * Compares the digits of the numbers starting from the * most significant digits. The exponent and sign are * taken into consideration, so if either one doesn't match, * the numbers are considered to have zero equal digits.

* * For example, the numbers (12345, 123) and (123456, 12) have * zero matching digits, and the numbers (12345, 12) and * (12355, 13) have three matching digits. * * @param z Number to compare with. * * @return Number of matching digits in the radix in which the numbers are presented. */ public long equalDigits(Apcomplex z) throws ApfloatRuntimeException { if (isZero() && z.isZero()) { // Both are zero return Apfloat.INFINITE; } long minScale = Math.min(scale(), z.scale()), maxScale = Math.max(scale(), z.scale()); if (maxScale - 1 > minScale) { // No match return 0; } else { // Neither is zero, but the real part OR the imaginary part of each number may be zero long realScale = Math.max(real().scale(), z.real().scale()), imagScale = Math.max(imag().scale(), z.imag().scale()), realScaleDiff = (maxScale - realScale < 0 ? Apfloat.INFINITE : maxScale - realScale), imagScaleDiff = (maxScale - imagScale < 0 ? Apfloat.INFINITE : maxScale - imagScale), realEquals = real().equalDigits(z.real()), imagEquals = imag().equalDigits(z.imag()); return Math.min(realEquals + realScaleDiff < 0 ? Apfloat.INFINITE : realEquals + realScaleDiff, imagEquals + imagScaleDiff < 0 ? Apfloat.INFINITE : imagEquals + imagScaleDiff); } } /** * Convert this apcomplex to the specified radix. * * @param radix The radix. * * @return This number in the specified radix. * * @exception NumberFormatException If the radix is invalid. * * @since 1.2 */ public Apcomplex toRadix(int radix) throws NumberFormatException, ApfloatRuntimeException { return new Apcomplex(real().toRadix(radix), imag().toRadix(radix)); } /** * Compares this object to the specified object.

* * Note: two apfloats are considered equal if they have an identical mantissa, * but different precision. * * @param obj The object to compare with. * * @return true if the objects are equal; false otherwise. */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } else if (obj instanceof Apcomplex) { Apcomplex that = (Apcomplex) obj; return test(that) && real().equals(that.real()) && imag().equals(that.imag()); } else { return false; } } /** * Tests two apcomplex numbers for equality. * Returns false if the numbers are definitely known to be not equal. * If true is returned, equality is unknown and should be verified by * calling {@link #equals(Object)}. * This method is usually significantly faster than calling equals(Object). * * @param z The number to test against. * * @return false if the numbers are definitely not equal, true if unknown. * * @since 1.10.0 */ public boolean test(Apcomplex z) throws ApfloatRuntimeException { return real().test(z.real()) && imag().test(z.imag()); } /** * Returns a hash code for this apcomplex. * * @return The hash code value for this object. */ @Override public int hashCode() { return real().hashCode() * 3 + imag().hashCode(); } /** * Returns a string representation of this apcomplex. * * @return A string representing this object. */ @Override public String toString() { return toString(false); } /** * Returns a string representation of this apcomplex. * * @param pretty true to use a fixed-point notation, false to use an exponential notation. * * @return A string representing this object. */ public String toString(boolean pretty) throws ApfloatRuntimeException { if (imag().signum() == 0) { return real().toString(pretty); } else { return '(' + real().toString(pretty) + ", " + imag().toString(pretty) + ')'; } } /** * Write a string representation of this apcomplex to a Writer. * * @param out The output Writer. * * @exception IOException In case of I/O error writing to the stream. */ public void writeTo(Writer out) throws IOException, ApfloatRuntimeException { writeTo(out, false); } /** * Write a string representation of this apcomplex to a Writer. * * @param out The output Writer. * @param pretty true to use a fixed-point notation, false to use an exponential notation. * * @exception IOException In case of I/O error writing to the stream. */ public void writeTo(Writer out, boolean pretty) throws IOException, ApfloatRuntimeException { if (imag().signum() == 0) { real().writeTo(out, pretty); } else { out.write('('); real().writeTo(out, pretty); out.write(", "); imag().writeTo(out, pretty); out.write(')'); } } /** * Formats the object using the provided formatter. * * @param formatter The formatter. * @param flags The flags to modify the output format. * @param width The minimum number of characters to be written to the output, or -1 for no minimum. * @param precision The maximum number of characters to be written to the output, or -1 for no maximum. * * @since 1.3 * * @see Apfloat#formatTo(Formatter,int,int,int) */ @Override public void formatTo(Formatter formatter, int flags, int width, int precision) { if (imag().signum() == 0) { real().formatTo(formatter, flags, width, precision); } else { if (width == -1) { formatter.format("("); real().formatTo(formatter, flags, width, precision); formatter.format(", "); imag().formatTo(formatter, flags, width, precision); formatter.format(")"); } else { try { Writer out = FormattingHelper.wrapAppendableWriter(formatter.out()); out = FormattingHelper.wrapPadWriter(out, (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY); formatter = new Formatter(out, formatter.locale()); formatter.format("("); real().formatTo(formatter, flags, -1, precision); formatter.format(", "); imag().formatTo(formatter, flags, -1, precision); formatter.format(")"); FormattingHelper.finishPad(out, width); } catch (IOException ioe) { // Ignore as we can't propagate it; unfortunately we can't set it to the formattable either } } } } static final Apint[] ZEROS; static final Apint[] ONES; static { ZEROS = new Apint[37]; ONES = new Apint[37]; for (int i = 2; i <= 36; i++) { ZEROS[i] = new Apint(0, i); ONES[i] = new Apint(1, i); } ZEROS[ZERO.radix()] = ZERO; ONES[ONE.radix()] = ONE; } private static final long serialVersionUID = 3642932980384250551L; private Apfloat real; private Apfloat imag; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ApcomplexMath.java000066400000000000000000005603741461767713300251650ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.Queue; import java.util.function.Consumer; import java.util.function.Function; import java.util.PriorityQueue; import org.apfloat.spi.Util; /** * Various mathematical functions for arbitrary precision complex numbers. * * @see ApfloatMath * * @version 1.14.0 * @author Mikko Tommila */ public class ApcomplexMath { private ApcomplexMath() { } /** * Negative value. * * @deprecated Use {@link Apcomplex#negate()}. * * @param z The argument. * * @return -z. */ @Deprecated public static Apcomplex negate(Apcomplex z) throws ApfloatRuntimeException { return z.negate(); } /** * Absolute value. * * @param z The argument. * * @return sqrt(x2 + y2), where z = x + i y. */ public static Apfloat abs(Apcomplex z) throws ApfloatRuntimeException { if (z.real().signum() == 0) { return ApfloatMath.abs(z.imag()); } else if (z.imag().signum() == 0) { return ApfloatMath.abs(z.real()); } else { return ApfloatMath.sqrt(norm(z)); } } /** * Norm. Square of the magnitude. * * @param z The argument. * * @return x2 + y2, where z = x + i y. */ public static Apfloat norm(Apcomplex z) throws ApfloatRuntimeException { return ApfloatMath.multiplyAdd(z.real(), z.real(), z.imag(), z.imag()); } /** * Angle of the complex vector in the complex plane. * * @param z The argument. * * @return arctan(y / x) from the appropriate branch, where z = x + i y. * * @exception ArithmeticException If z is zero. */ public static Apfloat arg(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return ApfloatMath.atan2(z.imag(), z.real()); } /** * Multiply by a power of the radix. * * @param z The argument. * @param scale The scaling factor. * * @return z * z.radix()scale. */ public static Apcomplex scale(Apcomplex z, long scale) throws ApfloatRuntimeException { return new Apcomplex(ApfloatMath.scale(z.real(), scale), ApfloatMath.scale(z.imag(), scale)); } /** * Integer power. * * @param z Base of the power operator. * @param n Exponent of the power operator. * * @return z to the n:th power, that is zn. * * @exception ArithmeticException If both z and n are zero. */ public static Apcomplex pow(Apcomplex z, long n) throws ArithmeticException, ApfloatRuntimeException { if (n == 0) { if (z.isZero()) { throw new ArithmeticException("Zero to power zero"); } return new Apcomplex(new Apfloat(1, Apfloat.INFINITE, z.radix())); } else if (n < 0) { z = Apcomplex.ONES[z.radix()].divide(z); n = -n; } return powAbs(z, n); } // Absolute value of n used private static Apcomplex powAbs(Apcomplex z, long n) throws ArithmeticException, ApfloatRuntimeException { long precision = z.precision(); z = ApfloatHelper.extendPrecision(z); // Big exponents will accumulate round-off errors // Algorithm improvements by Bernd Kellner int b2pow = 0; while ((n & 1) == 0) { b2pow++; n >>>= 1; } Apcomplex r = z; while ((n >>>= 1) > 0) { z = z.multiply(z); if ((n & 1) != 0) { r = r.multiply(z); } } while (b2pow-- > 0) { r = r.multiply(r); } return ApfloatHelper.setPrecision(r, precision); } /** * Square root. * * @param z The argument. * * @return Square root of z. */ public static Apcomplex sqrt(Apcomplex z) throws ApfloatRuntimeException { return root(z, 2); } /** * Cube root. * * @param z The argument. * * @return Cube root of z. */ public static Apcomplex cbrt(Apcomplex z) throws ApfloatRuntimeException { return root(z, 3); } /** * Positive integer root. The branch that has the smallest angle * and same sign of imaginary part as z is always chosen. * * @param z The argument. * @param n Which root to take. * * @return n:th root of z, that is z1/n. * * @exception ArithmeticException If n is zero. */ public static Apcomplex root(Apcomplex z, long n) throws ArithmeticException, ApfloatRuntimeException { return root(z, n, 0); } /** * Positive integer root. The specified branch counting from the smallest angle * and same sign of imaginary part as z is chosen. * * @param z The argument. * @param n Which root to take. * @param k Which branch to take. * * @return n:th root of z, that is z1/nei2πsk/n where s is the signum of the imaginary part of z. * * @exception ArithmeticException If n is zero. * * @since 1.5 */ public static Apcomplex root(Apcomplex z, long n, long k) throws ArithmeticException, ApfloatRuntimeException { if (n == 0) { throw new ArithmeticException("Zeroth root"); } else if (z.isZero()) { if (n < 0) { throw new ArithmeticException("Inverse root of zero"); } return Apcomplex.ZEROS[z.radix()]; // Avoid division by zero } else if (n == 1) { return z; } k %= n; if (z.imag().signum() == 0 && z.real().signum() > 0 && k == 0) { return new Apcomplex(ApfloatMath.root(z.real(), n)); } else if (n < 0) // Also correctly handles 0x8000000000000000L { return inverseRootAbs(z, -n, k); } else if (n == 2) { return z.multiply(inverseRootAbs(z, 2, k)); } else if (n == 3) { // Choose the correct branch if (z.real().signum() < 0) { k = (z.imag().signum() == 0 ? 1 - k : k - 1); k %= n; } else { k = -k; } Apcomplex w = z.multiply(z); return z.multiply(inverseRootAbs(w, 3, k)); } else { return inverseRootAbs(inverseRootAbs(z, n, k), 1, 0); } } /** * Inverse positive integer root. The branch that has the smallest angle * and different sign of imaginary part than z is always chosen. * * @param z The argument. * @param n Which inverse root to take. * * @return Inverse n:th root of z, that is z-1/n. * * @exception ArithmeticException If z or n is zero. */ public static Apcomplex inverseRoot(Apcomplex z, long n) throws ArithmeticException, ApfloatRuntimeException { return inverseRoot(z, n, 0); } /** * Inverse positive integer root. The specified branch counting from the smallest angle * and different sign of imaginary part than z is chosen. * * @param z The argument. * @param n Which inverse root to take. * @param k Which branch to take. * * @return Inverse n:th root of z, that is z-1/ne-i2πk/n. * * @exception ArithmeticException If z or n is zero. */ public static Apcomplex inverseRoot(Apcomplex z, long n, long k) throws ArithmeticException, ApfloatRuntimeException { if (z.isZero()) { throw new ArithmeticException("Inverse root of zero"); } else if (n == 0) { throw new ArithmeticException("Inverse zeroth root"); } k %= n; if (z.imag().signum() == 0 && z.real().signum() > 0 && k == 0) { return new Apcomplex(ApfloatMath.inverseRoot(z.real(), n)); } else if (n < 0) { return inverseRootAbs(inverseRootAbs(z, -n, k), 1, 0); // Also correctly handles 0x8000000000000000L } return inverseRootAbs(z, n, k); } // Absolute value of n used private static Apcomplex inverseRootAbs(Apcomplex z, long n, long k) throws ArithmeticException, ApfloatRuntimeException { if (z.equals(Apcomplex.ONE) && k == 0) { // Trivial case return z; } else if (n == 2 && z.imag().signum() == 0 && z.real().signum() < 0) { // Avoid round-off errors and produce a pure imaginary result Apfloat y = ApfloatMath.inverseRoot(z.real().negate(), n); return new Apcomplex(Apfloat.ZEROS[z.radix()], k == 0 ? y.negate() : y); } long targetPrecision = z.precision(); if (targetPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate inverse root to infinite precision"); } Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), divisor = ApfloatMath.abs(new Apfloat(n, Apfloat.INFINITE, z.radix())); double doubleReal, doubleImag, magnitude, angle, doubleN = Math.abs((double) n); long realScale = z.real().scale(), imagScale = z.imag().scale(), scale = Math.max(realScale, imagScale), scaleDiff = scale - Math.min(realScale, imagScale), doublePrecision = ApfloatHelper.getDoublePrecision(z.radix()), precision = doublePrecision, // Accuracy of initial guess scaleQuot = scale / n, // If n is 0x8000000000000000 then this will be zero scaleRem = scale - scaleQuot * n; double scaleRemFactor = Math.pow((double) z.radix(), (double) -scaleRem / doubleN); Apcomplex result; // Calculate initial guess from z if (z.imag().signum() == 0 || (scaleDiff > doublePrecision / 2 || scaleDiff < 0) && realScale > imagScale) // Detect overflow { // z.real() is a lot bigger in magnitude than z.imag() Apfloat tmpReal = z.real().precision(doublePrecision), tmpImag = z.imag().precision(doublePrecision); Apcomplex tweak = new Apcomplex(Apfloat.ZERO, tmpImag.divide(divisor.multiply(tmpReal))); tmpReal = ApfloatMath.scale(tmpReal, -tmpReal.scale()); // Allow exponents in excess of doubles' if ((magnitude = tmpReal.doubleValue()) >= 0.0) { doubleReal = Math.pow(magnitude, -1.0 / doubleN) * scaleRemFactor; doubleImag = 0.0; } else { magnitude = Math.pow(-magnitude, -1.0 / doubleN) * scaleRemFactor; angle = (tmpImag.signum() >= 0 ? -Math.PI : Math.PI) / doubleN; doubleReal = magnitude * Math.cos(angle); doubleImag = magnitude * Math.sin(angle); } tmpReal = ApfloatMath.scale(new Apfloat(doubleReal, doublePrecision, z.radix()), -scaleQuot); tmpImag = ApfloatMath.scale(new Apfloat(doubleImag, doublePrecision, z.radix()), -scaleQuot); result = new Apcomplex(tmpReal, tmpImag); result = result.subtract(result.multiply(tweak)); // Must not be real } else if (z.real().signum() == 0 || (scaleDiff > doublePrecision / 2 || scaleDiff < 0) && imagScale > realScale) // Detect overflow { // z.imag() is a lot bigger in magnitude than z.real() Apfloat tmpReal = z.real().precision(doublePrecision), tmpImag = z.imag().precision(doublePrecision); Apcomplex tweak = new Apcomplex(Apfloat.ZERO, tmpReal.divide(divisor.multiply(tmpImag))); tmpImag = ApfloatMath.scale(tmpImag, -tmpImag.scale()); // Allow exponents in exess of doubles' if ((magnitude = tmpImag.doubleValue()) >= 0.0) { magnitude = Math.pow(magnitude, -1.0 / doubleN) * scaleRemFactor; angle = -Math.PI / (2.0 * doubleN); } else { magnitude = Math.pow(-magnitude, -1.0 / doubleN) * scaleRemFactor; angle = Math.PI / (2.0 * doubleN); } doubleReal = magnitude * Math.cos(angle); doubleImag = magnitude * Math.sin(angle); tmpReal = ApfloatMath.scale(new Apfloat(doubleReal, doublePrecision, z.radix()), -scaleQuot); tmpImag = ApfloatMath.scale(new Apfloat(doubleImag, doublePrecision, z.radix()), -scaleQuot); result = new Apcomplex(tmpReal, tmpImag); result = result.add(result.multiply(tweak)); // Must not be pure imaginary } else { // z.imag() and z.real() approximately the same in magnitude Apfloat tmpReal = z.real().precision(doublePrecision), tmpImag = z.imag().precision(doublePrecision); tmpReal = ApfloatMath.scale(tmpReal, -scale); // Allow exponents in exess of doubles' tmpImag = ApfloatMath.scale(tmpImag, -scale); // Allow exponents in exess of doubles' doubleReal = tmpReal.doubleValue(); doubleImag = tmpImag.doubleValue(); magnitude = Math.pow(doubleReal * doubleReal + doubleImag * doubleImag, -1.0 / (2.0 * doubleN)) * scaleRemFactor; angle = -Math.atan2(doubleImag, doubleReal) / doubleN; doubleReal = magnitude * Math.cos(angle); doubleImag = magnitude * Math.sin(angle); tmpReal = ApfloatMath.scale(new Apfloat(doubleReal, doublePrecision, z.radix()), -scaleQuot); tmpImag = ApfloatMath.scale(new Apfloat(doubleImag, doublePrecision, z.radix()), -scaleQuot); result = new Apcomplex(tmpReal, tmpImag); } // Alter the angle by the branch chosen if (k != 0) { Apcomplex branch; // Handle exact cases k = (k < 0 ? k + n : k); if (n % 4 == 0 && (n >>> 2) == k) { branch = new Apcomplex(Apfloat.ZERO, one); } else if (n % 4 == 0 && (n >>> 2) * 3 == k) { branch = new Apcomplex(Apfloat.ZERO, one.negate()); } else if (n % 2 == 0 && (n >>> 1) == k) { branch = one.negate(); } else { angle = 2.0 * Math.PI * (double) k / doubleN; doubleReal = Math.cos(angle); doubleImag = Math.sin(angle); Apfloat tmpReal = new Apfloat(doubleReal, doublePrecision, z.radix()); Apfloat tmpImag = new Apfloat(doubleImag, doublePrecision, z.radix()); branch = new Apcomplex(tmpReal, tmpImag); } result = result.multiply(z.imag().signum() >= 0 ? branch.conj() : branch); } int iterations = 0; // Compute total number of iterations for (long maxPrec = precision; maxPrec < targetPrecision; maxPrec <<= 1) { iterations++; } int precisingIteration = iterations; // Check where the precising iteration should be done for (long minPrec = precision; precisingIteration > 0; precisingIteration--, minPrec <<= 1) { if ((minPrec - Apcomplex.EXTRA_PRECISION) << precisingIteration >= targetPrecision) { break; } } z = ApfloatHelper.extendPrecision(z); // Newton's iteration while (iterations-- > 0) { precision *= 2; result = ApfloatHelper.setPrecision(result, Math.min(precision, targetPrecision)); Apcomplex t = powAbs(result, n); t = lastIterationExtendPrecision(iterations, precisingIteration, t); t = one.subtract(z.multiply(t)); if (iterations < precisingIteration) { t = new Apcomplex(t.real().precision(precision / 2), t.imag().precision(precision / 2)); } result = lastIterationExtendPrecision(iterations, precisingIteration, result); result = result.add(result.multiply(t).divide(divisor)); // Precising iteration if (iterations == precisingIteration) { t = powAbs(result, n); t = lastIterationExtendPrecision(iterations, -1, t); result = lastIterationExtendPrecision(iterations, -1, result); result = result.add(result.multiply(one.subtract(z.multiply(t))).divide(divisor)); } } return ApfloatHelper.setPrecision(result, targetPrecision); } /** * All values of the positive integer root.

* * Returns all of the n values of the root, in the order * of the angle, starting from the smallest angle and same sign of * imaginary part as z. * * @param z The argument. * @param n Which root to take. * * @return All values of the n:th root of z, that is z1/n, in the order of the angle. * * @exception ArithmeticException If n is zero. * * @since 1.5 */ public static Apcomplex[] allRoots(Apcomplex z, int n) throws ArithmeticException, ApfloatRuntimeException { if (n == 0) { throw new ArithmeticException("Zeroth root"); } else if (n == 1) { return new Apcomplex[] { z }; } else if (n == 0x80000000) { throw new ApfloatRuntimeException("Maximum array size exceeded"); } else if (z.isZero()) { if (n < 0) { throw new ArithmeticException("Inverse root of zero"); } Apcomplex[] allRoots = new Apcomplex[n]; Arrays.fill(allRoots, Apcomplex.ZEROS[z.radix()]); return allRoots; // Avoid division by zero } boolean inverse = (n < 0); n = Math.abs(n); long precision = z.precision(); z = ApfloatHelper.extendPrecision(z); // Big roots will accumulate round-off errors Apcomplex w = inverseRootAbs(new Apfloat(1, precision, z.radix()), n, 1); w = (z.imag().signum() >= 0 ^ inverse ? w.conj() : w); // Complex n:th root of unity Apcomplex[] allRoots = new Apcomplex[n]; Apcomplex root = (inverse ? inverseRootAbs(z, n, 0) : root(z, n)); allRoots[0] = ApfloatHelper.setPrecision(root, precision); for (int i = 1; i < n; i++) { root = root.multiply(w); allRoots[i] = ApfloatHelper.setPrecision(root, precision); } return allRoots; } /** * Arithmetic-geometric mean. * * @param a First argument. * @param b Second argument. * * @return Arithmetic-geometric mean of a and b. */ public static Apcomplex agm(Apcomplex a, Apcomplex b) throws ApfloatRuntimeException { return agm(a, b, null); } static Apcomplex agm(Apcomplex a, Apcomplex b, Consumer consumer) throws ApfloatRuntimeException { if (a.isZero() || b.isZero()) // Would not converge quadratically { return Apcomplex.ZEROS[a.radix()]; } if (a.real().signum() == b.real().signum() && a.imag().signum() == 0 && b.imag().signum() == 0) { return ApfloatMath.agm(a.real(), b.real(), consumer == null ? null : consumer::accept); } if (a.equals(b)) // Thanks to Marko Gaspersic for finding several bugs in issue #12 { return a.precision(Math.min(a.precision(), b.precision())); } if (a.equals(b.negate())) // Would not converge quadratically { return Apcomplex.ZEROS[a.radix()]; } long workingPrecision = Math.min(a.precision(), b.precision()), targetPrecision = workingPrecision; if (workingPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate agm to infinite precision"); } // Some minimum precision is required for the algorithm to work workingPrecision = ApfloatHelper.extendPrecision(workingPrecision); a = ApfloatHelper.ensurePrecision(a, workingPrecision); b = ApfloatHelper.ensurePrecision(b, workingPrecision); long precision = 0, halfWorkingPrecision = (workingPrecision + 1) / 2; final long CONVERGING = 1000; // Arbitrarily chosen value... Apfloat two = new Apfloat(2, Apfloat.INFINITE, a.radix()); Apcomplex c2 = null; if (consumer != null) { c2 = ApfloatHelper.ensurePrecision(a.multiply(a).subtract(b.multiply(b)), workingPrecision); consumer.accept(c2); } // First check convergence while (precision < CONVERGING && precision < halfWorkingPrecision) { Apcomplex t = limitPrecision(a.add(b)).divide(two); b = rightSqrt(a.multiply(b), t); a = t; // Conserve precision in case of accumulating round-off errors a = ApfloatHelper.ensurePrecision(a, workingPrecision); b = ApfloatHelper.ensurePrecision(b, workingPrecision); precision = a.equalDigits(b); c2 = agmConsume(consumer, a, c2, workingPrecision); } // Now we know quadratic convergence while (precision <= halfWorkingPrecision) { Apcomplex t = a.add(b).divide(two); b = rightSqrt(a.multiply(b), t); a = t; // Conserve precision in case of accumulating round-off errors a = ApfloatHelper.ensurePrecision(a, workingPrecision); b = ApfloatHelper.ensurePrecision(b, workingPrecision); precision *= 2; c2 = agmConsume(consumer, a, c2, workingPrecision); } Apcomplex result = a.add(b).divide(two); agmConsume(consumer, result, c2, workingPrecision); return ApfloatHelper.setPrecision(result, targetPrecision); } private static Apcomplex limitPrecision(Apcomplex z) { return z.precision(z.precision()); } private static Apcomplex rightSqrt(Apcomplex z, Apcomplex reference) { // See D. A. Cox, "The Arithmetic-Geometric Mean of Gauss", L'Enseignement Mathematique, Vol. 30, 1984, pp. 275-330 // or for example Tomack Gilmore's paper about it: https://homepage.univie.ac.at/tomack.gilmore/papers/Agm.pdf // 1. norm(a1 - b1) <= norm(a1 + b1) // 2. If norm(a1 - b1) = norm(a1 + b1) then imag(b1 / a1) > 0 Apcomplex result = sqrt(z); // First compare norms with low precision int doublePrecision = ApfloatHelper.getDoublePrecision(z.radix()); Apcomplex approxResult = result.precision(doublePrecision); Apcomplex approxReference = reference.precision(doublePrecision); int comparison = norm(approxReference.subtract(approxResult)).compareTo(norm(approxReference.add(approxResult))); if (comparison == 0) { // Full precision comparison as they are equal to low precision comparison = norm(reference.subtract(result)).compareTo(norm(reference.add(result))); } if (comparison > 0 || comparison == 0 && result.divide(reference).imag().signum() <= 0) { result = result.negate(); } return result; } private static Apcomplex agmConsume(Consumer consumer, Apcomplex a, Apcomplex c2, long workingPrecision) { if (consumer != null) { Apfloat four = new Apfloat(4, Apfloat.INFINITE, a.radix()); Apcomplex c = ApfloatHelper.ensurePrecision(c2.divide(four.multiply(a)), workingPrecision); c2 = ApfloatHelper.ensurePrecision(c.multiply(c), workingPrecision); consumer.accept(c2); } return c2; } /** * Natural logarithm.

* * The logarithm is calculated using the arithmetic-geometric mean. * See the Borweins' book for the formula. * * @param z The argument. * * @return Natural logarithm of z. * * @exception ArithmeticException If z is zero. */ public static Apcomplex log(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (z.imag().signum() == 0) { if (z.real().signum() >= 0) { return ApfloatMath.log(z.real()); } return new Apcomplex(ApfloatMath.log(z.real().negate()), ApfloatMath.pi(z.precision(), z.radix())); } // Calculate the log using 1 / radix <= |z| < 1 and the log addition formula // because the agm converges badly for big z long targetPrecision = z.precision(); if (targetPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate logarithm to infinite precision"); } // If the absolute value of the argument is very big, the result is more accurate Apfloat x = abs(z); if (x.scale() > 1) { double logScale = Math.log((double) x.scale() - 1) / Math.log((double) x.radix()); logScale += Math.ulp(logScale); targetPrecision = Util.ifFinite(targetPrecision, targetPrecision + (long) logScale); } Apfloat imagBias; // Scale z so that real part of z is always >= 0, that is its angle is -pi/2 <= angle(z) <= pi/2 to avoid possible instability near z.imag() = +-pi if (z.real().signum() < 0) { Apfloat pi = ApfloatHelper.extendPrecision(ApfloatMath.pi(targetPrecision, z.radix()), z.radix() <= 3 ? 1 : 0); // pi may have 1 digit more than pi/2 if (z.imag().signum() >= 0) { imagBias = pi; } else { imagBias = pi.negate(); } z = z.negate(); } else { // No bias imagBias = Apfloat.ZERO; } Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()); long originalScale = z.scale(); z = scale(z, -originalScale); // Set z's scale to zero Apfloat radixPower; if (originalScale == 0) { radixPower = Apfloat.ZERO; } else { Apfloat logRadix = ApfloatHelper.extendPrecision(ApfloatMath.logRadix(targetPrecision, z.radix())); radixPower = new Apfloat(originalScale, Apfloat.INFINITE, z.radix()).multiply(logRadix); } Apcomplex result = ApfloatHelper.extendPrecision(rawLog(z)).add(radixPower); // If the absolute value of the argument is close to 1, the real part of the result is less accurate // If the angle of the argument is close to zero, the imaginary part of the result is less accurate long finalRealPrecision = Math.max(targetPrecision - one.equalDigits(x), 1), finalImagPrecision = Math.max(targetPrecision - 1 + result.imag().scale(), 1); // Scale of pi/2 is always 1 return new Apcomplex(result.real().precision(finalRealPrecision), result.imag().precision(finalImagPrecision).add(imagBias)); } /** * Logarithm in arbitrary base.

* * @param z The argument. * @param w The base. * * @return Base-w logarithm of z. * * @exception ArithmeticException If z or w is zero. * * @since 1.6 */ public static Apcomplex log(Apcomplex z, Apcomplex w) throws ArithmeticException, ApfloatRuntimeException { if (z.real().signum() >= 0 && z.imag().signum() == 0 && w.real().signum() >= 0 && w.imag().signum() == 0) { return ApfloatMath.log(z.real(), w.real()); } long targetPrecision = Math.min(z.precision(), w.precision()); if (z.real().signum() >= 0 && z.imag().signum() == 0) { Apfloat x = z.real(); Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); targetPrecision = Util.ifFinite(targetPrecision, targetPrecision + one.equalDigits(x)); // If the log() argument is close to 1, the result is less accurate x = x.precision(Math.min(x.precision(), targetPrecision)); return ApfloatMath.log(x).divide(log(w)); } else if (w.real().signum() >= 0 && w.imag().signum() == 0) { Apfloat y = w.real(); Apfloat one = new Apfloat(1, Apfloat.INFINITE, y.radix()); targetPrecision = Util.ifFinite(targetPrecision, targetPrecision + one.equalDigits(y)); // If the log() argument is close to 1, the result is less accurate y = y.precision(Math.min(y.precision(), targetPrecision)); return log(z).divide(ApfloatMath.log(y)); } else { return log(z).divide(log(w)); } } // Raw logarithm, regardless of z // Doesn't work for really big z, but is faster if used alone for small numbers private static Apcomplex rawLog(Apcomplex z) throws ApfloatRuntimeException { assert (!z.isZero()); // Infinity Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()); final int EXTRA_PRECISION = 25; long targetPrecision = z.precision(), workingPrecision = ApfloatHelper.extendPrecision(targetPrecision), n = targetPrecision / 2 + EXTRA_PRECISION; // Very rough estimate z = ApfloatHelper.extendPrecision(z, EXTRA_PRECISION); Apfloat e = one.precision(workingPrecision); e = ApfloatMath.scale(e, -n); z = scale(z, -n); Apfloat agme = ApfloatHelper.extendPrecision(ApfloatMath.agm(one, e)); Apcomplex agmez = ApfloatHelper.extendPrecision(agm(one, z)); Apfloat pi = ApfloatHelper.extendPrecision(ApfloatMath.pi(targetPrecision, z.radix())); Apcomplex log = pi.multiply(agmez.subtract(agme)).divide(new Apfloat(2, Apfloat.INFINITE, z.radix()).multiply(agme).multiply(agmez)); return ApfloatHelper.setPrecision(log, targetPrecision); } /** * Exponent function. * Calculated using Newton's iteration for the inverse of logarithm. * * @param z The argument. * * @return ez. */ public static Apcomplex exp(Apcomplex z) throws ApfloatRuntimeException { if (z.imag().signum() == 0) { return ApfloatMath.exp(z.real()); } int radix = z.radix(); Apfloat one = new Apfloat(1, Apfloat.INFINITE, radix); long doublePrecision = ApfloatHelper.getDoublePrecision(radix); if (z.real().compareTo(new Apfloat(Long.MIN_VALUE * Math.log((double) radix), doublePrecision, radix)) <= 0) { // Underflow return Apcomplex.ZEROS[z.radix()]; } // If the real part of the argument is close to 0, the result is more accurate; if it's very big the result is less accurate if (z.real().precision() < z.real().scale() - 1) { throw new LossOfPrecisionException("Complete loss of accurate digits in real part"); } // The imaginary part must be scaled to the range of -pi ... pi, which may limit the precision if (z.imag().precision() < z.imag().scale()) { throw new LossOfPrecisionException("Complete loss of accurate digits in imaginary part"); } long realPrecision = Util.ifFinite(z.real().precision(), z.real().precision() + 1 - z.real().scale()), imagPrecision = Util.ifFinite(z.imag().precision(), 1 + z.imag().precision() - z.imag().scale()), targetPrecision = Math.min(realPrecision, imagPrecision); if (targetPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate exponent to infinite precision"); } else if (z.real().compareTo(new Apfloat((double) Long.MAX_VALUE * Math.log((double) radix), doublePrecision, radix)) >= 0) { throw new OverflowException("Overflow"); } boolean negateResult = false; // If the final result is to be negated Apfloat zImag; if (z.imag().scale() > 0) { long piPrecision = Util.ifFinite(targetPrecision, targetPrecision + z.imag().scale()); Apfloat pi = ApfloatMath.pi(piPrecision, radix), // This is precalculated for initial check only twoPi = pi.add(pi), halfPi = pi.divide(new Apfloat(2, targetPrecision, radix)); // Scale z so that -pi < z.imag() <= pi zImag = ApfloatMath.fmod(z.imag(), twoPi); if (zImag.compareTo(pi) > 0) { zImag = zImag.subtract(twoPi); } else if (zImag.compareTo(pi.negate()) <= 0) { zImag = zImag.add(twoPi); } // More, scale z so that -pi/2 < z.imag() <= pi/2 to avoid instability near z.imag() = +-pi if (zImag.compareTo(halfPi) > 0) { // exp(z - i*pi) = exp(z)/exp(i*pi) = -exp(z) zImag = zImag.subtract(pi); negateResult = true; } else if (zImag.compareTo(halfPi.negate()) <= 0) { // exp(z + i*pi) = exp(z)*exp(i*pi) = -exp(z) zImag = zImag.add(pi); negateResult = true; } } else { // No need to scale the imaginary part since it's small, -pi/2 < z.imag() <= pi/2 zImag = z.imag(); } z = new Apcomplex(z.real(), zImag); Apfloat resultReal; Apcomplex resultImag; // First handle the real part if (z.real().signum() == 0) { resultReal = one; } else if (z.real().scale() < -doublePrecision / 2) { // Taylor series: exp(x) = 1 + x + x^2/2 + ... long precision = Util.ifFinite(-z.real().scale(), -2 * z.real().scale()); resultReal = one.precision(precision).add(z.real()); } else { // Approximate starting value for iteration // An overflow or underflow should not occur long scaledRealPrecision = Math.max(0, z.real().scale()) + doublePrecision; Apfloat logRadix = ApfloatMath.log(new Apfloat((double) radix, scaledRealPrecision, radix)), scaledReal = z.real().precision(scaledRealPrecision).divide(logRadix), integerPart = scaledReal.truncate(), fractionalPart = scaledReal.frac(); resultReal = new Apfloat(Math.pow((double) radix, fractionalPart.doubleValue()), doublePrecision, radix); resultReal = ApfloatMath.scale(resultReal, integerPart.longValue()); if (resultReal.signum() == 0) { // Underflow return Apcomplex.ZEROS[z.radix()]; } } // Then handle the imaginary part if (zImag.signum() == 0) { // Imaginary part may have been reduced to zero e.g. if it was exactly pi resultImag = one; } else if (zImag.scale() < -doublePrecision / 2) { // Taylor series: exp(z) = 1 + z + z^2/2 + ... long precision = Util.ifFinite(-zImag.scale(), -2 * zImag.scale()); resultImag = new Apcomplex(one.precision(precision), zImag.precision(-zImag.scale())); } else { // Approximate starting value for iteration double doubleImag = zImag.doubleValue(); resultImag = new Apcomplex(new Apfloat(Math.cos(doubleImag), doublePrecision, radix), new Apfloat(Math.sin(doubleImag), doublePrecision, radix)); } // Starting value is (real part starting value) * (imag part starting value) Apcomplex result = resultReal.multiply(resultImag); long precision = result.precision(); // Accuracy of initial guess int iterations = 0; // Compute total number of iterations for (long maxPrec = precision; maxPrec < targetPrecision; maxPrec <<= 1) { iterations++; } int precisingIteration = iterations; // Check where the precising iteration should be done for (long minPrec = precision; precisingIteration > 0; precisingIteration--, minPrec <<= 1) { if ((minPrec - Apcomplex.EXTRA_PRECISION) << precisingIteration >= targetPrecision) { break; } } if (iterations > 0) { // Precalculate the needed values once to the required precision ApfloatMath.logRadix(targetPrecision, radix); } z = ApfloatHelper.extendPrecision(z); // Newton's iteration while (iterations-- > 0) { precision *= 2; result = ApfloatHelper.setPrecision(result, Math.min(precision, targetPrecision)); Apcomplex t = log(result); t = lastIterationExtendPrecision(iterations, precisingIteration, t); t = z.subtract(t); if (iterations < precisingIteration) { t = new Apcomplex(t.real().precision(precision / 2), t.imag().precision(precision / 2)); } result = lastIterationExtendPrecision(iterations, precisingIteration, result); result = result.add(result.multiply(t)); // Precising iteration if (iterations == precisingIteration) { t = log(result); t = lastIterationExtendPrecision(iterations, -1, t); result = lastIterationExtendPrecision(iterations, -1, result); result = result.add(result.multiply(z.subtract(t))); } } return ApfloatHelper.setPrecision(negateResult ? result.negate() : result, targetPrecision); } /** * Arbitrary power. Calculated using log() and exp().

* * @param z The base. * @param w The exponent. * * @return zw. * * @exception ArithmeticException If both z and w are zero. */ public static Apcomplex pow(Apcomplex z, Apcomplex w) throws ApfloatRuntimeException { long targetPrecision = Math.min(z.precision(), w.precision()); Apcomplex result = ApfloatHelper.checkPow(z, w, targetPrecision); if (result != null) { return result; } if (z.real().signum() >= 0 && z.imag().signum() == 0) { Apfloat x = z.real(); // Limits precision for log() but may be sub-optimal; precision could be limited more Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); targetPrecision = Util.ifFinite(targetPrecision, targetPrecision + one.equalDigits(x)); // If the log() argument is close to 1, the result is less accurate x = x.precision(Math.min(x.precision(), targetPrecision)); return exp(w.multiply(ApfloatMath.log(x))); } else { return exp(w.multiply(log(z))); } } /** * Inverse cosine. Calculated using log(). * * @param z The argument. * * @return Inverse cosine of z. */ public static Apcomplex acos(Apcomplex z) throws ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()); if (z.imag().signum() == 0 && ApfloatMath.abs(z.real()).compareTo(one) <= 0) { return ApfloatMath.acos(z.real()); } Apcomplex i = new Apcomplex(Apfloat.ZERO, one), w = i.multiply(log(z.add(sqrt(z.multiply(z).subtract(one))))); if (z.real().signum() < 0 && z.imag().signum() == 0) { return new Apcomplex(w.real().negate(), w.imag()); } else if (z.real().signum() * z.imag().signum() > 0 || z.real().signum() == 0) { return w.negate(); } else { return w; } } static Apcomplex acos(Apcomplex z, long precision) { if (z.isZero()) { return ApfloatMath.halfPi(z.radix(), precision); } return acos(z); } /** * Inverse hyperbolic cosine. Calculated using log(). * * @param z The argument. * * @return Inverse hyperbolic cosine of z. */ public static Apcomplex acosh(Apcomplex z) throws ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()); if (z.real().signum() > 0 || z.real().signum() == 0 && z.imag().signum() >= 0) { return log(z.add(sqrt(z.multiply(z).subtract(one)))); } else { return log(z.subtract(sqrt(z.multiply(z).subtract(one)))); } } static Apcomplex acosh(Apcomplex z, long precision) { if (z.isZero()) { return new Apcomplex(Apfloat.ZEROS[z.radix()], ApfloatMath.halfPi(z.radix(), precision)); } return acosh(z); } /** * Inverse sine. Calculated using log(). * * @param z The argument. * * @return Inverse sine of z. */ public static Apcomplex asin(Apcomplex z) throws ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()); if (z.imag().signum() == 0 && ApfloatMath.abs(z.real()).compareTo(one) <= 0) { return ApfloatMath.asin(z.real()); } Apcomplex i = new Apcomplex(Apfloat.ZERO, one); if (z.imag().signum() >= 0) { return i.multiply(log(sqrt(one.subtract(z.multiply(z))).subtract(i.multiply(z)))); } else { return i.multiply(log(i.multiply(z).add(sqrt(one.subtract(z.multiply(z)))))).negate(); } } /** * Inverse hyperbolic sine. Calculated using log(). * * @param z The argument. * * @return Inverse hyperbolic sine of z. */ public static Apcomplex asinh(Apcomplex z) throws ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()); if (z.real().signum() >= 0) { return log(sqrt(z.multiply(z).add(one)).add(z)); } else { return log(sqrt(z.multiply(z).add(one)).subtract(z)).negate(); } } /** * Inverse tangent. Calculated using log(). * * @param z The argument. * * @return Inverse tangent of z. * * @exception ArithmeticException If z == i. */ public static Apcomplex atan(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (z.imag().signum() == 0) { return ApfloatMath.atan(z.real()); } Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), two = new Apfloat(2, Apfloat.INFINITE, z.radix()); Apcomplex i = new Apcomplex(Apfloat.ZERO, one), w = log(i.add(z).divide(i.subtract(z))).multiply(i).divide(two); if (z.real().signum() == 0 && z.imag().signum() > 0) { return new Apcomplex(w.real().negate(), w.imag()); } else { return w; } } /** * Inverse hyperbolic tangent. Calculated using log(). * * @param z The argument. * * @return Inverse hyperbolic tangent of z. * * @exception ArithmeticException If z is 1 or -1. */ public static Apcomplex atanh(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), two = new Apfloat(2, Apfloat.INFINITE, z.radix()); Apcomplex w = log(one.add(z).divide(one.subtract(z))).divide(two); if (z.real().signum() > 0 && z.imag().signum() == 0) { return w.conj(); } else { return w; } } /** * Cosine. Calculated using exp(). * * @param z The argument. * * @return Cosine of z. */ public static Apcomplex cos(Apcomplex z) throws ApfloatRuntimeException { if (z.imag().signum() == 0) { return ApfloatMath.cos(z.real()); } Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), two = new Apfloat(2, Apfloat.INFINITE, z.radix()); Apcomplex i = new Apcomplex(Apfloat.ZERO, one), w = exp(i.multiply(z)); return (w.add(one.divide(w))).divide(two); } /** * Hyperbolic cosine. Calculated using exp(). * * @param z The argument. * * @return Hyperbolic cosine of z. */ public static Apcomplex cosh(Apcomplex z) throws ApfloatRuntimeException { if (z.imag().signum() == 0) { return ApfloatMath.cosh(z.real()); } Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), two = new Apfloat(2, Apfloat.INFINITE, z.radix()); Apcomplex w = exp(z); return (w.add(one.divide(w))).divide(two); } /** * Sine. Calculated using exp(). * * @param z The argument. * * @return Sine of z. */ public static Apcomplex sin(Apcomplex z) throws ApfloatRuntimeException { if (z.imag().signum() == 0) { return ApfloatMath.sin(z.real()); } Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), two = new Apfloat(2, Apfloat.INFINITE, z.radix()); Apcomplex i = new Apcomplex(Apfloat.ZERO, one), w = exp(i.multiply(z)); return one.divide(w).subtract(w).multiply(i).divide(two); } /** * Hyperbolic sine. Calculated using exp(). * * @param z The argument. * * @return Hyperbolic sine of z. */ public static Apcomplex sinh(Apcomplex z) throws ApfloatRuntimeException { if (z.imag().signum() == 0) { return ApfloatMath.sinh(z.real()); } Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), two = new Apfloat(2, Apfloat.INFINITE, z.radix()); Apcomplex w = exp(z); return (w.subtract(one.divide(w))).divide(two); } /** * Tangent. Calculated using exp(). * * @param z The argument. * * @return Tangent of z. * * @exception ArithmeticException If z is π/2 + n π where n is an integer. */ public static Apcomplex tan(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return tan(z, z.imag().signum() < 0); } static Apcomplex tanFixedPrecision(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return tan(z, z.imag().signum() > 0); } static Apcomplex tan(Apcomplex z, boolean negate) throws ArithmeticException, ApfloatRuntimeException { if (z.imag().signum() == 0) { return ApfloatMath.tan(z.real()); } z = (negate ? z.negate() : z); Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), two = new Apfloat(2, Apfloat.INFINITE, z.radix()); Apcomplex i = new Apcomplex(Apfloat.ZERO, one), w = exp(two.multiply(i).multiply(z)); w = i.multiply(one.subtract(w)).divide(one.add(w)); return (negate ? w.negate() : w); } /** * Hyperbolic tangent. Calculated using exp(). * * @param z The argument. * * @return Hyperbolic tangent of z. * * @exception ArithmeticException If z is i (π/2 + n π) where n is an integer. */ public static Apcomplex tanh(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return tanh(z, z.real().signum() > 0); } static Apcomplex tanhFixedPrecision(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return tanh(z, z.real().signum() < 0); } private static Apcomplex tanh(Apcomplex z, boolean negate) throws ArithmeticException, ApfloatRuntimeException { if (z.imag().signum() == 0) { return ApfloatMath.tanh(z.real()); } z = (negate ? z.negate() : z); Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), two = new Apfloat(2, Apfloat.INFINITE, z.radix()); Apcomplex w = exp(two.multiply(z)); w = w.subtract(one).divide(w.add(one)); return (negate ? w.negate() : w); } static Apcomplex cot(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { boolean negate = z.imag().signum() < 0; z = (negate ? z.negate() : z); Apfloat one = new Apfloat(1, Apfloat.INFINITE, z.radix()), two = new Apfloat(2, Apfloat.INFINITE, z.radix()); Apcomplex i = new Apcomplex(Apfloat.ZERO, one), w = expNoLoP(two.multiply(i).multiply(z)); w = i.multiply(two.multiply(w).divide(w.subtract(one)).subtract(one)); return (negate ? w.negate() : w); } /** * Sinc. * * @param z The argument. * * @return sinc(z) * * @since 1.14.0 */ public static Apcomplex sinc(Apcomplex z) throws ApfloatRuntimeException { if (z.isZero()) { return Apcomplex.ONES[z.radix()]; } return sin(z).divide(z); } /** * Lambert W function. The W function gives the solution to the equation * W eW = z. Also known as the product logarithm.

* * This function gives the solution to the principal branch, W0. * * @param z The argument. * * @return W0(z). * * @since 1.8.0 */ public static Apcomplex w(Apcomplex z) throws ApfloatRuntimeException { return LambertWHelper.w(z); } /** * Lambert W function for the specified branch.

* * @param z The argument. * @param k The branch. * * @return Wk(z). * * @exception ArithmeticException If z is zero and k is not zero. * * @see #w(Apcomplex) * * @since 1.8.0 */ public static Apcomplex w(Apcomplex z, long k) throws ArithmeticException, ApfloatRuntimeException { return LambertWHelper.w(z, k); } /** * Product of numbers. * The precision used in the multiplications is only * what is needed for the end result. This method may * perform significantly better than simply multiplying * the numbers sequentially.

* * If there are no arguments, the return value is 1. * * @param z The argument(s). * * @return The product of the given numbers. * * @since 1.3 */ public static Apcomplex product(Apcomplex... z) throws ApfloatRuntimeException { if (z.length == 0) { return Apcomplex.ONE; } // Determine working precision long maxPrec = Apcomplex.INFINITE; for (int i = 0; i < z.length; i++) { if (z[i].real().signum() == 0 && z[i].imag().signum() == 0) { return Apcomplex.ZEROS[z[i].radix()]; } maxPrec = Math.min(maxPrec, z[i].precision()); } // Do not use z.clone() as the array might be of some subclass type, resulting in ArrayStoreException later Apcomplex[] tmp = new Apcomplex[z.length]; // Add sqrt length digits for round-off errors long extraPrec = (long) Math.sqrt((double) z.length), destPrec = ApfloatHelper.extendPrecision(maxPrec, extraPrec); for (int i = 0; i < z.length; i++) { tmp[i] = z[i].precision(destPrec); } z = tmp; // Create a heap, ordered by size Queue heap = new PriorityQueue<>(z.length, Comparator.comparing(Apcomplex::size)); // Perform the multiplications in parallel ParallelHelper.ProductKernel kernel = (h) -> { Apcomplex a = h.remove(); Apcomplex b = h.remove(); Apcomplex c = a.multiply(b); h.add(c); }; ParallelHelper.parallelProduct(z, heap, kernel); return ApfloatHelper.setPrecision(heap.remove(), maxPrec); } /** * Sum of numbers. * The precision used in the additions is only * what is needed for the end result. This method may * perform significantly better than simply adding * the numbers sequentially.

* * If there are no arguments, the return value is 0. * * @param z The argument(s). * * @return The sum of the given numbers. * * @since 1.3 */ public static Apcomplex sum(Apcomplex... z) throws ApfloatRuntimeException { if (z.length == 0) { return Apcomplex.ZERO; } Apfloat[] x = new Apfloat[z.length], y = new Apfloat[z.length]; for (int i = 0; i < z.length; i++) { x[i] = z[i].real(); y[i] = z[i].imag(); } return new Apcomplex(ApfloatMath.sum(x), ApfloatMath.sum(y)); } /** * Gamma function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the gamma function. * * @param z The argument. * * @return Γ(z) * * @throws ArithmeticException If z is a nonpositive integer. * * @since 1.9.0 */ public static Apcomplex gamma(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { // Implementation note: the ck are actually constant (wrt. to precision and radix) so we could cache them, // however since this is a slow algorithm, the factors ck would take up quite a lot of space, and would not // improve the asymptotic complexity, so it's not really worth it - this function is anyway only useful for // a few thousand digits of precision, no matter of what optimization we might try. if (z.equals(Apfloat.ONE)) { return z; } long precision = z.precision(); int radix = z.radix(); Apint one = new Apint(1, radix); if (z.scale() < -precision) { return one.divide(z); } if (z.imag().signum() == 0) { if (z.real().signum() == 0) { throw new ArithmeticException("Gamma of zero"); } if (z.real().isInteger()) { if (z.real().signum() < 0) { throw new ArithmeticException("Gamma of negative integer"); } long n = ApfloatHelper.longValueExact(z.real().truncate()); // If n is extremely large and precision is relatively low, then computing it as gamma is faster // If n is relatively small compared to precision, then computing it as factorial is faster double gammaEffort = Math.log(precision) * precision * precision; double factorialEffort = Math.log(precision) * precision * Math.log(n) * n / 2e6; if (factorialEffort < gammaEffort) { return ApfloatMath.factorial(n - 1, precision, radix); } } } if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate gamma function to infinite precision"); } if (z.real().signum() < 0) { // Reduced precision for negative near-integers long targetPrecision = precision; Apint zRounded = RoundingHelper.roundToInteger(z.real(), RoundingMode.HALF_EVEN).truncate(); if (zRounded.signum() < 0) { long digitLoss = -z.subtract(zRounded).scale(); if (digitLoss >= targetPrecision) { throw new ArithmeticException("Gamma of negative integer within precision"); } if (digitLoss > 0) { targetPrecision -= digitLoss; } } // Use reflection formula, see e.g. https://functions.wolfram.com/GammaBetaErf/Gamma/16/03/01/ precision = ApfloatHelper.extendPrecision(precision, ApfloatHelper.getSmallExtraPrecision(radix)); z = ApfloatHelper.ensurePrecision(z.negate(), precision); Apfloat pi = ApfloatMath.pi(precision, radix); return ApfloatHelper.limitPrecision(pi.negate().divide(z.multiply(sin(pi.multiply(z))).multiply(gamma(z))), targetPrecision); } long a1 = (long) (precision / Math.log(2 * Math.PI) * Math.log(radix)); long workingPrecision = ApfloatHelper.extendPrecision(precision, (long) (precision * 0.5) + Apfloat.EXTRA_PRECISION); // increase intermediate precision - ck are large and alternating in sign, lots of precision loss z = ApfloatHelper.ensurePrecision(z, workingPrecision).subtract(one); Apfloat a = new Apint(a1 + 1, radix); Apint two = new Apint(2, radix); Apfloat c0 = ApfloatMath.sqrt(ApfloatMath.pi(workingPrecision, radix).multiply(two)); Apcomplex sum = c0; Apfloat e = ApfloatMath.exp(one.precision(workingPrecision)); Apfloat divisor = ApfloatMath.exp(new Apfloat(-a1, workingPrecision, radix)); for (long k = 1; k <= a1; k++) { Apint kk = new Apint(k, radix); Apfloat ak = a.subtract(kk).precision(workingPrecision); Apfloat ck = ApfloatMath.inverseRoot(ak, 2).multiply(ApfloatMath.pow(ak, k)).divide(divisor); sum = sum.add(ck.divide(z.add(kk))); if (k < a1) { divisor = divisor.multiply(e).multiply(kk).negate(); } } a = a.precision(workingPrecision); Apfloat half = new Aprational(one, two).precision(workingPrecision); Apcomplex result = ApcomplexMath.pow(z.add(a), z.add(half)).multiply(ApcomplexMath.exp(z.negate().subtract(a))).multiply(sum); double normalizedScale = result.scale() * Math.log(radix); if (normalizedScale > 0 && z.real().scale() > 0) { precision -= (long) (1.01 * Math.log(normalizedScale) / Math.log(radix)); // Very large results have a reduced precision } else if (normalizedScale < 0) { precision -= (long) (1.148 * Math.log(-normalizedScale) / Math.log(radix)); // Very small results also have a reduced precision } if (precision <= 0) { throw new LossOfPrecisionException("Complete loss of accurate digits"); } return ApfloatHelper.limitPrecision(result, precision); } /** * Incomplete gamma function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the incomplete gamma function. * * @param a The first argument. * @param z The second argument. * * @return Γ(a, z) * * @throws ArithmeticException If the real part of a is nonpositive and z is zero. * * @since 1.10.0 */ public static Apcomplex gamma(Apcomplex a, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return IncompleteGammaHelper.gamma(a, z); } /** * Generalized incomplete gamma function.

* * This function is defined as: Γ(a, z0, z1) = Γ(a, z0) - Γ(a, z1)

* * The lower gamma function can be calculated with: γ(a, z) = Γ(a, 0, z)

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the incomplete gamma function. * * @param a The first argument. * @param z0 The second argument. * @param z1 The third argument. * * @return Γ(a, z0, z1) * * @throws ArithmeticException If the real part of a is nonpositive and either z0 or z1 is zero. For the lower gamma function if a is a nonpositive integer. * * @since 1.10.0 */ public static Apcomplex gamma(Apcomplex a, Apcomplex z0, Apcomplex z1) throws ArithmeticException, ApfloatRuntimeException { return IncompleteGammaHelper.gamma(a, z0, z1); } /** * Logarithm of the gamma function. Note that this function has a different branch * structure than log(gamma(z)).

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the gamma function. * * @param z The argument. * * @return logΓ(z) * * @throws ArithmeticException If z is a nonpositive integer. * * @since 1.11.0 */ public static Apcomplex logGamma(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { // |B_2n| ~ 4 sqrt(pi n) (n / (pi e))^2n // Stirling's series (does not converge) // B_2n / (2n(2n-1)z^(2n-1)) // The sum diverges, but depending on how large re(z) is, the terms initially get smaller and smaller, // until they start getting bigger and bigger (and grow to infinity) // By truncating the sum at the point where the terms are the smallest, we can get a good approximation // Thus we can calculate which is the smallest term, given any z // The larger re(z) is, the larger the n of the term is, and the smaller the term is // For higher precision we need more terms, and a larger re(z) // Use the recurrence formula to move re(z) to be as large as needed // For negative re(z) use first the reflection formula // To calculate how many terms of the sum we need, and how big should re(z) be: // Use the asymptotic formula for B_2n (which is good enough for n >= 3) // The term in the sum is B_2n / (2n(2n-1)z^(2n-1)) // // which is approximately // // z (E Pi z / n)^(-2n) / (2n (2n - 1)) // // Take derivative with respect to n and solve when it's zero // // z = (n exp((4n - 1) / (2n - 4n^2))) / Pi // // Substitute back to what the term is at that point // // exp(-(2n - 1)^2 / (2n)) / (2 Pi (2 n - 1)) // // For precision p in base b, we want that term to be equal to b^-p, solve that for n // (cannot be solved but approximately 2n ~ 2n-1 for large n, then it can be solved) // // n = 1/2 (1 + W(b^p / (2 Pi))) // // Use formula further above to get corresponding value for z // // W is Lambert's W function // W can be approximated by log(z) - log(log(z)) // Followed possibly by iteration(s) of w = w/(1 + w) (1 + log(x/w)) // // The bernoulli number factor of ~sqrt(n) has been ignored in the above calculations, // compensate by adding a few digits of extra precision long precision = z.precision(); if (z.imag().signum() == 0) { if (z.real().signum() == 0) { throw new ArithmeticException("Log gamma of zero"); } if (z.real().isInteger() && z.real().signum() < 0) { throw new ArithmeticException("Log gamma of negative integer"); } } if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate log gamma function to infinite precision"); } int radix = z.radix(); Apint one = Apint.ONES[radix], two = new Apint(2, radix); long workingPrecision = ApfloatHelper.extendPrecision(precision); Apfloat pi = ApfloatMath.pi(workingPrecision, radix); if (z.real().signum() <= 0) { long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix); z = ApfloatHelper.extendPrecision(z, extraPrecision); // Use reflection formula Apcomplex result; if (z.scale() < -precision) { // See e.g. https://functions.wolfram.com/GammaBetaErf/LogGamma/16/01/01/ // Note that with z so small, now sin(z) ~= z, accurate to the precision of z result = log(pi).subtract(log(pi.multiply(z))).subtract(logGamma(z.negate())).subtract(log(z.negate())); } else { // See: Arbitrary-precision computation of the gamma function, Fredrik Johansson, https://arxiv.org/pdf/2109.08392.pdf result = log(pi).subtract(logSin(z)).subtract(logGamma(one.subtract(z))); } return ApfloatHelper.reducePrecision(result, extraPrecision); } double adjust = Math.log(precision) + 1, // Adjustment for the sqrt(n) factor in bernoulli numbers w = (precision + adjust) * Math.log(radix) - Math.log(2 * Math.PI); long n = (long) Math.ceil(0.5 * (1 + w - Math.log(w))); Apfloat zReal = new Apfloat(n * Math.exp((4. * n - 1) / (2 * n - 4. * n * n)) / Math.PI, precision, radix); Apcomplex s = Apcomplex.ZERO; if (z.real().compareTo(zReal) < 0) { long N = zReal.subtract(z.real()).roundAway().longValueExact(); // Use recurrence formula s = s.subtract(logPochhammer(z, N)); z = z.add(new Apfloat(N, precision, radix)); } s = s.add(z.subtract(new Aprational(one, two)).multiply(log(z))).subtract(z).add(log(two.multiply(pi)).divide(two)); Apcomplex z2 = z.multiply(z), zp = z; Iterator bernoulli2 = AprationalMath.bernoullis2(n, radix); for (long k = 1; k <= n; k++) { long k2 = Util.multiplyExact(k, 2); Apcomplex term = bernoulli2.next().precision(workingPrecision).divide(new Apint(k2, radix).multiply(new Apint(k2 - 1, radix)).multiply(zp)); if (k < n) { zp = zp.multiply(z2); } long[] matchingPrecisionsReal = ApfloatHelper.getMatchingPrecisions(s.real(), term.real()); long[] matchingPrecisionsImag = ApfloatHelper.getMatchingPrecisions(s.imag(), term.imag()); if (matchingPrecisionsReal[1] == 0 && matchingPrecisionsImag[1] == 0) { // The rest of the terms would be insignificantly small break; } s = s.add(term); } return s; } // log(sin(pi z)) with correct branch structure private static Apcomplex logSin(Apcomplex z) { // See https://arxiv.org/pdf/2109.08392.pdf Arbitrary-precision computation of the gamma function by Fredrik Johansson long precision = z.precision(), workingPrecision = ApfloatHelper.extendPrecision(precision); int radix = z.radix(); Apint n = z.real().floor(), one = Apint.ONES[radix], two = new Apint(2, radix); Apfloat half = new Aprational(one, two).precision(workingPrecision), pi = ApfloatMath.pi(workingPrecision, radix); Apcomplex i = new Apcomplex(Apint.ZERO, Apint.ONES[radix]); Apcomplex offset = n.multiply(pi).multiply(i); assert (z.real().signum() <= 0); if (z.imag().signum() >= 0) { offset = offset.negate(); } z = z.subtract(n); Apcomplex ls; if (z.imag().compareTo(one) > 0) { ls = log(half.multiply(one.subtract(expNoLoP(two.multiply(i).multiply(pi).multiply(z))))).subtract(i.multiply(pi).multiply(z.subtract(half))); } else if (z.imag().compareTo(one.negate()) < 0) { ls = log(half.multiply(one.subtract(expNoLoP(two.negate().multiply(i).multiply(pi).multiply(z))))).add(i.multiply(pi).multiply(z.subtract(half))); } else { ls = log(sin(pi.multiply(z))); } return ls.add(offset); } private static Apcomplex expNoLoP(Apcomplex z) { // Avoid loss of precision if z is too big if (z.real().signum() < 0) { if (z.real().scale() > 1) { if (z.real().precision() <= z.real().scale() - 1) { z = new Apcomplex(z.real().precision(z.real().scale()), z.imag()); } } } return exp(z); } private static Apcomplex logPochhammer(Apcomplex z, long n) { // Hare's algorithm boolean conj = (z.imag().signum() < 0); if (conj) { z = z.conj(); } int radix = z.radix(); Apcomplex s = z; long m = 0; for (long k = 1; k < n; k++) { Apcomplex t = s.multiply(z.add(new Apint(k, radix))); if (s.imag().signum() >= 0 && t.imag().signum() < 0) { m += 2; } s = t; } if (s.real().signum() < 0) { if (s.imag().signum() >= 0) { m++; } else { m--; } s = s.negate(); } Apcomplex i = new Apcomplex(Apint.ZERO, Apint.ONES[radix]); Apfloat pi = ApfloatMath.pi(z.precision(), radix); Apcomplex result = log(s).add(pi.multiply(i).multiply(new Apint(m, radix))); return (conj ? result.conj() : result); } /** * Digamma function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the digamma function. * * @param z The argument. * * @return ψ(z) * * @throws ArithmeticException If z is a nonpositive integer. * * @since 1.11.0 */ public static Apcomplex digamma(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { // digamma(x) = digamma(1-x) - pi cot(pi x) // |B_2n| ~ 4 sqrt(pi n) (n / (pi e))^2n // digamma(z) ~ ln(z) - 1 / 2z - sum (j=1, infinity, B_2j / (2j z^2j)), re(z) > 0 // digamma(z) = digamma(z + N) - sum (k=0, N-1, 1 / (z + k)) // The sum diverges, but depending on how large re(z) is, the terms initially get smaller and smaller, // until they start getting bigger and bigger (and grow to infinity) // By truncating the sum at the point where the terms are the smallest, we can get a good approximation // Thus we can calculate which is the smallest term, given any z // The larger re(z) is, the larger the n of the term is, and the smaller the term is // For higher precision we need more terms, and a larger re(z) // Use the recurrence formula to move re(z) to be as large as needed // For negative re(z) use first the reflection formula // To calculate how many terms of the sum we need, and how big should re(z) be: // Use the asymptotic formula for B_2n (which is good enough for n >= 3) // The term in the sum is B_2n / (2n z^2n) // // which is approximately // // (n / (pi e))^2n / (2n z^2n) // = // 1/2 n^(2n-1) (e pi z)^(-2n) // = // 1/(2n) (e pi z / n)^(-2n) // // Take derivative with respect to n and solve when it's zero // // n = 1/(2 W(1/(2 pi z))) // so then (solve for z) // z = e^(-1/(2n)) n / pi // // Substitute back to what the term is at that point // // e^(1-2n) / (2n) // // For precision p in base b, we want that term to be equal to b^-p, solve that for n // // n = 1/2 W(b^p e) // // Use formula further above to get corresponding value for z // // W is Lambert's W function // W can be approximated by log(z) - log(log(z)) // Followed possibly by iteration(s) of w = w/(1 + w) (1 + log(x/w)) // // The bernoulli number factor of ~sqrt(n) has been ignored in the above calculations, // compensate by adding a few digits of extra precision long precision = z.precision(); int radix = z.radix(); Apint one = Apint.ONES[radix]; if (z.real().signum() <= 0) { if (z.real().isInteger() && z.imag().signum() == 0) { throw new ArithmeticException("Digamma of nonpositive integer"); } if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate digamma function to infinite precision"); } long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix); precision = ApfloatHelper.extendPrecision(precision, extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat pi = ApfloatMath.pi(precision, radix); // Use reflection formula, see e.g. https://functions.wolfram.com/GammaBetaErf/PolyGamma/16/01/01/ Apcomplex result; if (z.scale() < -precision) { result = digamma(z.negate()).subtract(pi.multiply(cot(pi.multiply(z)))).subtract(one.divide(z)); } else { result = digamma(one.subtract(z)).subtract(pi.multiply(cot(pi.multiply(z)))); } return ApfloatHelper.reducePrecision(result, extraPrecision); } if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate digamma function to infinite precision"); } double adjust = Math.log(precision) + 1, // Adjustment for the sqrt(n) factor in bernoulli numbers w = (precision + adjust) * Math.log(radix) + 1; long n = (long) Math.ceil(0.5 * (w - Math.log(w))); Apfloat zReal = new Apfloat(Math.exp(-0.5 / n) * n / Math.PI, precision, radix); Apcomplex s = Apfloat.ZERO; if (z.real().compareTo(zReal) < 0) { long N = zReal.subtract(z.real()).roundAway().longValueExact(); // Use recurrence formula for (long k = 0; k < N; k++) { s = s.subtract(one.divide(z.add(new Apint(k, radix)))); } z = z.add(new Apfloat(N, precision, radix)); } Apint two = new Apint(2, radix); s = s.add(log(z)).subtract(one.divide(two.multiply(z))); Apcomplex z2 = z.multiply(z), zp = one; Iterator bernoulli2 = AprationalMath.bernoullis2(n, radix); for (long k = 1; k <= n; k++) { long k2 = Util.multiplyExact(k, 2); zp = zp.multiply(z2); Apcomplex term = bernoulli2.next().precision(precision).divide(new Apint(k2, radix).multiply(zp)); long[] matchingPrecisionsReal = ApfloatHelper.getMatchingPrecisions(s.real(), term.real()); long[] matchingPrecisionsImag = ApfloatHelper.getMatchingPrecisions(s.imag(), term.imag()); if (matchingPrecisionsReal[1] == 0 && matchingPrecisionsImag[1] == 0) { // The rest of the terms would be insignificantly small break; } s = s.subtract(term); } return s; } /** * Polygamma function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the polygamma function. * * @param n The order. * @param z The argument. * * @return ψ(n)(z) * * @throws ArithmeticException If n is negative or z is a nonpositive integer. * * @since 1.13.0 */ public static Apcomplex polygamma(long n, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (n < 0) { throw new ArithmeticException("Polygamma of negative order"); } if (isNonPositiveInteger(z)) { throw new ArithmeticException("Polygamma of nonpositive integer"); } if (n == 0) { return digamma(z); } int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(z.precision(), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apint one = Apint.ONES[radix]; Apfloat n1 = new Apfloat(n, precision, radix).add(one); Apcomplex result = ApfloatMath.gamma(n1).multiply(zeta(n1, z)); return ApfloatHelper.reducePrecision((n & 1) == 1 ? result : result.negate(), extraPrecision); } /** * Beta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the beta function. * * @param a The first argument. * @param b The second argument. * * @return B(a, b) * * @throws ArithmeticException If a or b is a nonpositive integer but a + b is not. Also if both a and b are nonpositive integers. * * @since 1.13.0 */ public static Apcomplex beta(Apcomplex a, Apcomplex b) throws ArithmeticException, ApfloatRuntimeException { Apcomplex ab = a.add(b); boolean aNonpositiveInteger = isNonPositiveInteger(a), bNonpositiveInteger = isNonPositiveInteger(b), abNonpositiveInteger = isNonPositiveInteger(ab), aOrBNonpositiveInteger = aNonpositiveInteger || bNonpositiveInteger; if (aOrBNonpositiveInteger && !abNonpositiveInteger || aNonpositiveInteger && bNonpositiveInteger) { // Infinite divided by finite, or two infinities divided by one infinity throw new ArithmeticException("Beta is infinite"); } int radix = a.radix(); if (!aOrBNonpositiveInteger && abNonpositiveInteger) { // Finite divided by infinity return Apcomplex.ZEROS[radix]; } long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Math.min(a.precision(), b.precision()), extraPrecision); if (aOrBNonpositiveInteger && abNonpositiveInteger) { // Infinity divided by infinity, needs different algorithm if (aNonpositiveInteger) { // Make b the nonpositive integer always Apcomplex tmp = b; b = a; a = tmp; } a = ApfloatHelper.ensureGammaPrecision(a, precision); b = ApfloatHelper.ensurePrecision(b, precision); return ApfloatHelper.reducePrecision(gamma(a).divide(pochhammer(b, a)), extraPrecision); } // The trivial case a = ApfloatHelper.ensureGammaPrecision(a, precision); b = ApfloatHelper.ensureGammaPrecision(b, precision); ab = ApfloatHelper.ensureGammaPrecision(ab, precision); return ApfloatHelper.reducePrecision(gamma(a).multiply(gamma(b)).divide(gamma(ab)), extraPrecision); } /** * Incomplete beta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The first argument. * @param a The second argument. * @param b The third argument. * * @return Bz(a, b) * * @throws ArithmeticException If a is a nonpositive integer or z is zero and a has nonpositive real part. * * @since 1.13.0 */ public static Apcomplex beta(Apcomplex z, Apcomplex a, Apcomplex b) throws ArithmeticException, ApfloatRuntimeException { if (isNonPositiveInteger(a)) { throw new ArithmeticException("Incomplete beta with a nonpositive integer"); } int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Util.min(z.precision(), a.precision(), b.precision()), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); a = ApfloatHelper.ensurePrecision(a, precision); Apfloat one = new Apfloat(1, ApfloatHelper.extendPrecision(precision, 1), radix); Apcomplex result = pow(z, a).divide(a).multiply(hypergeometric2F1(a, ApfloatHelper.ensurePrecision(one.subtract(b), precision), ApfloatHelper.ensurePrecision(a.add(one), precision), z)); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Generalized incomplete beta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z1 The first argument. * @param z2 The second argument. * @param a The third argument. * @param b The fourth argument. * * @return B(z1, z2)(a, b) * * @throws ArithmeticException If a is a nonpositive integer or z1 or z2 is zero and a has nonpositive real part. * * @since 1.13.0 */ public static Apcomplex beta(Apcomplex z1, Apcomplex z2, Apcomplex a, Apcomplex b) throws ArithmeticException, ApfloatRuntimeException { int radix = z1.radix(); if (z1.equals(z2)) { return Apint.ZEROS[radix]; } if (isNonPositiveInteger(a)) { throw new ArithmeticException("Generalized incomplete beta with a nonpositive integer"); } long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Util.min(z1.precision(), z2.precision(), a.precision(), b.precision()), extraPrecision); z1 = ApfloatHelper.ensurePrecision(z1, precision); z2 = ApfloatHelper.ensurePrecision(z2, precision); a = ApfloatHelper.ensurePrecision(a, precision); Apfloat one = new Apfloat(1, ApfloatHelper.extendPrecision(precision, 1), radix); Apcomplex a1 = ApfloatHelper.ensurePrecision(a.add(one), precision), b1 = ApfloatHelper.ensurePrecision(one.subtract(b), precision); Apcomplex result = pow(z2, a).multiply(hypergeometric2F1(a, b1, a1, z2)).subtract(pow(z1, a).multiply(hypergeometric2F1(a, b1, a1, z1))).divide(a); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Pochhammer symbol.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the pochhammer symbol. * * @param z The first argument. * @param n The second argument. * * @return (z)n * * @throws ArithmeticException If z + n is a nonpositive integer but z is not. * * @since 1.13.0 */ public static Apcomplex pochhammer(Apcomplex z, Apcomplex n) throws ArithmeticException, ApfloatRuntimeException { int radix = z.radix(); long precision = Math.min(z.precision(), n.precision()); Apint one = Apint.ONES[radix]; if (n.isZero()) { return one.precision(precision); } long longPrecision = ApfloatHelper.getLongPrecision(radix); Apcomplex zn = ApfloatHelper.extendPrecision(z, longPrecision).add(ApfloatHelper.extendPrecision(n, longPrecision)); // Keep sufficient precision regardless of the scale difference of z and n if (isNonPositiveInteger(z)) // gamma(z) is infinite { if (isNonPositiveInteger(zn)) // gamma(z + n) is infinite, too { z = one.subtract(z).subtract(n); Apcomplex result = pochhammer(z, n); Apint two = new Apint(2, radix); return (n.real().truncate().mod(two).signum() == 0 ? result : result.negate()); } return Apint.ZEROS[radix]; } if (n.isInteger() && n.real().signum() > 0 && n.real().compareTo(new Apint(precision, radix)) <= 0) { // If n is integer and relatively small, just evaluating the multiplication is probably faster return pochhammer(z, n.longValueExact()); } long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), extendedPrecision = ApfloatHelper.extendPrecision(precision, extraPrecision); zn = ApfloatHelper.ensureGammaPrecision(zn, extendedPrecision); z = ApfloatHelper.ensureGammaPrecision(z, extendedPrecision); return ApfloatHelper.limitPrecision(gamma(zn).divide(gamma(z)), precision); } static Apcomplex pochhammer(Apcomplex z, long n) { z = ApfloatHelper.extendPrecision(z); long precision = z.precision(); Apfloat one = Apcomplex.ONES[z.radix()].precision(precision); Apcomplex p = one; for (int k = 0; k < n; k++) { p = ApfloatHelper.ensurePrecision(p.multiply(z), precision); z = ApfloatHelper.ensurePrecision(z.add(one), precision); } return ApfloatHelper.reducePrecision(p); } /** * Binomial coefficient. Calculated using the {@link #gamma(Apcomplex)} function. * * @param n The first argument. * @param k The second argument. * * @return * * ( * * n * k * * ) * * * * @throws ArithmeticException If n is a negative integer and k is noninteger. * * @since 1.11.0 */ public static Apcomplex binomial(Apcomplex n, Apcomplex k) throws ArithmeticException, ApfloatRuntimeException { long precision = Math.min(n.precision(), k.precision()); int radix = n.radix(); Apint threshold = new Apint(precision, radix); if (n.isInteger() && k.isInteger() && n.real().compareTo(threshold) <= 0 && k.real().compareTo(threshold) <= 0) { // If n and k are integers and relatively small, evaluating factorials is probably faster return ApintMath.binomial(n.real().truncate(), k.real().truncate()).precision(precision); } Apcomplex nk = n.subtract(k); if (k.isInteger() && k.real().signum() < 0 || nk.isInteger() && nk.real().signum() < 0) { // The divisor is infinity (but the dividend isn't) so we get zero return Apcomplex.ZEROS[radix]; } long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix); precision = ApfloatHelper.extendPrecision(precision, extraPrecision); Apint one = Apint.ONES[radix]; Apcomplex n1 = ApfloatHelper.ensureGammaPrecision(n.add(one), precision), k1 = ApfloatHelper.ensureGammaPrecision(k.add(one), precision), nk1 = ApfloatHelper.ensureGammaPrecision(nk.add(one), precision); Apcomplex result = gamma(n1).divide(gamma(k1).multiply(gamma(nk1))); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Riemann zeta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few hundred digits. At the time of * implementation no generic fast algorithm is known for the zeta function. * * @param s The argument. * * @return ζ(s) * * @throws ArithmeticException If s is 1. * * @since 1.11.0 */ public static Apcomplex zeta(Apcomplex s) throws ArithmeticException, ApfloatRuntimeException { return ZetaHelper.zeta(s); } /** * Hurwitz zeta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few hundred digits. At the time of * implementation no generic fast algorithm is known for the zeta function. * * @param s The first argument. * @param a The second argument. * * @return ζ(s, a) * * @throws ArithmeticException If s is 1 or if a is a nonpositive integer. * * @since 1.11.0 */ public static Apcomplex zeta(Apcomplex s, Apcomplex a) throws ArithmeticException, ApfloatRuntimeException { return HurwitzZetaHelper.zeta(s, a); } /** * Confluent hypergeometric function 0F1.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param z The second argument. * * @return 0F1(; a; z) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public static Apcomplex hypergeometric0F1(Apcomplex a, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return HypergeometricHelper.hypergeometricPFQ(new Apcomplex[0], new Apcomplex[] { a }, z); } /** * Regularized confluent hypergeometric function 01.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param z The second argument. * * @return 01(; a; z) * * @since 1.13.0 */ public static Apcomplex hypergeometric0F1Regularized(Apcomplex a, Apcomplex z) throws ApfloatRuntimeException { return HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[0], new Apcomplex[] { a }, z); } /** * Kummer confluent hypergeometric function 1F1. * Also known as the confluent hypergeometric function of the first kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param z The third argument. * * @return 1F1(a; b; z) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public static Apcomplex hypergeometric1F1(Apcomplex a, Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return HypergeometricHelper.hypergeometricPFQ(new Apcomplex[] { a }, new Apcomplex[] { b }, z); } /** * Regularized Kummer confluent hypergeometric function 11. * Also known as the regularized confluent hypergeometric function of the first kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param z The third argument. * * @return 11(a; b; z) * * @since 1.13.0 */ public static Apcomplex hypergeometric1F1Regularized(Apcomplex a, Apcomplex b, Apcomplex z) throws ApfloatRuntimeException { return HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { a }, new Apcomplex[] { b }, z); } /** * Hypergeometric function 2F1. * Also known as the Gaussian or ordinary hypergeometric function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param c The third argument. * @param z The fourth argument. * * @return 2F1(a, b; c; z) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public static Apcomplex hypergeometric2F1(Apcomplex a, Apcomplex b, Apcomplex c, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return HypergeometricHelper.hypergeometricPFQ(new Apcomplex[] { a, b }, new Apcomplex[] { c }, z); } /** * Regularized hypergeometric function 21. * Also known as the regularized Gaussian or ordinary hypergeometric function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param c The third argument. * @param z The fourth argument. * * @return 21(a, b; c; z) * * @since 1.13.0 */ public static Apcomplex hypergeometric2F1Regularized(Apcomplex a, Apcomplex b, Apcomplex c, Apcomplex z) throws ApfloatRuntimeException { return HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { a, b }, new Apcomplex[] { c }, z); } /** * Tricomi's confluent hypergeometric function U. * Also known as the confluent hypergeometric function of the second kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param z The third argument. * * @return U(a, b, z) * * @throws ArithmeticException If the result is not finite. * * @since 1.13.0 */ public static Apcomplex hypergeometricU(Apcomplex a, Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return HypergeometricHelper.hypergeometricU(a, b, z, false); } /** * Error function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return erf(z) * * @since 1.13.0 */ public static Apcomplex erf(Apcomplex z) throws ApfloatRuntimeException { if (z.isZero()) { return z; } if (z.scale() > 0) { // More accurate algorithm for larger values int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(z.precision(), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apint one = Apint.ONES[radix], two = new Apint(2, radix); Apfloat sqrtPi = ApfloatMath.sqrt(ApfloatMath.pi(precision, radix)), half = new Aprational(one, two).precision(precision); Apcomplex result = one.subtract(gamma(half, z.multiply(z)).divide(sqrtPi)); boolean negate = (z.real().signum() == 0 ? z.imag().signum() < 0 : z.real().signum() < 0); return ApfloatHelper.reducePrecision(negate ? result.negate() : result, extraPrecision); } // More accurate algorithm for smaller values return erfFixedPrecision(z); } static Apcomplex erfFixedPrecision(Apcomplex z) throws ApfloatRuntimeException { if (z.isZero()) { return z; } int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(z.precision(), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apint one = Apint.ONES[radix], two = new Apint(2, radix), three = new Apint(3, radix); Apfloat sqrtPi = ApfloatMath.sqrt(ApfloatMath.pi(precision, radix)), half = new Aprational(one, two).precision(precision), threeHalfs = new Aprational(three, two).precision(precision); Apcomplex result = two.multiply(z).divide(sqrtPi).multiply(hypergeometric1F1(half, threeHalfs, z.multiply(z).negate())); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Complementary error function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return erfc(z) * * @since 1.13.0 */ public static Apcomplex erfc(Apcomplex z) throws ApfloatRuntimeException { int radix = z.radix(); Apint one = Apint.ONES[radix]; if (z.scale() > 0 && z.real().signum() > 0) { // More accurate algorithm for larger values long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(z.precision(), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat sqrtPi = ApfloatMath.sqrt(ApfloatMath.pi(precision, radix)), two = new Apfloat(2, precision, radix), half = one.divide(two); Apcomplex result = gamma(half, z.multiply(z)).divide(sqrtPi); return ApfloatHelper.reducePrecision(result, extraPrecision); // Note that compared to the erf() algorithm, z.real().signum() > 0 always so no need to negate the result ever } // More accurate algorithm for smaller values return one.subtract(erf(z)); } static Apcomplex erfcFixedPrecision(Apcomplex z) throws ApfloatRuntimeException { if (z.scale() > 0 && z.real().signum() > 0 && z.real().scale() >= z.imag().scale()) { return erfc(z); } Apint one = Apint.ONES[z.radix()]; return one.subtract(erfFixedPrecision(z)); } /** * Imaginary error function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return erfi(z) * * @since 1.13.0 */ public static Apcomplex erfi(Apcomplex z) throws ApfloatRuntimeException { int radix = z.radix(); Apcomplex i = new Apcomplex(Apfloat.ZEROS[radix], Apfloat.ONES[radix]); return i.multiply(erf(i.multiply(z))).negate(); } static Apcomplex erfiFixedPrecision(Apcomplex z) throws ApfloatRuntimeException { int radix = z.radix(); Apcomplex i = new Apcomplex(Apfloat.ZEROS[radix], Apfloat.ONES[radix]); return i.multiply(erfFixedPrecision(i.multiply(z))).negate(); } /** * Fresnel integral S.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return S(z) * * @since 1.13.0 */ public static Apcomplex fresnelS(Apcomplex z) throws ApfloatRuntimeException { if (z.isZero()) { return z; } int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(z.precision(), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat two = new Apfloat(2, precision, radix), pi = ApfloatMath.pi(precision, radix); if (z.scale() > 0) { Apint one = Apfloat.ONES[radix]; Apfloat half = one.divide(two), invSqrtPi = ApfloatMath.inverseRoot(pi, 2); Apcomplex i = new Apcomplex(Apfloat.ZEROS[radix], one), z2 = z.multiply(z), iz2 = i.multiply(z2), iHalfPiZ2 = iz2.multiply(pi).divide(two), result = i.multiply(z).multiply(inverseRoot(two, 2)).divide(two).multiply(fresnelTerm(one, half, invSqrtPi, iz2, iHalfPiZ2).subtract(fresnelTerm(one, half, invSqrtPi, iz2.negate(), iHalfPiZ2.negate()))); return ApfloatHelper.reducePrecision(result, extraPrecision); } Apfloat three = new Apfloat(3, precision, radix), four = new Apfloat(4, precision, radix), six = new Apfloat(6, precision, radix), seven = new Apfloat(7, precision, radix), sixteen = new Apfloat(16, precision, radix); Apcomplex[] a = { three.divide(four) }, b = { three.divide(two), seven.divide(four) }; Apcomplex result = pi.multiply(pow(z, 3)).divide(six).multiply(HypergeometricHelper.hypergeometricPFQ(a, b, pi.multiply(pi).negate().multiply(pow(z, 4)).divide(sixteen))); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Fresnel integral C.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return C(z) * * @since 1.13.0 */ public static Apcomplex fresnelC(Apcomplex z) throws ApfloatRuntimeException { if (z.isZero()) { return z; } int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(z.precision(), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat two = new Apfloat(2, precision, radix), pi = ApfloatMath.pi(precision, radix); Apint one = Apfloat.ONES[radix]; if (z.scale() > 0) { Apfloat half = one.divide(two), invSqrtPi = ApfloatMath.inverseRoot(pi, 2); Apcomplex i = new Apcomplex(Apfloat.ZEROS[radix], one), z2 = z.multiply(z), iz2 = i.multiply(z2), iHalfPiZ2 = iz2.multiply(pi).divide(two), result = z.multiply(inverseRoot(two, 2)).divide(two).multiply(fresnelTerm(one, half, invSqrtPi, iz2, iHalfPiZ2).add(fresnelTerm(one, half, invSqrtPi, iz2.negate(), iHalfPiZ2.negate()))); return ApfloatHelper.reducePrecision(result, extraPrecision); } Apfloat four = new Apfloat(4, precision, radix), five = new Apfloat(5, precision, radix), sixteen = new Apfloat(16, precision, radix); Apcomplex[] a = { one.divide(four) }, b = { one.divide(two), five.divide(four) }; Apcomplex result = z.multiply(HypergeometricHelper.hypergeometricPFQ(a, b, pi.multiply(pi).negate().multiply(pow(z, 4)).divide(sixteen))); return ApfloatHelper.reducePrecision(result, extraPrecision); } private static Apcomplex fresnelTerm(Apint one, Apfloat half, Apfloat invSqrtPi, Apcomplex iz2, Apcomplex iHalfPiZ2) throws ApfloatRuntimeException { return inverseRoot(iz2, 2).multiply(one.subtract(invSqrtPi.multiply(gamma(half, iHalfPiZ2)))); } /** * Exponential integral E.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param z The second argument. * * @return Eν(z) * * @throws ArithmeticException If real part of ν is ≤ 1 and z is zero. * * @since 1.13.0 */ public static Apcomplex expIntegralE(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { int radix = ν.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Math.min(ν.precision(), z.precision()), extraPrecision); ν = ApfloatHelper.ensurePrecision(ν, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat one = Apint.ONES[radix].precision(ApfloatHelper.extendPrecision(precision, 1)); Apcomplex ν1 = ApfloatHelper.ensureGammaPrecision(ν.subtract(one), precision), result = pow(z, ν1).multiply(gamma(ν1.negate(), z)); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Exponential integral Ei.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Ei(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public static Apcomplex expIntegralEi(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(z.precision(), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apint zero = Apint.ZEROS[radix]; Apfloat adjust; if (z.imag().signum() == 0) { adjust = z.real().signum() > 0 ? ApfloatMath.pi(precision, radix).negate() : zero; } else { Apfloat pi = ApfloatMath.pi(precision, radix); adjust = z.imag().signum() < 0 ? pi.negate() : pi; } Apcomplex result = gamma(zero, z.negate()).negate().add(new Apcomplex(zero, adjust)); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Logarithmic integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return li(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public static Apcomplex logIntegral(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (z.isZero()) { return z; } return expIntegralEi(log(z)); } /** * Sine integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Si(z) * * @since 1.13.0 */ public static Apcomplex sinIntegral(Apcomplex z) throws ApfloatRuntimeException { int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(z.precision(), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat zero = Apint.ZEROS[radix], one = Apint.ONES[radix], two = new Apfloat(2, precision, radix); if (z.scale() > 0) { Apfloat adjust = ApfloatMath.pi(precision, radix); if (z.real().signum() > 0 || z.real().signum() == 0 && z.imag().signum() > 0) { adjust = adjust.negate(); } Apcomplex i = new Apcomplex(zero, one), iz = i.multiply(z), result = gamma(zero, iz.negate()).subtract(gamma(zero, iz)).add(new Apcomplex(zero, adjust)).multiply(i).divide(two); return ApfloatHelper.reducePrecision(result, extraPrecision); } Apfloat three = new Apfloat(3, precision, radix), four = new Apfloat(4, precision, radix); Apcomplex[] a = { one.divide(two) }, b = { three.divide(two), three.divide(two) }; Apcomplex result = z.multiply(HypergeometricHelper.hypergeometricPFQ(a, b, z.multiply(z).divide(four).negate())); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Cosine integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Ci(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public static Apcomplex cosIntegral(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(z.precision(), extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat zero = Apint.ZEROS[radix], one = Apint.ONES[radix], two = new Apfloat(2, precision, radix); if (z.scale() > 0) { Apfloat adjust = zero; if (z.real().signum() < 0 || z.real().signum() == 0 && z.imag().signum() < 0) { adjust = ApfloatMath.pi(precision, radix); adjust = (z.imag().signum() < 0 ? adjust.negate() : adjust); } Apcomplex i = new Apcomplex(zero, one), iz = i.multiply(z), result = gamma(zero, iz.negate()).add(gamma(zero, iz)).divide(two).negate().add(new Apcomplex(zero, adjust)); return ApfloatHelper.reducePrecision(result, extraPrecision); } Apcomplex logz = log(z); Apfloat three = new Apfloat(3, precision, radix), four = new Apfloat(4, precision, radix), euler = ApfloatMath.euler(precision, radix); Apcomplex[] a = { one, one }, b = { two, two, three.divide(two) }; Apcomplex z24 = z.multiply(z).divide(four).negate(), result = z24.multiply(HypergeometricHelper.hypergeometricPFQ(a, b, z24)).add(logz).add(euler); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Hyperbolic sine integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Shi(z) * * @since 1.13.0 */ public static Apcomplex sinhIntegral(Apcomplex z) throws ApfloatRuntimeException { int radix = z.radix(); Apcomplex i = new Apcomplex(Apint.ZEROS[radix], Apint.ONES[radix]); return i.multiply(sinIntegral(i.multiply(z))).negate(); } /** * Hyperbolic cosine integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Chi(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public static Apcomplex coshIntegral(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { int radix = z.radix(); long precision = z.precision(); Apint zero = Apint.ZEROS[radix], one = Apint.ONES[radix], two = new Apint(2, radix); Apcomplex i = new Apcomplex(zero, one), ci = cosIntegral(i.multiply(z)); Apfloat adjust = ApfloatMath.pi(precision, radix).divide(two).negate(); if (z.real().signum() < 0 && z.imag().signum() >= 0) { Apint three = new Apint(3, radix); adjust = adjust.multiply(three).negate(); } return ci.add(new Apcomplex(zero, adjust)); } /** * Airy function Ai.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Ai(z) * * @throws InfiniteExpansionException If z is zero. * * @since 1.13.0 */ public static Apcomplex airyAi(Apcomplex z) throws ApfloatRuntimeException { return airyAi(z, z.precision()); } static Apcomplex airyAi(Apcomplex z0, long targetPrecision) throws ApfloatRuntimeException { int radix = z0.radix(); Apcomplex result = airy(precision -> { Apfloat one = Apint.ONES[radix].precision(precision), two = new Apfloat(2, precision, radix), three = new Apfloat(3, precision, radix), four = new Apfloat(4, precision, radix), nine = new Apfloat(9, precision, radix), twoThirds = two.divide(three), invCube3 = ApfloatMath.inverseRoot(three, 3); Apcomplex z = ApfloatHelper.ensurePrecision(z0, precision), z39 = pow(z, 3).divide(nine); return invCube3.multiply(invCube3).divide(gamma(twoThirds)).multiply(hypergeometric0F1(twoThirds, z39)).subtract(z.multiply(invCube3).divide(gamma(one.divide(three))).multiply(hypergeometric0F1(four.divide(three), z39))); }, targetPrecision, radix); return result; } /** * Derivative of the Airy function Ai.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Ai′(z) * * @throws InfiniteExpansionException If z is zero. * * @since 1.13.0 */ public static Apcomplex airyAiPrime(Apcomplex z) throws ApfloatRuntimeException { return airyAiPrime(z, z.precision()); } static Apcomplex airyAiPrime(Apcomplex z0, long targetPrecision) throws ApfloatRuntimeException { int radix = z0.radix(); Apcomplex result; result = airy(precision -> { Apfloat one = Apint.ONES[radix].precision(precision), two = new Apfloat(2, precision, radix), three = new Apfloat(3, precision, radix), five = new Apfloat(5, precision, radix), nine = new Apfloat(9, precision, radix), oneThird = one.divide(three), invCube3 = ApfloatMath.inverseRoot(three, 3); Apcomplex z = ApfloatHelper.ensurePrecision(z0, precision), z39 = pow(z, 3).divide(nine); return z.multiply(z).divide(two).multiply(invCube3).multiply(invCube3).divide(gamma(two.divide(three))).multiply(hypergeometric0F1(five.divide(three), z39)).subtract(invCube3.divide(gamma(oneThird)).multiply(hypergeometric0F1(oneThird, z39))); }, targetPrecision, radix); return result; } /** * Airy function Bi.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Bi(z) * * @throws InfiniteExpansionException If z is zero. * * @since 1.13.0 */ public static Apcomplex airyBi(Apcomplex z) throws ApfloatRuntimeException { return airyBi(z, z.precision()); } static Apcomplex airyBi(Apcomplex z0, long targetPrecision) throws ApfloatRuntimeException { int radix = z0.radix(); Apcomplex result = airy(precision -> { Apfloat one = Apint.ONES[radix].precision(precision), two = new Apfloat(2, precision, radix), three = new Apfloat(3, precision, radix), four = new Apfloat(4, precision, radix), nine = new Apfloat(9, precision, radix), twoThirds = two.divide(three), invSixth3 = ApfloatMath.inverseRoot(three, 6); Apcomplex z = ApfloatHelper.ensurePrecision(z0, precision), z39 = pow(z, 3).divide(nine); return invSixth3.divide(gamma(twoThirds)).multiply(hypergeometric0F1(twoThirds, z39)).add(z.divide(invSixth3.multiply(gamma(one.divide(three)))).multiply(hypergeometric0F1(four.divide(three), z39))); }, targetPrecision, radix); return result; } /** * Derivative of the Airy function Bi.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Bi′(z) * * @throws InfiniteExpansionException If z is zero. * * @since 1.13.0 */ public static Apcomplex airyBiPrime(Apcomplex z) throws ApfloatRuntimeException { return airyBiPrime(z, z.precision()); } static Apcomplex airyBiPrime(Apcomplex z0, long targetPrecision) throws ApfloatRuntimeException { int radix = z0.radix(); Apcomplex result = airy(precision -> { Apfloat one = Apint.ONES[radix].precision(precision), two = new Apfloat(2, precision, radix), three = new Apfloat(3, precision, radix), five = new Apfloat(5, precision, radix), nine = new Apfloat(9, precision, radix), oneThird = one.divide(three), invSixth3 = ApfloatMath.inverseRoot(three, 6); Apcomplex z = ApfloatHelper.ensurePrecision(z0, precision), z39 = pow(z, 3).divide(nine); return inverseRoot(invSixth3.multiply(gamma(oneThird)), 1).multiply(hypergeometric0F1(oneThird, z39)).add(z.multiply(z).divide(two).multiply(invSixth3).divide(gamma(two.divide(three))).multiply(hypergeometric0F1(five.divide(three), z39))); }, targetPrecision, radix); return result; } private static Apcomplex airy(Function f, long targetPrecision, int radix) { long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), resultPrecision = ApfloatHelper.extendPrecision(targetPrecision, extraPrecision), precision = resultPrecision, precisionLoss; Apcomplex result; do { result = f.apply(precision); precisionLoss = (result.isZero() ? precision : resultPrecision - result.precision()); // The result shouldn't be exactly zero, it means full loss of significant digits precision = Util.ifFinite(precision, precision + precisionLoss); } while (precisionLoss > 0); long reducePrecision = Math.max(0, (long) Math.round(Math.log(result.scale()) / Math.log(radix))); targetPrecision = ApfloatHelper.reducePrecision(targetPrecision, reducePrecision); return ApfloatHelper.limitPrecision(result, targetPrecision); } /** * Bessel function of the first kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The order. * @param z The argument. * * @return Jν(z) * * @throws ArithmeticException If the real part of ν is < 0 and ν is not an integer and z is zero. Also if the real part of ν is zero but the imaginary part is not, and z is zero. * * @since 1.13.0 */ public static Apcomplex besselJ(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return BesselHelper.besselJ(ν, z); } /** * Modified Bessel function of the first kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The order. * @param z The argument. * * @return Iν(z) * * @throws ArithmeticException If the real part of ν is < 0 and ν is not an integer and z is zero. Also if the real part of ν is zero but the imaginary part is not, and z is zero. * * @since 1.13.0 */ public static Apcomplex besselI(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return BesselHelper.besselI(ν, z); } /** * Bessel function of the second kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The order. * @param z The argument. * * @return Yν(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public static Apcomplex besselY(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return BesselHelper.besselY(ν, z); } /** * Modified Bessel function of the second kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The order. * @param z The argument. * * @return Kν(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public static Apcomplex besselK(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return BesselHelper.besselK(ν, z); } /** * Complete elliptic integral of the first kind.

* * Note that this function uses the definition: * * * * * K * ( * z * ) * * * * * * 0 * * π * 2 * * * * * 1 * * * 1 * - * * z * * * * sin * 2 * * ( * t * ) * * * * * * * * * t * * * * * * * * @param z The argument. * * @return K(z) * * @throws InfiniteExpansionException If z is zero. * @throws ArithmeticException If z is one. * * @since 1.13.0 */ public static Apcomplex ellipticK(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return ellipticK(z, z.precision()); } static Apcomplex ellipticK(Apcomplex z, long precision) throws ArithmeticException, ApfloatRuntimeException { return ellipticK(z, precision, null); } static Apcomplex ellipticK(Apcomplex z, long precision, Consumer consumer) throws ArithmeticException, ApfloatRuntimeException { int radix = z.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix); precision = ApfloatHelper.extendPrecision(precision, extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat one = Apint.ONES[radix], two = new Apfloat(2, precision, radix), pi = ApfloatMath.pi(precision, radix); Apcomplex result = pi.divide(two.multiply(agm(one, sqrt(ApfloatHelper.ensurePrecision(one.subtract(z), precision)), consumer))); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Complete elliptic integral of the second kind.

* * Note that this function uses the definition: * * * * * E * ( * z * ) * * * * * * 0 * * π * 2 * * * * * * 1 * - * * z * * * * sin * 2 * * ( * t * ) * * * * * * * * t * * * * * * * * @param z The argument. * * @return E(z) * * @throws InfiniteExpansionException If z is zero. * * @since 1.13.0 */ public static Apcomplex ellipticE(Apcomplex z) throws ApfloatRuntimeException { return ellipticE(z, z.precision()); } static Apcomplex ellipticE(Apcomplex z, long precision) throws ApfloatRuntimeException { int radix = z.radix(); Apint zero = Apint.ZEROS[radix], one = Apint.ONES[radix], two = new Apint(2, radix); if (z.equals(one)) { return z; } long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix); precision = ApfloatHelper.extendPrecision(precision, extraPrecision); z = ApfloatHelper.ensurePrecision(z, precision); Apcomplex[] sum = new Apcomplex[] { zero }; Aprational[] p2 = new Aprational[1]; Apcomplex k = ellipticK(z, precision, c2 -> sum[0] = sum[0].add((p2[0] = (p2[0] == null ? new Aprational(one, two) : p2[0].multiply(two))).multiply(c2))), result = one.subtract(sum[0]).multiply(k); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Hermite function. For integer values of ν gives the Hermite polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param z The second argument. * * @return Hν(z) * * @since 1.14.0 */ public static Apcomplex hermiteH(Apcomplex ν, Apcomplex z) throws ApfloatRuntimeException { int radix = z.radix(); long targetPrecision = Math.min(ν.precision(), z.precision()), extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), resultPrecision = ApfloatHelper.extendPrecision(targetPrecision, extraPrecision), precision = resultPrecision, precisionLoss; Apint one = Apint.ONES[radix]; if (ν.isZero()) { return one.precision(targetPrecision); } if (z.isZero()) { Apint two = new Apint(2, radix); if (ν.isInteger() && ν.real().signum() > 0 && ν.real().truncate().mod(two).signum() > 0) { return Apint.ZEROS[radix]; } ν = ApfloatHelper.ensurePrecision(ν, precision); Apfloat pi = ApfloatMath.pi(precision, radix); Apcomplex ν12 = ApfloatHelper.ensureGammaPrecision(ApfloatHelper.ensurePrecision(one.subtract(ν), precision).divide(two), precision), result = pow(two.precision(precision), ν).multiply(sqrt(pi)).divide(gamma(ν12)); return ApfloatHelper.reducePrecision(result, extraPrecision); } Apcomplex result; do { ν = ApfloatHelper.ensurePrecision(ν, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat two = new Apfloat(2, precision, radix), three = new Apfloat(3, precision, radix); Apcomplex n12 = one.subtract(ν).divide(two), nn2 = ν.negate().divide(two), z2 = z.multiply(z); result = Apint.ZEROS[radix]; if (!isNonPositiveInteger(n12)) { result = inverseRoot(gamma(ApfloatHelper.ensureGammaPrecision(n12, precision)), 1).multiply(hypergeometric1F1(ApfloatHelper.ensurePrecision(nn2, precision), one.divide(two), z2)); } if (!isNonPositiveInteger(nn2)) { result = result.subtract(two.multiply(z).divide(gamma(ApfloatHelper.ensureGammaPrecision(nn2, precision))).multiply(hypergeometric1F1(ApfloatHelper.ensurePrecision(n12, precision), three.divide(two), z2))); } precisionLoss = (result.isZero() ? precision : resultPrecision - result.precision()); // The result shouldn't be exactly zero, it means full loss of significant digits precision = Util.ifFinite(precision, precision + precisionLoss); } while (precisionLoss > 0); precision = resultPrecision; Apfloat two = new Apfloat(2, precision, radix), pi = ApfloatMath.pi(precision, radix); ν = ApfloatHelper.limitPrecision(ν, precision); result = pow(two, ν).multiply(sqrt(pi)).multiply(result); if (ν.imag().signum() == 0 && z.imag().signum() == 0) { result = result.real(); // With purely real input arguments the result should be purely real } return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Laguerre function. For integer values of ν gives the Laguerre polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param z The second argument. * * @return Lν(z) * * @since 1.14.0 */ public static Apcomplex laguerreL(Apcomplex ν, Apcomplex z) throws ApfloatRuntimeException { long precision = Math.min(ν.precision(), z.precision()); Apfloat one = Apint.ONES[ν.radix()].precision(precision); return hypergeometric1F1(ν.negate(), one, z); } /** * Generalized Laguerre function. For integer values of ν gives the generalized Laguerre polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param λ The second argument. * @param z The third argument. * * @return Lνλ(z) * * @since 1.14.0 */ public static Apcomplex laguerreL(Apcomplex ν, Apcomplex λ, Apcomplex z) throws ApfloatRuntimeException { long precision = Util.min(ν.precision(), λ.precision(), z.precision()); Apfloat one = Apint.ONES[ν.radix()]; Apcomplex ν1 = ApfloatHelper.ensurePrecision(ν.add(one), precision), λ1 = ApfloatHelper.ensurePrecision(λ.add(one), precision); return pochhammer(ν1, λ).multiply(hypergeometric1F1Regularized(ν.negate(), λ1, z)); } /** * Legendre function. For integer values of ν gives the Legendre polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param z The second argument. * * @return Pν(z) * * @throws ArithmeticException If ν is not an integer and z is -1. * * @since 1.14.0 */ public static Apcomplex legendreP(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { Apcomplex zero = Apcomplex.ZEROS[ν.radix()]; return legendreP(ν, zero, z); } /** * Associated Legendre function of the first kind. Gives Legendre functions of type 2.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param μ The second argument. * @param z The third argument. * * @return Pνμ(z) * * @throws ArithmeticException If ν is not an integer and z is -1. * * @since 1.14.0 */ public static Apcomplex legendreP(Apcomplex ν, Apcomplex μ, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { int radix = ν.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Util.min(ν.precision(), μ.precision(), z.precision()), extraPrecision); ν = ApfloatHelper.ensurePrecision(ν, precision); μ = ApfloatHelper.ensurePrecision(μ, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat one = Apint.ONES[radix], two = new Apint(2, radix); Apcomplex ν1 = ApfloatHelper.ensurePrecision(ν.add(one), precision), μ1 = ApfloatHelper.ensurePrecision(one.subtract(μ), precision), z12 = ApfloatHelper.ensurePrecision(one.subtract(z), precision).divide(two); Apcomplex result = hypergeometric2F1Regularized(ν.negate(), ν1, μ1, z12); if (!μ.isZero()) { Apcomplex μ2 = μ.divide(two), z1 = ApfloatHelper.ensurePrecision(one.add(z), precision), z1n = ApfloatHelper.ensurePrecision(one.subtract(z), precision); result = result.multiply(pow(z1, μ2)).divide(pow(z1n, μ2)); } return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Legendre function of the second kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param z The second argument. * * @return Qν(z) * * @throws ArithmeticException If z is 1 or -1. * * @since 1.14.0 */ public static Apcomplex legendreQ(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { Apcomplex zero = Apcomplex.ZEROS[ν.radix()]; return legendreQ(ν, zero, z); } /** * Associated Legendre function of the second kind. Gives Legendre functions of type 2.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param μ The second argument. * @param z The third argument. * * @return Qνμ(z) * * @throws ArithmeticException If z is 1 or -1. * * @since 1.14.0 */ public static Apcomplex legendreQ(Apcomplex ν, Apcomplex μ, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { int radix = ν.radix(); long targetPrecision = Util.min(ν.precision(), μ.precision(), z.precision()), extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), resultPrecision = ApfloatHelper.extendPrecision(targetPrecision, extraPrecision), precision = resultPrecision, precisionLoss; Apint one = Apint.ONES[radix]; boolean isOne = (z.equals(one) || z.equals(one.negate())); Apcomplex result; do { ν = ApfloatHelper.ensurePrecision(ν, precision); μ = ApfloatHelper.ensurePrecision(μ, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat two = new Apfloat(2, precision, radix), three = new Apint(3, radix), pi = ApfloatMath.pi(precision, radix); Apcomplex z2 = z.multiply(z), p1 = pochhammer(ApfloatHelper.ensurePrecision(one.subtract(μ).add(ν), precision).divide(two), ApfloatHelper.ensurePrecision(one.divide(two).add(μ), precision)), p2 = pochhammer(ApfloatHelper.ensurePrecision(two.subtract(μ).add(ν), precision).divide(two), ApfloatHelper.ensurePrecision(μ.subtract(one.divide(two)), precision)); result = Apint.ZEROS[radix]; if (!p1.isZero()) { Apcomplex μν = ApfloatHelper.ensurePrecision(μ.add(ν), precision), μν12 = ApfloatHelper.ensurePrecision(one.subtract(μ).subtract(ν), precision).divide(two), νμ = ApfloatHelper.ensurePrecision(ν.subtract(μ), precision), νμ12 = ApfloatHelper.ensurePrecision(νμ.divide(two).add(one), precision); result = result.add(cos(μν.divide(two).multiply(pi)).multiply(p1).multiply(z).divide(two).multiply(hypergeometric2F1Regularized(μν12, νμ12, three.divide(two), z2))); } if (!p2.isZero()) { Apcomplex μν = ApfloatHelper.ensurePrecision(μ.add(ν), precision), μν2 = ApfloatHelper.ensurePrecision(μ.negate().subtract(ν), precision).divide(two), νμ12 = ApfloatHelper.ensurePrecision(ν.subtract(μ).add(one), precision).divide(two); result = result.subtract(sin(μν.divide(two).multiply(pi)).multiply(p2).divide(two).multiply(hypergeometric2F1Regularized(μν2, νμ12, one.divide(two), z2))); } precisionLoss = (!isOne && result.isZero() ? precision : resultPrecision - result.precision()); // The result shouldn't be exactly zero, it means full loss of significant digits precision = Util.ifFinite(precision, precision + precisionLoss); } while (precisionLoss > 0); precision = resultPrecision; Apfloat two = new Apfloat(2, precision, radix), pi = ApfloatMath.pi(precision, radix); μ = ApfloatHelper.limitPrecision(μ, precision); z = ApfloatHelper.limitPrecision(z, precision); Apcomplex z2 = z.multiply(z); result = result.multiply(pow(two, μ)).multiply(pi).multiply(pow(ApfloatHelper.ensurePrecision(one.subtract(z2), precision), μ.negate().divide(two))); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Spherical harmonic function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param λ The first argument. * @param μ The second argument. * @param ϑ The third argument. * @param ϕ The fourth argument. * * @return Yλμ(ϑ, φ) * * @throws ArithmeticException If ϑ is π plus a multiple of 2 π and μ is not an integer and has a negative real part, or if λ - μ is a negative integer. * * @since 1.14.0 */ public static Apcomplex sphericalHarmonicY(Apcomplex λ, Apcomplex μ, Apcomplex ϑ, Apcomplex ϕ) throws ArithmeticException, ApfloatRuntimeException { if (λ.isInteger() && μ.isInteger()) { // The polynomial version return sphericalHarmonicY(λ.real().truncate(), μ.real().truncate(), ϑ, ϕ); } int radix = λ.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Util.min(λ.precision(), μ.precision(), ϑ.precision(), ϕ.precision()), extraPrecision); λ = ApfloatHelper.ensurePrecision(λ, precision); μ = ApfloatHelper.ensurePrecision(μ, precision); ϑ = ApfloatHelper.ensurePrecision(ϑ, precision); ϕ = ApfloatHelper.ensurePrecision(ϕ, precision); Apint zero = Apint.ZEROS[radix], one = Apint.ONES[radix], two = new Apint(2, radix), four = new Apint(4, radix); Apcomplex i = new Apcomplex(zero, one), result = two.multiply(λ).add(one); if (result.isZero()) { return result; } Apfloat pi = ApfloatMath.pi(precision, radix); result = sqrt(result.divide(four.multiply(pi))); if (!μ.isZero()) { Apcomplex λμ1 = λ.add(μ).add(one); if (λμ1.isInteger() && λμ1.real().signum() <= 0) { return zero; } Apcomplex λnμ1 = ApfloatHelper.ensureGammaPrecision(λ.subtract(μ).add(one), precision); λμ1 = ApfloatHelper.ensureGammaPrecision(λμ1, precision); result = result.multiply(sqrt(gamma(λnμ1))).divide(sqrt(gamma(λμ1))).multiply(exp(i.multiply(ϕ).multiply(μ))); } return ApfloatHelper.reducePrecision(result.multiply(legendreP(λ, μ, cos(ϑ))), extraPrecision); } private static Apcomplex sphericalHarmonicY(Apint n, Apint m, Apcomplex ϑ, Apcomplex ϕ) throws ArithmeticException, ApfloatRuntimeException { int radix = n.radix(); Apint zero = Apint.ZEROS[radix], one = Apint.ONES[radix], two = new Apint(2, radix), four = new Apint(4, radix); if (n.signum() < 0) { return sphericalHarmonicY(n.negate().subtract(one), m, ϑ, ϕ); } if (n.compareTo(ApfloatMath.abs(m)) < 0) { return zero; } long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Util.min(ϑ.precision(), ϕ.precision()), extraPrecision); ϑ = ApfloatHelper.ensurePrecision(ϑ, precision); ϕ = ApfloatHelper.ensurePrecision(ϕ, precision); Apfloat pi = ApfloatMath.pi(precision, radix); Apcomplex i = new Apcomplex(zero, one), result = sqrt(two.multiply(n).add(one).multiply(ApfloatMath.factorial(ApfloatHelper.longValueExact(n.subtract(m)), precision, radix)).divide(four.multiply(pi).multiply(ApfloatMath.factorial(ApfloatHelper.longValueExact(n.add(m)), precision, radix)))).multiply(exp(i.multiply(m).multiply(ϕ))).multiply(legendreP(n, m, cos(ϑ))); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Chebyshev function of the first kind. For integer values of ν gives the Chebyshev polynomial of the first kind.

* * @param ν The first argument. * @param z The second argument. * * @return Tν(z) * * @since 1.14.0 */ public static Apcomplex chebyshevT(Apcomplex ν, Apcomplex z) throws ApfloatRuntimeException { int radix = ν.radix(); if (ν.isZero() && z.isZero()) { return Apcomplex.ONES[radix]; } long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Math.min(ν.precision(), z.precision()), extraPrecision); ν = ApfloatHelper.ensurePrecision(ν, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apcomplex result = cos(ν.multiply(acos(z, precision))); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Chebyshev function of the second kind. For integer values of ν gives the Chebyshev polynomial of the second kind.

* * @param ν The first argument. * @param z The second argument. * * @return Uν(z) * * @throws ArithmeticException If z is -1 and ν is not an integer. * * @since 1.14.0 */ public static Apcomplex chebyshevU(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { int radix = ν.radix(); Apint one = Apint.ONES[radix]; if (ν.isZero() && z.isZero()) { return one; } if (z.equals(one)) { return one.add(ν); } if (z.equals(one.negate()) && ν.isInteger()) { Apcomplex result = one.add(ν); boolean negate = (ν.real().truncate().mod(new Apint(2, radix)).signum() != 0); return (negate ? result.negate() : result); } long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Math.min(ν.precision(), z.precision()), extraPrecision); ν = ApfloatHelper.ensurePrecision(ν, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apcomplex result = sin(ν.add(one).multiply(acos(z, precision))).multiply(inverseRoot(one.subtract(pow(z, 2)), 2)); return ApfloatHelper.reducePrecision(result, extraPrecision); } /** * Renormalized Gegenbauer function.

* * @param ν The first argument. * @param z The second argument. * * @return Cν(0)(z) * * @throws ArithmeticException If ν is zero. * * @since 1.14.0 */ public static Apcomplex gegenbauerC(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { Apint two = new Apint(2, ν.radix()); return two.divide(ν).multiply(chebyshevT(ν, z)); } /** * Gegenbauer function. For nonnegative integer values of ν gives the Gegenbauer polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param λ The second argument. * @param z The third argument. * * @return Cνλ(z) * * @throws ArithmeticException If z is -1 and real part of λ is > 1/2. Also if z is -1 and λ is 1/2 and ν is not an integer. * * @since 1.14.0 */ public static Apcomplex gegenbauerC(Apcomplex ν, Apcomplex λ, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (λ.isZero()) { return λ; } if (ν.isInteger() && ν.real().signum() >= 0) { return gegenbauerC(ApfloatHelper.longValueExact(ν.real().truncate()), λ, z); } int radix = ν.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Util.min(ν.precision(), λ.precision(), z.precision()), extraPrecision); ν = ApfloatHelper.ensurePrecision(ν, precision); λ = ApfloatHelper.ensurePrecision(λ, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apfloat one = Apint.ONES[radix], two = new Apfloat(2, precision, radix), pi = ApfloatMath.pi(precision, radix); Apcomplex λ12 = ApfloatHelper.ensurePrecision(one.subtract(two.multiply(λ)), precision), νλ = ApfloatHelper.ensurePrecision(ν.add(λ), precision), ν1 = ApfloatHelper.ensurePrecision(ν.add(one), precision), λ2ν = ApfloatHelper.ensurePrecision(two.multiply(λ).add(ν), precision), λhalf = ApfloatHelper.ensurePrecision(λ.add(one.divide(two)), precision), z12 = ApfloatHelper.ensurePrecision(one.subtract(z), precision).divide(two), result; if (isNonPositiveInteger(ν1)) { if (isNonPositiveInteger(λ)) { return Apint.ZEROS[radix]; } result = pochhammer(ν1, λ12.negate()).divide(gamma(ApfloatHelper.ensureGammaPrecision(λ, precision))); } else { result = pochhammer(λ, νλ).divide(gamma(ApfloatHelper.ensureGammaPrecision(ν1, precision))); } if (result.isZero()) { return result; } result = result.multiply(pow(two, λ12)).multiply(sqrt(pi)).multiply(hypergeometric2F1Regularized(ν.negate(), λ2ν, λhalf, z12)); return ApfloatHelper.reducePrecision(result, extraPrecision); } private static Apcomplex gegenbauerC(long n, Apcomplex λ, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { long precision = Math.min(λ.precision(), z.precision()); int radix = λ.radix(); if (n == 0) { return new Apfloat(1, precision, radix); } precision = ApfloatHelper.extendPrecision(precision); λ = ApfloatHelper.ensurePrecision(λ, precision); z = ApfloatHelper.ensurePrecision(z, precision); long n2 = n / 2, k = n2, n2k = n - 2 * k; Apcomplex sum = Apint.ZEROS[radix], z2 = z.multiply(new Apint(2, radix)), numerator = pochhammer(λ, n - k).multiply(n2k == 0 ? Apint.ONES[radix] : z2), denominator = ApfloatMath.factorial(k, precision, radix).multiply(ApfloatMath.factorial(n2k, precision, radix)); z2 = z2.multiply(z2); for (; k >= 0; k--, n2k += 2) { if (k < n2) { numerator = numerator.multiply(λ.add(new Apint(n - k - 1, radix))).multiply(z2); denominator = denominator.multiply(new Apint(n2k - 1, radix)).multiply(new Apint(n2k, radix)); } Apcomplex term = numerator.divide(denominator); sum = ((k & 1) == 0 ? sum.add(term) : sum.subtract(term)); if (k > 0) { numerator = numerator.multiply(new Apint(k, radix)); } } return ApfloatHelper.reducePrecision(sum); } /** * Jacobi function. For nonnegative integer values of ν gives the Jacobi polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param a The second argument. * @param b The third argument. * @param z The fourth argument. * * @return Pν(a,b)(z) * * @throws ArithmeticException If z is -1 and real part of b is > 0 and ν is not a positive integer. Also if ν + a is a negative integer and ν is not an integer. * * @since 1.14.0 */ public static Apcomplex jacobiP(Apcomplex ν, Apcomplex a, Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (ν.isInteger() && ν.real().signum() >= 0) { return jacobiP(ApfloatHelper.longValueExact(ν.real().truncate()), a, b, z); } int radix = ν.radix(); long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(Util.min(ν.precision(), a.precision(), b.precision(), z.precision()), extraPrecision); ν = ApfloatHelper.ensurePrecision(ν, precision); a = ApfloatHelper.ensurePrecision(a, precision); b = ApfloatHelper.ensurePrecision(b, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apint one = Apint.ONES[radix], two = new Apint(2, radix); Apcomplex ν1 = ApfloatHelper.ensurePrecision(ν.add(one), precision), abν1 = ApfloatHelper.ensurePrecision(a.add(b).add(ν).add(one), precision), a1 = ApfloatHelper.ensurePrecision(a.add(one), precision), z12 = ApfloatHelper.ensurePrecision(one.subtract(z), precision).divide(two), result = pochhammer(ν1, a).multiply(hypergeometric2F1Regularized(ν.negate(), abν1, a1, z12)); return ApfloatHelper.reducePrecision(result, extraPrecision); } private static Apcomplex jacobiP(long n, Apcomplex a, Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { long precision = Util.min(a.precision(), b.precision(), z.precision()); int radix = a.radix(); if (n == 0) { return new Apfloat(1, precision, radix); } precision = ApfloatHelper.extendPrecision(precision); a = ApfloatHelper.ensurePrecision(a, precision); b = ApfloatHelper.ensurePrecision(b, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apint one = Apint.ONES[radix], two = new Apint(2, radix); Apcomplex sum = Apint.ZEROS[radix], a1 = ApfloatHelper.ensurePrecision(a.add(one), precision), abn1 = ApfloatHelper.ensurePrecision(a1.add(b).add(new Apint(n, radix)), precision), z12 = ApfloatHelper.ensurePrecision(one.subtract(z), precision).divide(two), numerator = one, denominator = ApfloatMath.factorial(n, precision, radix); for (long k = 0; k <= n; k++) { Apint kk = new Apint(k, radix); Apcomplex term = numerator.multiply(pochhammer(a1.add(kk), n - k)).divide(denominator); sum = sum.add(term); if (k < n) { Apcomplex abnk1 = ApfloatHelper.ensurePrecision(abn1.add(kk), precision); numerator = numerator.multiply(new Apint(-n + k, radix)).multiply(abnk1).multiply(z12); denominator = denominator.multiply(kk.add(one)); } } return ApfloatHelper.reducePrecision(sum); } /** * Fibonacci function. For nonnegative integer values of ν gives the Fibonacci polynomial.

* * @param ν The first argument. * @param z The second argument. * * @return Fν(z) * * @throws ArithmeticException If z is -1 and ν is not an integer. * * @since 1.14.0 */ public static Apcomplex fibonacci(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { int radix = ν.radix(); long targetPrecision = Math.min(ν.precision(), z.precision()), extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix), precision = ApfloatHelper.extendPrecision(targetPrecision, extraPrecision); ν = ApfloatHelper.ensurePrecision(ν, precision); z = ApfloatHelper.ensurePrecision(z, precision); Apint zero = Apfloat.ZEROS[radix], two = new Apint(2, radix), four = new Apint(4, radix); Apcomplex twoI = new Apcomplex(zero, two), result; if (ν.isInteger() && (z.equals(twoI) || z.equals(twoI.negate()))) { long n = ν.real().truncate().mod(four).longValueExact(); Apcomplex i = new Apcomplex(zero, new Apint(z.imag().signum() < 0 ? -1 : 1, radix)); result = pow(i, n + 1).multiply(ν).negate(); } else { Apfloat pi = ApfloatMath.pi(precision, radix); Apcomplex ν2 = pow(two, ν), z4 = sqrt(ApfloatHelper.ensurePrecision(z.multiply(z).add(four), precision)), zz4ν = pow(ApfloatHelper.ensurePrecision(z.add(z4), precision), ν); result = zz4ν.divide(ν2).subtract(cos(pi.multiply(ν)).multiply(ν2).divide(zz4ν)).divide(z4); } targetPrecision = ApfloatHelper.reducePrecision(targetPrecision, Math.max(0, (long) Math.log(result.scale() * 0.3))); return ApfloatHelper.limitPrecision(result, targetPrecision); } /** * Euler polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param n The first argument. * @param z The second argument. * * @return En(z) * * @throws IllegalArgumentException If n < 0. * * @since 1.14.0 */ public static Apcomplex eulerE(long n, Apcomplex z) throws IllegalArgumentException, ApfloatRuntimeException { return eulerE(n, z, z.precision()); } static Apcomplex eulerE(long n, Apcomplex z, long precision) throws IllegalArgumentException, ApfloatRuntimeException { if (n < 0) { throw new IllegalArgumentException("Negative Euler polynomial"); } int radix = z.radix(); long n1 = Util.addExact(n, 1); if (z.isZero()) { if (n > 0 && (n & 1) == 0) { return z; } if (precision == Apfloat.INFINITE) { Apint one = Apint.ONES[radix], two = new Apint(2, radix); return AprationalMath.bernoulli(n1, radix).multiply(two).multiply(ApintMath.pow(two, n1).subtract(one)).divide(new Apint(n1, radix)).negate(); } } if (n == 0) { return new Apfloat(1, precision, radix); } long extraPrecision = (long) Math.ceil(2.7 * n / Math.log(radix)), workingPrecision = ApfloatHelper.extendPrecision(precision, extraPrecision); z = ApfloatHelper.ensurePrecision(z, workingPrecision); Apfloat two = new Apfloat(2, workingPrecision, radix), nn = new Apfloat(-n, workingPrecision, radix); Apcomplex result = two.multiply(pow(two, n1).multiply(zeta(nn, z.divide(two))).subtract(zeta(nn, z))); return ApfloatHelper.limitPrecision(result, precision); } /** * Bernoulli polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param n The first argument. * @param z The second argument. * * @return Bn(z) * * @throws IllegalArgumentException If n < 0. * * @since 1.14.0 */ public static Apcomplex bernoulliB(long n, Apcomplex z) throws IllegalArgumentException, ApfloatRuntimeException { return bernoulliB(n, z, z.precision()); } static Apcomplex bernoulliB(long n, Apcomplex z, long precision) throws IllegalArgumentException, ApfloatRuntimeException { if (n < 0) { throw new IllegalArgumentException("Negative Bernoulli polynomial"); } int radix = z.radix(); if (z.isZero()) { if (n > 1 && (n & 1) == 1) { return z; } if (precision == Apfloat.INFINITE) { return AprationalMath.bernoulli(n, radix); } } if (n == 0) { return new Apfloat(1, precision, radix); } long extraPrecision = (long) Math.ceil(2.7 * n / Math.log(radix)), workingPrecision = ApfloatHelper.extendPrecision(precision, extraPrecision); z = ApfloatHelper.ensurePrecision(z, workingPrecision); Apfloat nn = new Apfloat(-n, workingPrecision, radix), n1 = new Apfloat(1 - n, workingPrecision, radix); Apcomplex result = nn.multiply(zeta(n1, z)); return ApfloatHelper.limitPrecision(result, precision); } /** * Harmonic number.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The argument. * * @return Hz * * @throws ArithmeticException If z is a negative integer. * * @since 1.14.0 */ public static Apcomplex harmonicNumber(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (z.isZero()) { return z; } long precision = z.precision(); int radix = z.radix(); Apint one = Apint.ONES[radix]; Apfloat eulerGamma = ApfloatMath.euler(precision, radix); Apcomplex z1 = ApfloatHelper.ensurePrecision(z.add(one), precision); return digamma(z1).add(eulerGamma); } /** * Generalized harmonic number.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param z The first argument. * @param r The second argument. * * @return Hz(r) * * @throws ArithmeticException If z is a negative integer, unless r has a negative real part or is zero. * * @since 1.14.0 */ public static Apcomplex harmonicNumber(Apcomplex z, Apcomplex r) throws ArithmeticException, ApfloatRuntimeException { if (z.isZero() || r.isZero()) { return z; } int radix = z.radix(); Apint one = Apint.ONES[radix]; if (r.equals(one)) { return harmonicNumber(z); } long precision = Math.min(z.precision(), r.precision()); Apcomplex z1 = ApfloatHelper.ensurePrecision(z.add(one), precision); return zeta(r).subtract(zeta(r, z1)); } /** * Polylogarithm.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param z The second argument. * * @return Liν(z) * * @throws ArithmeticException If the real part of ν is ≤ 1 and z is 1. * * @since 1.14.0 */ public static Apcomplex polylog(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (z.isZero()) { return z; } int radix = ν.radix(); long targetPrecision = Math.min(ν.precision(), z.precision()), extraPrecision = (long) Math.ceil(Math.max(ApfloatHelper.getSmallExtraPrecision(radix), 2.7 * ApfloatHelper.longValueExact(ν.real().ceil()) / Math.log(radix))), precision = ApfloatHelper.extendPrecision(targetPrecision, extraPrecision); Apint zero = Apint.ZEROS[radix], one = Apint.ONES[radix], two = new Apint(2, radix); if (z.equals(one) && ν.real().compareTo(one) <= 0) { throw new ArithmeticException("Polylogarithm is infinite"); } if (ν.isInteger() && ν.real().signum() > 0) { // Avoid gamma of nonpositive integer ν = ν.precision(Apfloat.INFINITE).add(scale(new Apfloat("0.1", precision, radix), -precision)); precision = Util.ifFinite(precision, precision + precision); } else if (ν.real().signum() > 0) { Apint νRounded = RoundingHelper.roundToInteger(ν.real(), RoundingMode.HALF_EVEN).truncate(); long digitLoss = Math.min(precision, -ν.subtract(νRounded).scale()); if (digitLoss > 0) { precision = Util.ifFinite(precision, precision + digitLoss); } } ν = ApfloatHelper.ensurePrecision(ν, precision); z = ApfloatHelper.ensurePrecision(z, precision); if (ν.isZero()) { // Avoid zeta of one Apcomplex z1 = ApfloatHelper.ensurePrecision(one.subtract(z), precision); return ApfloatHelper.limitPrecision(z.divide(z1), targetPrecision); } Apfloat pi = ApfloatMath.pi(precision, radix); boolean unitLine = (z.imag().signum() == 0 && z.real().signum() > 0 && z.real().compareTo(one) < 0); Apcomplex i = new Apcomplex(zero, one), epiνi2 = exp(pi.multiply(ν).multiply(i).divide(two)), zn = (unitLine ? z : z.negate()), offset = (unitLine ? zero : pi.multiply(i)), ν1 = ApfloatHelper.ensurePrecision(ν.subtract(one), precision), logznpi2i = ApfloatHelper.ensurePrecision(log(zn).add(offset), precision).divide(pi.multiply(two).multiply(i)), oneMinusLogznpi2i = ApfloatHelper.ensurePrecision(one.subtract(logznpi2i), precision), result = pow(two.multiply(pi), ν1).multiply(i).multiply(gamma(ApfloatHelper.ensureGammaPrecision(ν1.negate(), precision))).multiply(zeta(ν1.negate(), logznpi2i).divide(epiνi2).subtract(epiνi2.multiply(zeta(ν1.negate(), oneMinusLogznpi2i)))); targetPrecision = ApfloatHelper.reducePrecision(targetPrecision, Math.max(0, (long) Math.log(result.scale() * 0.3))); return ApfloatHelper.limitPrecision(result, targetPrecision); } /** * Logistic sigmoid. * * @param z The argument. * * @return σ(z) * * @throws ArithmeticException If z is an odd integer multiple of π i. * * @since 1.14.0 */ public static Apcomplex logisticSigmoid(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { int radix = z.radix(); Apint one = Apint.ONES[radix]; if (z.isZero()) { Apint two = new Apint(2, radix); return new Aprational(one, two); } long precision = z.precision(); Apint minusOne = new Apint(-1, radix); Apcomplex e = (z.scale() < -precision ? one : exp(z.negate())); return one.precision(precision).divide(one.precision(ApfloatHelper.extendPrecision(precision, e.equalDigits(minusOne))).add(e)); } /** * Returns the unit in the last place of the argument, considering the * scale and precision. This is maximum of the ulps of the real and * imaginary part of the argument. * If the precision of the argument is infinite, zero is returned. * * @param z The argument. * * @return The ulp of the argument. * * @since 1.10.0 */ public static Apfloat ulp(Apcomplex z) { return ApfloatMath.max(ApfloatMath.ulp(z.real()), ApfloatMath.ulp(z.imag())); } // Extend the precision on last iteration private static Apcomplex lastIterationExtendPrecision(int iterations, int precisingIteration, Apcomplex z) { return (iterations == 0 && precisingIteration != 0 ? ApfloatHelper.extendPrecision(z) : z); } static boolean isNonPositiveInteger(Apcomplex z) { return (z.isInteger() && z.real().signum() <= 0); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/Apfloat.java000066400000000000000000001314041461767713300237750ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.BigInteger; import java.math.BigDecimal; import java.io.PushbackReader; import java.io.Writer; import java.io.IOException; import java.util.Formatter; import static java.util.FormattableFlags.*; import org.apfloat.spi.ApfloatImpl; /** * Arbitrary precision floating-point number class.

* * Apfloat numbers are immutable.

* * A pitfall exists with the constructors {@link #Apfloat(float,long)} * and {@link #Apfloat(double,long)}. Since floats and * doubles are always represented internally in radix 2, the * conversion to any other radix usually causes round-off errors, and the * resulting apfloat won't be accurate to the desired number of digits.

* * For example, 0.3 can't be presented exactly in base 2. When * you construct an apfloat like new Apfloat(0.3f, 1000), the * resulting number won't be accurate to 1000 digits, but only to roughly 7 * digits (in radix 10). In fact, the resulting number will be something like * 0.30000001192092896...

* * If you want an exact representation of a floating-point primitive * (which is a rational number), you can use {@link Aprational#Aprational(double)}. * * @see ApfloatMath * * @version 1.11.1 * @author Mikko Tommila */ public class Apfloat extends Apcomplex implements Comparable { /** * Default constructor. To be used only by subclasses that * overload all needed methods. */ protected Apfloat() { } /** * Constructs an apfloat that is backed by the specified * ApfloatImpl object. * * @param impl The ApfloatImpl object backing this apfloat. */ protected Apfloat(ApfloatImpl impl) { assert (impl.precision() > 0); this.impl = impl; } /** * Constructs an apfloat from the specified string. * The default radix will be used.

* * The precision will be calculated from the number * of digits specified in the string. For example:

* * "0.1" will have a precision of 1 digit.
* "1.0" will have a precision of 2 digits.
* "100" will have a precision of 3 digits.
* * @param value The string representing the number. * * @exception NumberFormatException In case the number is invalid. */ public Apfloat(String value) throws NumberFormatException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, false)); } /** * Constructs an apfloat from the specified string and precision. * The default radix will be used. * * @param value The string representing the number. * @param precision The precision of the number. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(String value, long precision) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision, false)); } /** * Constructs an apfloat from the specified string, precision and radix.

* * Note that it's impossible to construct apfloats with a specified exponent * and with radix >= 14, since the characters 'e' and 'E' will be treated as * digits of the mantissa.

* * For example, in radix 10, "1e5" means the decimal number 100000. But in * radix 16, "1e5" means the decimal number 485. * * @param value The string representing the number. * @param precision The precision of the number. * @param radix The radix of the number. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(String value, long precision, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision, radix, false)); } /** * Constructs an apfloat from the specified long. * The default radix will be used. The precision of the number * will be {@link #INFINITE}. * * @param value The value of the number. * * @exception NumberFormatException In case the number is invalid. */ public Apfloat(long value) throws NumberFormatException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value)); } /** * Constructs an apfloat from the specified long * and precision. The default radix will be used. * * @param value The value of the number. * @param precision The precision of the number. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(long value, long precision) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision)); } /** * Constructs an apfloat from the specified long, * precision and radix. * * @param value The value of the number. * @param precision The precision of the number. * @param radix The radix of the number. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(long value, long precision, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision, radix)); } /** * Constructs an apfloat from the specified float. * The default radix will be used. The precision of the number * will be the precision of a float in the default * radix, for example in radix 10 the precision is 7 digits. * * @param value The value of the number. * * @exception NumberFormatException In case the number is invalid. */ public Apfloat(float value) throws NumberFormatException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value)); } /** * Constructs an apfloat from the specified float * and precision. The default radix will be used.

* * Note that the resulting apfloat won't accurately represent the given * float value to more than the default precision of a * float, for example in radix 10 the result is accurate to * only 7 digits. The rest of the digits are unspecified even if a greater * precision is specified. * * @param value The value of the number. * @param precision The precision of the number. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(float value, long precision) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision)); } /** * Constructs an apfloat from the specified float, * precision and radix.

* * Note that the resulting apfloat won't accurately represent the given * float value to more than the default precision of a * float, for example in radix 10 the result is accurate to * only 7 digits. The rest of the digits are unspecified even if a greater * precision is specified. * * @param value The value of the number. * @param precision The precision of the number. * @param radix The radix of the number. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(float value, long precision, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision, radix)); } /** * Constructs an apfloat from the specified double. * The default radix will be used. The precision of the number * will be the precision of a double in the default * radix, for example in radix 10 the precision is 16 digits. * * @param value The value of the number. * * @exception NumberFormatException In case the number is invalid. */ public Apfloat(double value) throws NumberFormatException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value)); } /** * Constructs an apfloat from the specified double * and precision. The default radix will be used.

* * Note that the resulting apfloat won't accurately represent the given * double value to more than the default precision of a * double, for example in radix 10 the result is accurate to * only 16 digits. The rest of the digits are unspecified even if a greater * precision is specified.

* * In particular, this constructor does not work the same way as the * {@link BigDecimal#BigDecimal(double)} constructor. If you want that kind * of behavior then please use the {@link #Apfloat(BigDecimal, long)} * constructor. * * @param value The value of the number. * @param precision The precision of the number. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(double value, long precision) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision)); } /** * Constructs an apfloat from the specified double, * precision and radix.

* * Note that the resulting apfloat won't accurately represent the given * double value to more than the default precision of a * double, for example in radix 10 the result is accurate to * only 16 digits. The rest of the digits are unspecified even if a greater * precision is specified.

* * In particular, this constructor does not work the same way as the * {@link BigDecimal#BigDecimal(double)} constructor. If you want that kind * of behavior then please use the {@link #Apfloat(BigDecimal, long)} * constructor. * * @param value The value of the number. * @param precision The precision of the number. * @param radix The radix of the number. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(double value, long precision, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision, radix)); } /** * Reads an apfloat from a stream using default precision and radix. * The stream needs to be a PushbackReader, * as the first invalid character is pushed back to the stream.

* * Note that since only a pushback buffer of one character is used, * the number read may still not be valid. For example, if the stream * contains "-#" or "1.5e#" (here '#' * is the first invalid character), the number is actually not valid, and * only the character '#' would be put back to the stream.

* * The precision is determined similarly as in the {@link #Apfloat(String)} * constructor that is as the number of digits read from the stream. * * @param in The stream to read from * * @exception IOException If an I/O error occurs accessing the stream. * @exception NumberFormatException If the number is not valid. */ public Apfloat(PushbackReader in) throws IOException, NumberFormatException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(in, false)); } /** * Reads an apfloat from a stream using the specified precision. * The default radix is used. * * @param in The stream to read from * @param precision The precision of the number. * * @exception IOException If an I/O error occurs accessing the stream. * @exception NumberFormatException If the number is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @see #Apfloat(PushbackReader) */ public Apfloat(PushbackReader in, long precision) throws IOException, NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(in, precision, false)); } /** * Reads an apfloat from a stream using the specified precision * and radix. * * @param in The stream to read from * @param precision The precision of the number. * @param radix The radix of the number. * * @exception IOException If an I/O error occurs accessing the stream. * @exception NumberFormatException If the number is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @see #Apfloat(PushbackReader) */ public Apfloat(PushbackReader in, long precision, int radix) throws IOException, NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(in, precision, radix, false)); } /** * Constructs an apfloat from a BigInteger. * Precision will be {@link #INFINITE} and the default radix * is used. * * @param value The value of the number. * * @exception NumberFormatException If the default radix is not valid. */ public Apfloat(BigInteger value) throws NumberFormatException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value)); } /** * Constructs an apfloat from a BigInteger with * the specified precision. The default radix is used. * * @param value The value of the number. * @param precision The precision of the number. * * @exception NumberFormatException If the default radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(BigInteger value, long precision) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision)); } /** * Constructs an apfloat from a BigInteger with * the specified precision and radix. * * @param value The value of the number. * @param precision The precision of the number. * @param radix The radix of the number. * * @exception NumberFormatException If the radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(BigInteger value, long precision, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision, radix)); } /** * Creates an apfloat from a BigDecimal. An apfloat created this * way will always have radix 10 regardless of the current default radix. * * @param value The value to use. */ public Apfloat(BigDecimal value) throws ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value)); } /** * Creates an apfloat from a BigDecimal. An apfloat created this * way will always have radix 10 regardless of the current default radix. * * @param value The value to use. * @param precision The precision to use, in decimal digits. * * @exception IllegalArgumentException In case the precision is invalid. */ public Apfloat(BigDecimal value, long precision) throws IllegalArgumentException, ApfloatRuntimeException { this(ApfloatHelper.createApfloat(value, precision)); } /** * Radix of this apfloat. * * @return Radix of this apfloat. */ @Override public int radix() { return this.impl.radix(); } /** * Real part of this apfloat. * * @return this */ @Override public Apfloat real() { return this; } /** * Imaginary part of this apfloat. * * @return {@link #ZERO} */ @Override public Apfloat imag() { return Apfloat.ZEROS[radix()]; } /** * Returns the precision of this apfloat. * * @return The precision of this apfloat in number of digits of the radix in which it's presented. */ @Override public long precision() throws ApfloatRuntimeException { return this.impl.precision(); } /** * Returns an apfloat with the same value as this apfloat accurate to the * specified precision.

* * If the requested precision less than this number's current precision, the * functionality is quite obvious: the precision is simply truncated, and e.g. * comparison and equality checking will work as expected. Some rounding errors * in e.g. addition and subtraction may still occur, as "invisible" trailing * digits can remain in the number.

* * If the requested precision more than this number's current precision, the * functionality is quite undefined: the digits up to this number's current * precision are guaranteed to be the same, but the "new" digits are undefined: * they may be zero, or they may be digits that have been previously discarded * with a call to precision() with a smaller number of digits, or they may be * something else, or any combination of these.

* * These limitations allow various performance optimizations to be made. * * @param precision Precision of the new apfloat. * * @return An apfloat with the specified precision and same value as this apfloat. * * @exception IllegalArgumentException If precision is <= 0. */ @Override public Apfloat precision(long precision) throws IllegalArgumentException, ApfloatRuntimeException { ApfloatHelper.checkPrecision(precision); return new Apfloat(getImpl(precision)); } /** * Returns the scale of this apfloat. The scale is defined here as

* * apfloat = signum * mantissa * radixscale

* * where 1/radix <= mantissa < 1. In other words, * scale = floor(logradix(apfloat)) + 1.

* * For example, 1 has a scale of 1, and 100 has a scale of 3 (in radix 10). * For integers, scale is equal to the number of digits in the apfloat.

* * Zero has a scale of -INFINITE.

* * Note that this definition of scale is different than in java.math.BigDecimal. * * @return The exponent of this apfloat in number of digits of the radix in which it's presented. */ @Override public long scale() throws ApfloatRuntimeException { if (signum() == 0) { return -INFINITE; } else { return this.impl.scale(); } } /** * Returns the size of this apfloat. The size is defined here as

* * apfloat = signum * mantissa * radixscale and

* mantissa = n / radixsize

* * where 1/radix <= mantissa < 1 and n is the smallest possible integer. * In other words, the size is the number of significant digits in the * mantissa (excluding leading and trailing zeros but including all zeros * between the first and last nonzero digit). * * For example, 1 has a size of 1, and 100 has also a size of 1 (in radix 10). * 11 has a size of 2, and 10001000 has a size of 5.

* * Zero has a size of 0. * * @return The number of digits in this number, from the most significant digit to the least significant nonzero digit, in the radix in which it's presented. * * @since 1.6 */ @Override public long size() throws ApfloatRuntimeException { if (signum() == 0) { return 0; } else { return this.impl.size(); } } /** * Returns the signum function of this apfloat. * * @return -1, 0 or 1 as the value of this apfloat is negative, zero or positive, correspondingly. */ public int signum() { return this.impl.signum(); } /** * Returns if this number has an integer value. Note that this does not * necessarily mean that this object is an instance of {@link Apint}. * Neither does it mean that the precision is infinite. * * @return If this number's value is an integer. * * @since 1.9.0 */ @Override public boolean isInteger() throws ApfloatRuntimeException { return signum() == 0 || size() <= scale(); } /** * Returns if this apfloat is "short". In practice an apfloat is "short" if its * mantissa fits in one machine word. If the apfloat is "short", some algorithms * can be performed faster.

* * For example, division by a "short" apfloat requires only a single pass through * the data, but that algorithm can't be used for divisors that aren't "short", * where calculating an inverse root is required instead.

* * The return value of this method is implementation dependent. * * @return true if the apfloat is "short", false if not. */ public boolean isShort() throws ApfloatRuntimeException { return this.impl.isShort(); } /** * Negative value. * * @return -this. * * @since 1.1 */ @Override public Apfloat negate() throws ApfloatRuntimeException { return new Apfloat(this.impl.negate()); } /** * Adds two apfloats. * * @param x The number to be added to this number. * * @return this + x. */ public Apfloat add(Apfloat x) throws ApfloatRuntimeException { if (x.signum() == 0) { // x + 0 = x return this; } else if (signum() == 0) { // 0 + x = x return x; } return addOrSubtract(x, false); } /** * Subtracts two apfloats. * * @param x The number to be subtracted from this number. * * @return this - x. */ public Apfloat subtract(Apfloat x) throws ApfloatRuntimeException { if (x.signum() == 0) { // x - 0 = x return this; } else if (signum() == 0) { ApfloatImpl impl = x.getImpl(); impl = impl.negate(); return new Apfloat(impl); } return addOrSubtract(x, true); } private Apfloat addOrSubtract(Apfloat x, boolean subtract) throws ApfloatRuntimeException { long[] precisions = ApfloatHelper.getMatchingPrecisions(this, x); ApfloatImpl impl; if (precisions[0] == 0) { impl = x.getImpl(precisions[1]); if (subtract) { impl = impl.negate(); } } else if (precisions[1] == 0) { impl = getImpl(precisions[0]); } else { impl = getImpl(precisions[0]); ApfloatImpl xImpl = x.getImpl(precisions[1]); impl = impl.addOrSubtract(xImpl, subtract); } return new Apfloat(impl); } /** * Multiplies two apfloats. * * @param x The number to be multiplied by this number. * * @return this * x. */ public Apfloat multiply(Apfloat x) throws ApfloatRuntimeException { if (signum() == 0) { // 0 * x = 0 return this; } else if (x.signum() == 0) { // x * 0 = 0 return x; } else if (equals(ONE)) { // 1 * x = x return x.precision(Math.min(precision(), x.precision())); } else if (x.equals(ONE)) { // x * 1 = x return precision(Math.min(precision(), x.precision())); } long targetPrecision = Math.min(precision(), x.precision()); ApfloatImpl thisImpl = getImpl(targetPrecision), xImpl = x.getImpl(targetPrecision), impl = thisImpl.multiply(xImpl); return new Apfloat(impl); } /** * Divides two apfloats. * * @param x The number by which this number is to be divided. * * @return this / x. * * @exception ArithmeticException In case the divisor is zero. */ public Apfloat divide(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0) { throw new ArithmeticException(signum() == 0 ? "Zero divided by zero" : "Division by zero"); } else if (signum() == 0) { // 0 / x = 0 return this; } else if (x.equals(ONE)) { // x / 1 = x return precision(Math.min(precision(), x.precision())); } long targetPrecision = Math.min(precision(), x.precision()); if (x.isShort()) { ApfloatImpl thisImpl = getImpl(targetPrecision), xImpl = x.getImpl(targetPrecision), impl = thisImpl.divideShort(xImpl); return new Apfloat(impl); } else { Apfloat inverse = ApfloatMath.inverseRoot(x, 1, targetPrecision); return multiply(inverse); } } /** * Calculates the remainder when divided by an apfloat. * The result has the same sign as this number. * If x is zero, then zero is returned. * * @param x The number that is used as the divisor in the remainder calculation. * * @return this % x. * * @see ApfloatMath#fmod(Apfloat,Apfloat) * * @since 1.2 */ public Apfloat mod(Apfloat x) throws ApfloatRuntimeException { return ApfloatMath.fmod(this, x); } /** * Floor function. Returns the largest (closest to positive infinity) value * that is not greater than this apfloat and is equal to a mathematical integer. * * @return This apfloat rounded towards negative infinity. */ public Apint floor() throws ApfloatRuntimeException { if (signum() >= 0) { return new Apint(new Apfloat(this.impl.absFloor())); } else { return new Apint(new Apfloat(this.impl.absCeil())); } } /** * Ceiling function. Returns the smallest (closest to negative infinity) value * that is not less than this apfloat and is equal to a mathematical integer. * * @return This apfloat rounded towards positive infinity. */ public Apint ceil() throws ApfloatRuntimeException { if (signum() >= 0) { return new Apint(new Apfloat(this.impl.absCeil())); } else { return new Apint(new Apfloat(this.impl.absFloor())); } } /** * Truncates fractional part. * * @return This apfloat rounded towards zero. */ public Apint truncate() throws ApfloatRuntimeException { return new Apint(new Apfloat(this.impl.absFloor())); } /** * Returns the fractional part. The fractional part is always 0 <= abs(frac()) < 1. * The fractional part has the same sign as the number. For the fractional and integer parts, this always holds:

* * x = x.truncate() + x.frac() * * @return The fractional part of this apfloat. * * @since 1.7.0 */ public Apfloat frac() throws ApfloatRuntimeException { return new Apfloat(this.impl.frac()); } /** * Returns the value of the this number as a double. * If the number is too big to fit in a double, * Double.POSITIVE_INFINITY or * Double.NEGATIVE_INFINITY is returned. * * @return The numeric value represented by this object after conversion to type double. */ @Override public double doubleValue() { int targetPrecision = ApfloatHelper.getDoublePrecision(radix()); ApfloatImpl impl = getImpl(targetPrecision); return impl.doubleValue(); } /** * Returns the value of the this number as a float. * If the number is too big to fit in a float, * Float.POSITIVE_INFINITY or * Float.NEGATIVE_INFINITY is returned. * * @return The numeric value represented by this object after conversion to type float. */ @Override public float floatValue() { return (float) doubleValue(); } /** * Returns the value of the this number as a byte. * If the number is too big to fit in a byte, * Byte.MIN_VALUE or * Byte.MAX_VALUE is returned. * * @return The numeric value represented by this object after conversion to type byte. */ @Override public byte byteValue() { long longValue = longValue(); return (byte) Math.min(Math.max(longValue, Byte.MIN_VALUE), Byte.MAX_VALUE); } /** * Returns the value of the this number as a short. * If the number is too big to fit in a short, * Short.MIN_VALUE or * Short.MAX_VALUE is returned. * * @return The numeric value represented by this object after conversion to type short. */ @Override public short shortValue() { long longValue = longValue(); return (short) Math.min(Math.max(longValue, Short.MIN_VALUE), Short.MAX_VALUE); } /** * Returns the value of the this number as an int. * If the number is too big to fit in an int, * Integer.MIN_VALUE or * Integer.MAX_VALUE is returned. * * @return The numeric value represented by this object after conversion to type int. */ @Override public int intValue() { long longValue = longValue(); return (int) Math.min(Math.max(longValue, Integer.MIN_VALUE), Integer.MAX_VALUE); } /** * Returns the value of the this number as a long. * If the number is too big to fit in a long, * Long.MIN_VALUE or * Long.MAX_VALUE is returned. * * @return The numeric value represented by this object after conversion to type long. */ @Override public long longValue() { int targetPrecision = ApfloatHelper.getLongPrecision(radix()); ApfloatImpl impl = getImpl(targetPrecision); return impl.longValue(); } @Override public long longValueExact() throws ArithmeticException { if (!isInteger()) { throw new ArithmeticException("Rounding necessary"); } long value = longValue(); if (!new Apint(value, radix()).equals(truncate())) { throw new ArithmeticException("Out of range"); } return value; } /** * Computes number of equal digits.

* * Compares the digits of the numbers starting from the * most significant digits. The exponent and sign are * taken into consideration, so if either one doesn't match, * the numbers are considered to have zero equal digits.

* * For example, the numbers 12345 and 123456 have zero * matching digits, and the numbers 12345 and 12355 have * three matching digits.

* * The result of this method is roughly equal to * Math.min(scale(), x.scale()) - subtract(x).scale() * but it typically is a lot more efficient to execute. * * @param x Number to compare with. * * @return Number of matching digits in the radix in which the numbers are presented. */ public long equalDigits(Apfloat x) throws ApfloatRuntimeException { long targetPrecision = Math.min(precision(), x.precision()); ApfloatImpl thisImpl = getImpl(targetPrecision), xImpl = x.getImpl(targetPrecision); return thisImpl.equalDigits(xImpl); } /** * Convert this apfloat to the specified radix. * * @param radix The radix. * * @exception NumberFormatException If the radix is invalid. * * @since 1.2 */ @Override public Apfloat toRadix(int radix) throws NumberFormatException, ApfloatRuntimeException { return RadixConversionHelper.toRadix(this, radix); } /** * Compare this apfloat to the specified apfloat.

* * Note: if two apfloats are compared where one number doesn't have enough * precise digits, the mantissa is assumed to contain zeros. For example: * *

     * Apfloat x = new Apfloat("0.12", 2);
     * Apfloat y = new Apfloat("0.12345", 5);
     * 
* * Now x.compareTo(y) < 0 because x is assumed to * be 0.12000.

* * However, new Apfloat("0.12", 2) and new Apfloat("0.12", 5) * would be considered equal. * * @param x Apfloat to which this apfloat is to be compared. * * @return -1, 0 or 1 as this apfloat is numerically less than, equal to, or greater than x. */ @Override public int compareTo(Apfloat x) { if (x.preferCompare(this)) { // Special handling of aprationals return -x.compareTo(this); } else { // Compare with maximum available precision; would not be efficient with aprationals return getImpl().compareTo(x.getImpl()); } } /** * Tests if the comparison with equals and compareTo should be done in the opposite order.

* * Implementations should avoid infinite recursion. * * @param x The number to compare to. * * @return true if this object should invoke x.equals(this) and -x.compareTo(this) instead of comparing normally. * * @since 1.7.0 */ public boolean preferCompare(Apfloat x) { return false; } /** * Compares this object to the specified object.

* * Note: if two apfloats are compared where one number doesn't have enough * precise digits, the mantissa is assumed to contain zeros. * See {@link #compareTo(Apfloat)}. * * @param obj The object to compare with. * * @return true if the objects are equal; false otherwise. */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } else if (obj instanceof Apfloat) { Apfloat x = (Apfloat) obj; if (x.preferCompare(this)) { // Special handling of aprationals return x.equals(this); } return getImpl().equals(x.getImpl()); } else { return super.equals(obj); } } /** * Tests two apfloat numbers for equality. * Returns false if the numbers are definitely known to be not equal. * If true is returned, equality is unknown and should be verified by * calling {@link #equals(Object)}. * This method is usually significantly faster than calling equals(Object). * * @param x The number to test against. * * @return false if the numbers are definitely not equal, true if unknown. * * @since 1.10.0 */ public boolean test(Apfloat x) throws ApfloatRuntimeException { if (x.preferCompare(this)) { // Special handling of aprationals return x.test(this); } else { return signum() == x.signum() && scale() == x.scale() && size() == x.size(); } } /** * Returns a hash code for this apfloat. * * @return The hash code value for this object. */ @Override public int hashCode() { return this.impl.hashCode(); } /** * Returns a string representation of this apfloat. * * @param pretty true to use a fixed-point notation, false to use an exponential notation. * * @return A string representing this object. */ @Override public String toString(boolean pretty) throws ApfloatRuntimeException { return this.impl.toString(pretty); } /** * Write a string representation of this apfloat to a Writer. * * @param out The output Writer. * @param pretty true to use a fixed-point notation, false to use an exponential notation. * * @exception IOException In case of I/O error writing to the stream. */ @Override public void writeTo(Writer out, boolean pretty) throws IOException, ApfloatRuntimeException { this.impl.writeTo(out, pretty); } /** * Formats the object using the provided formatter.

* * The format specifiers affect the output as follows: *

    *
  • By default, the exponential notation is used.
  • *
  • If the alternate format is specified ('#'), then the fixed-point notation is used.
  • *
  • Width is the minimum number of characters output. Any padding is done using spaces. Padding is on the left by default.
  • *
  • If the '-' flag is specified, then the padding will be on the right.
  • *
  • The precision is the number of significant digts output. If the precision of the number exceeds the number of characters output, the rounding mode for output is undefined.
  • *
*

* * The decimal separator will be localized if the formatter specifies a locale. * The digits will be localized also, but only if the radix is less than or equal to 10. * * @param formatter The formatter. * @param flags The flags to modify the output format. * @param width The minimum number of characters to be written to the output, or -1 for no minimum. * @param precision The maximum number of characters to be written to the output, or -1 for no maximum. * * @since 1.3 */ @Override public void formatTo(Formatter formatter, int flags, int width, int precision) { Apfloat x = (precision == -1 ? this : ApfloatHelper.limitPrecision(this, precision)); try { Writer out = FormattingHelper.wrapAppendableWriter(formatter.out()); out = FormattingHelper.wrapLocalizeWriter(out, formatter, radix(), (flags & UPPERCASE) == UPPERCASE); if (width == -1) { x.writeTo(out, (flags & ALTERNATE) == ALTERNATE); } else { out = FormattingHelper.wrapPadWriter(out, (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY); x.writeTo(out, (flags & ALTERNATE) == ALTERNATE); FormattingHelper.finishPad(out, width); } } catch (IOException ioe) { // Ignore as we can't propagate it; unfortunately we can't set it to the formattable either } } /** * Returns an ApfloatImpl representing the actual instance * of this apfloat up to the requested precision.

* * For apfloats this is simply the underlying ApfloatImpl, * but e.g. the {@link Aprational} class implements this so that * it only returns an approximation of the rational number. * * @param precision Precision of the ApfloatImpl that is needed. * * @return An ApfloatImpl representing this object to the requested precision. */ protected ApfloatImpl getImpl(long precision) throws ApfloatRuntimeException { if (precision == precision()) { return this.impl; } else { return this.impl.precision(precision); } } // Round away from zero i.e. opposite direction of rounding than in truncate() Apint roundAway() throws ApfloatRuntimeException { return new Apint(new Apfloat(this.impl.absCeil())); } Apfloat scale(long scale) { return ApfloatMath.scale(this, scale); } Apfloat abs() { return ApfloatMath.abs(this); } int compareToHalf() { return RoundingHelper.compareToHalf(this); } private ApfloatImpl getImpl() throws ApfloatRuntimeException { long precision = precision(); return getImpl(precision); } private static final long serialVersionUID = -36707433458144439L; private ApfloatImpl impl; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ApfloatConfigurationException.java000066400000000000000000000043371461767713300304100ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; /** * Exception indicating an error in the apfloat configuration.

* * @since 1.5 * @version 1.5 * @author Mikko Tommila */ public class ApfloatConfigurationException extends ApfloatRuntimeException { /** * Constructs a new apfloat configuration exception with an empty detail message. */ public ApfloatConfigurationException() { } /** * Constructs a new apfloat configuration exception with the specified detail message. * * @param message The detail message. */ public ApfloatConfigurationException(String message) { super(message); } /** * Constructs a new apfloat configuration exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public ApfloatConfigurationException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ApfloatContext.java000066400000000000000000001475321461767713300253530ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; import java.util.Enumeration; import java.util.Map; import java.util.Properties; import java.util.ResourceBundle; import java.util.MissingResourceException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; import java.util.concurrent.Future; import org.apfloat.spi.BuilderFactory; import org.apfloat.spi.FilenameGenerator; import org.apfloat.spi.Util; /** * This class encapsulates the information needed by the apfloat implementation * to perform computations.

* * All environment related settings of an apfloat implementation are accessed * through an ApfloatContext. Such settings include for example * the implementation provider class, maximum memory size to be used, and * the file names that are used for temporary files.

* * For performance reasons, access to an ApfloatContext is not * synchronized. Presumably, this won't be a problem in most cases. But, if * the code needs to concurrently modify and access an ApfloatContext, all * access to it should be externally synchronized.

* * At simplest, there is just one ApfloatContext, the global * apfloat context. All settings in your application are retrieved through * it. The global context is created when the ApfloatContext * class is loaded, and it's thus always available.

* * Values for the different settings in the global apfloat context are specified * in the apfloat.properties file, found in the class path. Since * they are loaded via a ResourceBundle named "apfloat", you can * alternatively deploy a ResourceBundle class named "apfloat" in * your class path to avoid having a .properties file, or to define properties * dynamically at run time.

* * The different settings that can be specified in the apfloat.properties * file are as follows: * *

    *
  • builderFactory, name of the class set as in {@link #setBuilderFactory(BuilderFactory)}
  • *
  • defaultRadix, set as in {@link #setDefaultRadix(int)}
  • *
  • maxMemoryBlockSize, set as in {@link #setMaxMemoryBlockSize(long)}
  • *
  • cacheL1Size, set as in {@link #setCacheL1Size(int)}
  • *
  • cacheL2Size, set as in {@link #setCacheL2Size(int)}
  • *
  • cacheBurst, set as in {@link #setCacheBurst(int)}
  • *
  • memoryThreshold, set as in {@link #setMemoryThreshold(long)}
  • *
  • shredMemoryTreshold, set as in {@link #setSharedMemoryTreshold(long)}
  • *
  • blockSize, set as in {@link #setBlockSize(int)}
  • *
  • numberOfProcessors, set as in {@link #setNumberOfProcessors(int)}
  • *
  • filePath, set as in {@link #setProperty(String,String)} with property name {@link #FILE_PATH}
  • *
  • fileInitialValue, set as in {@link #setProperty(String,String)} with property name {@link #FILE_INITIAL_VALUE}
  • *
  • fileSuffix, set as in {@link #setProperty(String,String)} with property name {@link #FILE_SUFFIX}
  • *
  • cleanupAtExit, set as in {@link #setCleanupAtExit(boolean)}
  • *
*

* * It is also possible to override the settings in apfloat.properties * with system properties. They can be defined with the property names listed above, * prefixed with "apfloat.".

* * An example apfloat.properties file could contain the following: * *

 * builderFactory=org.apfloat.internal.IntBuilderFactory
 * defaultRadix=10
 * maxMemoryBlockSize=50331648
 * cacheL1Size=8192
 * cacheL2Size=262144
 * cacheBurst=32
 * memoryThreshold=65536
 * sharedMemoryTreshold=65536
 * blockSize=65536
 * numberOfProcessors=1
 * filePath=
 * fileInitialValue=0
 * fileSuffix=.ap
 * cleanupAtExit=true
 * 
* * A system property could be used to override any of the above, e.g. by setting * on the command line "-Dapfloat.defaultRadix=11".

* * The total memory size and the number of processors are detected automatically, * as reported by the Java runtime, if they are not specified in the configuration * bundle.

* * If you need to create a complex multithreaded application that performs * apfloat calculations in parallel using multiple threads, you may need to * change the ApfloatContext settings for the different working threads.

* * If thread-specific apfloat contexts are not specified, all threads will use * the global context. To set a thread specific context, you would typically * create a {@link #clone()} of the global (or other parent) context, and then * set that context to the thread using {@link #setThreadContext(ApfloatContext,Thread)}. * Note that if you do not create a clone of the context, the same context will still * be used, since it's passed by reference.

* * To optimize thread usage while waiting for another thread in a multithreaded * application it's recommended to use {@link #wait(Future)} instead of just * e.g. {@link Future#get()}. This allows threads that the library uses to * perform useful work (instead of just being idle) while waiting for the * Future to complete.

* * Typically you may need to set the following properties for each thread: *

    *
  • {@link #setNumberOfProcessors(int)}: Since the number of physical * processors available is fixed, you may want to limit the amount * of processors each thread can use. In many cases you will want each * thread to use exactly one processor, and create as many threads as * there are processors.
  • *
  • {@link #setMaxMemoryBlockSize(long)}: The physical memory is global * and its amount is fixed as well. Since all threads share the global * memory, you may want to limit the maximum amount of memory each thread * can use. If you do this, you will probably just split the amount of * memory between the threads, e.g. by dividing it equally. In this case * you should set each thread to have a separate shared memory lock with * {@link #setSharedMemoryLock(Object)}. In this solution all threads can * allocate their maximum allowed memory block at the same time, and still * the VM won't run out of memory.
    * Another possibility is to set the whole global memory size as the maximum * available for each thread, and use the same shared memory lock for every * thread. This is actually the default behavior, if you don't call * {@link #setMaxMemoryBlockSize(long)} nor {@link #setSharedMemoryLock(Object)}. * This way all threads can access the maximum amount of physical memory * available. The drawback is that the threads will synchronize on the * same memory block, so only one thread can use it at a time. This can * have a major effect on performance, if threads are idle, waiting to acquire * the shared memory lock for most of the time. To work around this, some * mechanism can be set up for pooling the threads competing for the same * lock, and executing the task using parallel threads from the thread pool. * For example the default apfloat multiplication algorithm uses such a * mechanism. Note that synchronization against the shared memory lock * will be used for all data blocks larger than the shared memory * threshold (see {@link #getSharedMemoryTreshold()}).
  • *
  • {@link #setFilenameGenerator(FilenameGenerator)}: When you clone an * ApfloatContext, the filename generator is by default shared. For most * situations this is fine. If you for some reason want to separate * the files generated in each thread, you can just set a new * FilenameGenerator for each thread. In this case it's essential to * configure the FilenameGenerators not to generate conflicting file * names. You can do this easily by specifying a different directory or * file suffix for each filename generator, or by specifying a different * starting value for the file names (e.g. 1000000, 2000000, 3000000, ...).
    * Setting the filename generator may also be relevant, if you use a * distributed computing platform where separate physical machines (or * at least separate VM processes) create temporary files in the same * shared disk storage. In this case it's also essential to configure the * different processes so that they do not generate conflicting file names.
  • *
*

* * The other settings are generally global and do not typically need to * be set differently for each thread.

* * Unfortunately, Java doesn't allow detecting automatically many of the * settings, such as cache sizes. Also, for optimal performance, it would * usually be desirable to set each thread's processor affinity (which * physical processor runs which thread), which is also not possible. * If these features are added to the Java platform in the future, they * may be added to the ApfloatContext API as well. * * @version 1.14.0 * @author Mikko Tommila */ public class ApfloatContext implements Cloneable { /** * Property name for specifying the apfloat builder factory class. */ public static final String BUILDER_FACTORY = "builderFactory"; /** * Property name for specifying the default radix. */ public static final String DEFAULT_RADIX = "defaultRadix"; /** * Property name for specifying the maximum memory block size. */ public static final String MAX_MEMORY_BLOCK_SIZE = "maxMemoryBlockSize"; /** * Property name for specifying the level 1 cache size. */ public static final String CACHE_L1_SIZE = "cacheL1Size"; /** * Property name for specifying the level 2 cache size. */ public static final String CACHE_L2_SIZE = "cacheL2Size"; /** * Property name for specifying the level 1 cache burst size. */ public static final String CACHE_BURST = "cacheBurst"; /** * Property name for specifying the apfloat memory threshold. */ public static final String MEMORY_THRESHOLD = "memoryThreshold"; /** * Property name for specifying the apfloat memory threshold. * * @deprecated Use {@link #MEMORY_THRESHOLD}. */ @Deprecated public static final String MEMORY_TRESHOLD = "memoryTreshold"; /** * Property name for specifying the apfloat shared memory threshold. */ public static final String SHARED_MEMORY_TRESHOLD = "sharedMemoryTreshold"; /** * Property name for specifying the I/O block size. */ public static final String BLOCK_SIZE = "blockSize"; /** * Property name for specifying the number of processors available. */ public static final String NUMBER_OF_PROCESSORS = "numberOfProcessors"; /** * Property name for specifying the temporary file path. */ public static final String FILE_PATH = "filePath"; /** * Property name for specifying the temporary file initial value. */ public static final String FILE_INITIAL_VALUE = "fileInitialValue"; /** * Property name for specifying the temporary file suffix. */ public static final String FILE_SUFFIX = "fileSuffix"; /** * Property name for specifying if clean-up should be done at program exit. */ public static final String CLEANUP_AT_EXIT = "cleanupAtExit"; // At system exit, run garbage collection and finalization to clean up temporary files private static class CleanupThread extends Thread { public CleanupThread() { super("apfloat shutdown clean-up thread"); } @Override public void run() { ApfloatMath.cleanUp(); // Clear references to static cached apfloats System.gc(); System.gc(); System.runFinalization(); this.builderFactory.shutdown(); } public void setBuilderFactory(BuilderFactory builderFactory) { this.builderFactory = builderFactory; } private BuilderFactory builderFactory; } /** * Create a new ApfloatContext using the specified properties. * * @param properties The properties for the ApfloatContext. * * @exception org.apfloat.ApfloatConfigurationException If a property value can't be converted to the correct type. */ public ApfloatContext(Properties properties) throws ApfloatConfigurationException { this.properties = (Properties) ApfloatContext.defaultProperties.clone(); this.properties.putAll(properties); setProperties(this.properties); } /** * Get the ApfloatContext for the calling thread. If a thread-specific * context has not been specified, the global context is returned. * * @return The ApfloatContext for the calling thread. */ public static ApfloatContext getContext() { checkInterrupted(); ApfloatContext ctx = getThreadContext(); if (ctx == null) { ctx = getGlobalContext(); } return ctx; } /** * Get the global ApfloatContext. * * @return The global ApfloatContext. */ public static ApfloatContext getGlobalContext() { return ApfloatContext.globalContext; } /** * Get the thread-specific ApfloatContext for the calling thread. * * @return The ApfloatContext for the calling thread, or null if one has not been specified. */ public static ApfloatContext getThreadContext() { // Quick check to improve performance if (ApfloatContext.threadContexts.isEmpty()) { return null; } return getThreadContext(Thread.currentThread()); } /** * Get the thread-specific ApfloatContext for the specified thread. * * @param thread The thread whose ApfloatContext is to be returned. * * @return The ApfloatContext for the specified thread, or null if one has not been specified. */ public static ApfloatContext getThreadContext(Thread thread) { return ApfloatContext.threadContexts.get(thread); } /** * Set the thread-specific ApfloatContext for the calling thread. * * @param threadContext The ApfloatContext for the calling thread. */ public static void setThreadContext(ApfloatContext threadContext) { setThreadContext(threadContext, Thread.currentThread()); } /** * Set the thread-specific ApfloatContext for the specified thread. * * @param threadContext The ApfloatContext for the specified thread. * @param thread The thread whose ApfloatContext is to be set. */ public static void setThreadContext(ApfloatContext threadContext, Thread thread) { ApfloatContext.threadContexts.put(thread, threadContext); } /** * Removes the thread-specific context for the current thread. */ public static void removeThreadContext() { removeThreadContext(Thread.currentThread()); } /** * Removes the thread-specific context for the specified thread. * * @param thread The thread whose ApfloatContext is to be removed. */ public static void removeThreadContext(Thread thread) { ApfloatContext.threadContexts.remove(thread); } /** * Removes all thread-specific ApfloatContexts. */ public static void clearThreadContexts() { ApfloatContext.threadContexts.clear(); } /** * Get the BuilderFactory. * * @return The BuilderFactory for this ApfloatContext. */ public BuilderFactory getBuilderFactory() { return this.builderFactory; } /** * Set the BuilderFactory. * * @param builderFactory The BuilderFactory for this ApfloatContext. */ public void setBuilderFactory(BuilderFactory builderFactory) { this.properties.setProperty(BUILDER_FACTORY, builderFactory.getClass().getName()); this.builderFactory = builderFactory; if (this.cleanupThread != null) { this.cleanupThread.setBuilderFactory(builderFactory); } } /** * Get the FilenameGenerator. * * @return The FilenameGenerator for this ApfloatContext. */ public FilenameGenerator getFilenameGenerator() { return this.filenameGenerator; } /** * Set the FilenameGenerator. * * @param filenameGenerator The FilenameGenerator for this ApfloatContext. */ public void setFilenameGenerator(FilenameGenerator filenameGenerator) { this.properties.setProperty(FILE_PATH, filenameGenerator.getPath()); this.properties.setProperty(FILE_INITIAL_VALUE, String.valueOf(filenameGenerator.getInitialValue())); this.properties.setProperty(FILE_SUFFIX, filenameGenerator.getSuffix()); this.filenameGenerator = filenameGenerator; } /** * Get the default radix. * * @return The default radix for this ApfloatContext. */ public int getDefaultRadix() { return this.defaultRadix; } /** * Set the default radix. * The default value is 10. * * @param radix The default radix for this ApfloatContext. */ public void setDefaultRadix(int radix) { radix = Math.min(Math.max(radix, Character.MIN_RADIX), Character.MAX_RADIX); this.properties.setProperty(DEFAULT_RADIX, String.valueOf(radix)); this.defaultRadix = radix; } /** * Get the maximum memory block size. * * @return The maximum memory block size. * * @see #setMaxMemoryBlockSize(long) */ public long getMaxMemoryBlockSize() { return this.maxMemoryBlockSize; } /** * Set the maximum allowed memory block size in bytes. * Apfloat will allocate an array at most of this size * for calculations using this context. * The minimum value for this setting is 65536.

* * If you set the value of this parameter too low, * performance will suffer greatly as data is unnecessarily * paged to disk. If you set this value too high, your * application can crash with an OutOfMemoryError.

* * The default value for this setting is 80% of the total memory * available to the VM at application startup, as reported by * Runtime.totalMemory(), rounded down to the nearest * power of two or three times a power of two. * * @param maxMemoryBlockSize Maximum allocated memory block size in bytes. */ public void setMaxMemoryBlockSize(long maxMemoryBlockSize) { // Note that setting the 64-bit long is not guaranteed to be atomic // However on 32-bit JVMs the upper word is always zero, and on 64-bit JVMs the update is probably atomic maxMemoryBlockSize = Util.round23down(Math.max(maxMemoryBlockSize, 65536)); this.properties.setProperty(MAX_MEMORY_BLOCK_SIZE, String.valueOf(maxMemoryBlockSize)); this.maxMemoryBlockSize = maxMemoryBlockSize; } /** * Get the level 1 cache size. * * @return The level 1 cache size. * * @see #setCacheL1Size(int) */ public int getCacheL1Size() { return this.cacheL1Size; } /** * Set the L1 cache size in bytes. The minimum value for this setting is 512.

* * This setting has a minor performance impact on some memory * intensive operations. Unless you really want to tweak the performance, * it's better to not touch this setting.

* * The default value for this setting is 8kB. * * @param cacheL1Size The level 1 cache size in bytes. */ public void setCacheL1Size(int cacheL1Size) { cacheL1Size = Util.round2down(Math.max(cacheL1Size, 512)); this.properties.setProperty(CACHE_L1_SIZE, String.valueOf(cacheL1Size)); this.cacheL1Size = cacheL1Size; } /** * Get the level 2 cache size. * * @return The level 2 cache size. * * @see #setCacheL2Size(int) */ public int getCacheL2Size() { return this.cacheL2Size; } /** * Set the L2 cache size in bytes. The minimum value for this setting is 2048. * * This setting has a minor performance impact on some memory * intensive operations. Unless you really want to tweak the performance, * it's better to not touch this setting.

* * The default value for this setting is 256kB. * * @param cacheL2Size The level 2 cache size in bytes. */ public void setCacheL2Size(int cacheL2Size) { cacheL2Size = Util.round2down(Math.max(cacheL2Size, 2048)); this.properties.setProperty(CACHE_L2_SIZE, String.valueOf(cacheL2Size)); this.cacheL2Size = cacheL2Size; } /** * Get the level 1 cache burst size. * * @return The cache burst size. * * @see #setCacheBurst(int) */ public int getCacheBurst() { return this.cacheBurst; } /** * Set the L1 cache burst block size in bytes. * This value is also known as "L1 cache line size".

* * Some common values are: *

    *
  • 16 for 486 processors
  • *
  • 32 for Pentium MMX/II/III/Celeron series and Itanium processors
  • *
  • 64 for Pentium 4 and Itanium 2 processors
  • *
* The processor will move at least this amount of bytes * whenever data is moved between the level 1 cache and * other memory (lower level cache or main memory). * Note that other cache levels than L1 may have a different * line size. The minimum value for this setting is 8.

* * This setting has a minor performance impact on some memory * intensive operations. Unless you really want to tweak the performance, * it's usually better to not touch this setting. Though, if you have e.g. * a Pentium 4 processor, you may want to increase the value * of this setting to 64 from the default value of 32. * * @param cacheBurst The number of bytes in a L1 cache line. */ public void setCacheBurst(int cacheBurst) { cacheBurst = Util.round2down(Math.max(cacheBurst, 8)); this.properties.setProperty(CACHE_BURST, String.valueOf(cacheBurst)); this.cacheBurst = cacheBurst; } /** * Get the memory threshold.

* * If the value is larger than the maximum value that can be presented * in an integer, then Integer.MAX_VALUE is returned. * * @return The memory threshold. * * @deprecated Use {@link #getMemoryThreshold()}. */ @Deprecated public int getMemoryTreshold() { return (int) Math.min(Integer.MAX_VALUE, getMemoryThreshold()); } /** * Set the maximum size of apfloats in bytes that are * stored in memory within this context. * * @param memoryThreshold The number of bytes that apfloats that are stored in memory will at most have within this context. * * @deprecated Use {@link #setMemoryThreshold(long)}. */ @Deprecated public void setMemoryTreshold(int memoryThreshold) { setMemoryThreshold(memoryThreshold); } /** * Get the memory threshold. * * @return The memory threshold. */ public long getMemoryThreshold() { return this.memoryThreshold; } /** * Set the maximum size of apfloats in bytes that are * stored in memory within this context. The minimum value for this setting is 128.

* * If the memory threshold is too small, performance will suffer as * small numbers are stored to disk, and the amount of disk I/O * overhead becomes significant. On the other hand, if the memory * threshold is too big, you can get an OutOfMemoryError.

* * The optimal value depends greatly on each application. Obviously, * if you have plenty of heap space and don't create too many too big * numbers you are not likely to have problems. The default value of * this setting is 64kB, or the maximum heap size divided by 1024, * whichever is larger. * * @param memoryThreshold The number of bytes that apfloats that are stored in memory will at most have within this context. */ public void setMemoryThreshold(long memoryThreshold) { memoryThreshold = Math.max(memoryThreshold, 128); this.properties.setProperty(MEMORY_TRESHOLD, String.valueOf(memoryThreshold)); this.properties.setProperty(MEMORY_THRESHOLD, String.valueOf(memoryThreshold)); this.memoryThreshold = memoryThreshold; } /** * Get the shared memory threshold. * * @return The shared memory threshold. * * @see #setSharedMemoryTreshold(long) */ public long getSharedMemoryTreshold() { return this.sharedMemoryTreshold; } /** * Set the maximum size of apfloats in bytes that can be used * without synchronizing against the shared memory lock. * The minimum value for this setting is 128.

* * If only one thread is used then this setting has no effect. * If multiple threads are used, and this setting is too small, * performance will suffer as the synchronization blocking and * other overhead becomes significant. On the other hand, if the * numbers are being stored in memory, and the shared memory * threshold is too big, you can get an OutOfMemoryError.

* * The optimal value depends on the application and the way parallelism * is used. As a rule of thumb, this should be set to a value that is * the maximum memory block size divided by the number of parallel threads. * The default is somewhat more conservatively this number divided by 32. * * @param sharedMemoryTreshold The number of bytes that apfloats will at most have, without synchronizing against the shared memory lock, within this context. */ public void setSharedMemoryTreshold(long sharedMemoryTreshold) { sharedMemoryTreshold = Math.max(sharedMemoryTreshold, 128); this.properties.setProperty(SHARED_MEMORY_TRESHOLD, String.valueOf(sharedMemoryTreshold)); this.sharedMemoryTreshold = sharedMemoryTreshold; } /** * Get the I/O block size. * * @return The I/O block size. * * @see #setBlockSize(int) */ public int getBlockSize() { return this.blockSize; } /** * Set the efficient I/O block size in bytes for * this context. The minimum value for this setting is 128.

* * If the block size is too small, the overhead of each I/O call will * definetely have an adverse effect on performance. Setting the block * size very big will not affect performance significantly, but can * increase intermediate memory consumption a lot, possibly resulting * in running out of memory with an OutOfMemoryError. A * recommended minimum value is at least a few kilobytes.

* * In many places, data in files is accessed in reverse order, fetching * blocks of this size. Probably the optimal value of this setting is * roughly half of the read-ahead buffer size of you hard disk. * The default value is 64kB. * * @param blockSize The I/O block size in bytes to be used in calculations using this context. */ public void setBlockSize(int blockSize) { blockSize = Util.round2down(Math.max(blockSize, 128)); this.properties.setProperty(BLOCK_SIZE, String.valueOf(blockSize)); this.blockSize = blockSize; } /** * Get the number of processors that should be used for parallel calculations. * * @return The number of processors. * * @see #setNumberOfProcessors(int) */ public int getNumberOfProcessors() { return this.numberOfProcessors; } /** * Set the number of processors available to parallel calculations using * this context. The minimum value for this setting is 1. * The default is to use all processors (CPU cores) available.

* * Note that if you change the number of processors after the library has * been initialized, the number of threads available to the ExecutorService * is not changed. If you want to change that too, it can be done easily with * setExecutorService(ApfloatContext.getDefaultExecutorService()). * * @param numberOfProcessors Number of processors available to parallel calculations using this context. * * @see #getDefaultExecutorService * * @see #setExecutorService(ExecutorService) */ public void setNumberOfProcessors(int numberOfProcessors) { numberOfProcessors = Math.max(numberOfProcessors, 1); this.properties.setProperty(NUMBER_OF_PROCESSORS, String.valueOf(numberOfProcessors)); this.numberOfProcessors = numberOfProcessors; } /** * Get if clean-up should be performed at the time the program exits. * * @return true if clean-up will be done at JVM exit, or false if not. * * @see #setCleanupAtExit(boolean) */ public boolean getCleanupAtExit() { return (this.cleanupThread != null); } /** * Set if clean-up should be performed at the time the program exits. * The clean-up runs garbage collection and finalization to remove any * remaining temporary files that may have been created. * The default behavior is true.

* * For example unsigned applets must have this property set to false, * since they do not have access to setting shutdown hooks.

* * Note that if this setting is ever set to true in any * ApfloatContext (and never set to false * subsequently in that context), then clean-up will be performed.

* * Also note that having the shutdown hook set will prevent class garbage * collection i.e. the apfloat classes can't be unloaded if the shutdown * hook still references the ApfloatContext class. If class unloading is * desired then the cleanupAtExit property should be set to false first. * * @param cleanupAtExit true if clean-up should be done at JVM exit, or false if not. */ public void setCleanupAtExit(boolean cleanupAtExit) { this.properties.setProperty(CLEANUP_AT_EXIT, String.valueOf(cleanupAtExit)); if (cleanupAtExit && this.cleanupThread == null) { this.cleanupThread = new CleanupThread(); this.cleanupThread.setBuilderFactory(this.builderFactory); Runtime.getRuntime().addShutdownHook(this.cleanupThread); } else if (!cleanupAtExit && this.cleanupThread != null) { Runtime.getRuntime().removeShutdownHook(this.cleanupThread); this.cleanupThread = null; } } /** * Get the value of a property as string. * The name of the property can be any of the constants defined above. * * @param propertyName The name of the property. * * @return The value of the property as a String. */ public String getProperty(String propertyName) { return this.properties.getProperty(propertyName); } /** * Get the value of a property as string, with the provided default * value if the property is not set. * * @param propertyName The name of the property. * @param defaultValue The default value to be returned, if the property is not set. * * @return The value of the property as a String. * * @since 1.7.0 */ public String getProperty(String propertyName, String defaultValue) { return this.properties.getProperty(propertyName, defaultValue); } /** * Set the value of a property as string. * The name of the property can be any of the constants defined above. * * @param propertyName The name of the property. * @param propertyValue The value of the property as a String. * * @exception org.apfloat.ApfloatConfigurationException If the property value can't be converted to the correct type. */ public void setProperty(String propertyName, String propertyValue) throws ApfloatConfigurationException { try { if (propertyName.equals(BUILDER_FACTORY)) { setBuilderFactory((BuilderFactory) Class.forName(propertyValue).getDeclaredConstructor().newInstance()); } else if (propertyName.equals(DEFAULT_RADIX)) { setDefaultRadix(Integer.parseInt(propertyValue)); } else if (propertyName.equals(MAX_MEMORY_BLOCK_SIZE)) { setMaxMemoryBlockSize(Long.parseLong(propertyValue)); } else if (propertyName.equals(CACHE_L1_SIZE)) { setCacheL1Size(Integer.parseInt(propertyValue)); } else if (propertyName.equals(CACHE_L2_SIZE)) { setCacheL2Size(Integer.parseInt(propertyValue)); } else if (propertyName.equals(CACHE_BURST)) { setCacheBurst(Integer.parseInt(propertyValue)); } else if (propertyName.equals(MEMORY_TRESHOLD) || propertyName.equals(MEMORY_THRESHOLD)) { setMemoryThreshold(Long.parseLong(propertyValue)); } else if (propertyName.equals(SHARED_MEMORY_TRESHOLD)) { setSharedMemoryTreshold(Long.parseLong(propertyValue)); } else if (propertyName.equals(BLOCK_SIZE)) { setBlockSize(Integer.parseInt(propertyValue)); } else if (propertyName.equals(NUMBER_OF_PROCESSORS)) { setNumberOfProcessors(Integer.parseInt(propertyValue)); } else if (propertyName.equals(FILE_PATH)) { setFilenameGenerator(new FilenameGenerator(propertyValue, getProperty(FILE_INITIAL_VALUE), getProperty(FILE_SUFFIX))); } else if (propertyName.equals(FILE_INITIAL_VALUE)) { setFilenameGenerator(new FilenameGenerator(getProperty(FILE_PATH), propertyValue, getProperty(FILE_SUFFIX))); } else if (propertyName.equals(FILE_SUFFIX)) { setFilenameGenerator(new FilenameGenerator(getProperty(FILE_PATH), getProperty(FILE_INITIAL_VALUE), propertyValue)); } else if (propertyName.equals(CLEANUP_AT_EXIT)) { setCleanupAtExit(Boolean.parseBoolean(propertyValue)); } else { this.properties.setProperty(propertyName, propertyValue); } } catch (Exception e) { throw new ApfloatConfigurationException("Error setting property \"" + propertyName + "\" to value \"" + propertyValue + '\"', e); } } /** * Get the values of all properties as strings. * The names of the properties are all of the constants defined above. * * @return The properties. */ public Properties getProperties() { return (Properties) this.properties.clone(); } /** * Get the shared memory lock object. * All internal functions that allocate a memory block larger than the * shared memory threshold should synchronize the allocation and memory access * on the object returned by this method. * * @return The object on which large memory block allocation and access should be synchronized. */ public Object getSharedMemoryLock() { return this.sharedMemoryLock; } /** * Set the shared memory lock object. * All internal functions that allocate a memory block larger than the * shared memory threshold should synchronize the allocation and memory access * on the object passed to this method.

* * The object is not used for anything else than synchronization, so the * class of the object should really be java.lang.Object. One * would typically call this method e.g. as * ctx.setSharedMemoryLock(new Object()). * * @param lock The object on which large memory block allocation and access should be synchronized. */ public void setSharedMemoryLock(Object lock) { this.sharedMemoryLock = lock; } /** * Get the ExecutorService. * It can be used for executing operations in parallel.

* * By default the ExecutorService is a thread pool that is * shared by all the ApfloatContexts. The threads in the pool * are daemon threads so the thread pool requires no clean-up * at shutdown time. * * @return The ExecutorService. * * @see #getDefaultExecutorService * * @since 1.1 */ public ExecutorService getExecutorService() { return this.executorService; } /** * Set the ExecutorService.

* * If a custom ExecutorService is used, e.g. a thread pool, then the number * of available threads in the pool should match the number of processors * set to all ApfloatContexts with {@link #setNumberOfProcessors(int)}.

* * Note that if a custom ExecutorService that requires shutdown is used, * it is the caller's responsibility to clean up the ExecutorService * at shutdown. * * @param executorService The ExecutorService. * * @see #getDefaultExecutorService * * @since 1.1 */ public void setExecutorService(ExecutorService executorService) { this.executorService = executorService; } /** * While waiting for a Future to be completed, do some useful * work instead of just being idle.

* * This method is intended to coordinate with the executor service from * {@link #getExecutorService()} to keep all threads busy at all times. * * @param future The Future to wait for. * * @since 1.9.0 */ public void wait(Future future) { getBuilderFactory().getExecutionBuilder().createExecution().wait(future); } /** * Checks if the current thread was interrupted. If yes, throws an * {@link ApfloatInterruptedException}.

* * This method calls {@link Thread#interrupted()} so if the thread was * interrupted, it clears the interrupted status. * * @throws ApfloatInterruptedException If the current thread was interrupted. * * @since 1.14.0 */ public static void checkInterrupted() throws ApfloatInterruptedException { if (Thread.interrupted()) { throw new ApfloatInterruptedException("Interrupted"); } } /** * Get an arbitrary object as an attribute for this ApfloatContext. * * @param name Name of the attribute. * * @return Value of the attribute or null if the attribute doesn't exist. */ public Object getAttribute(String name) { return this.attributes.get(name); } /** * Set an arbitrary object as an attribute for this ApfloatContext. * * @param name Name of the attribute. * @param value Value of the attribute. * * @return Previous value of the attribute or null if the attribute didn't exist. */ public Object setAttribute(String name, Object value) { return this.attributes.put(name, value); } /** * Remove an attribute from this ApfloatContext. * * @param name Name of the attribute. * * @return Value of the attribute or null if the attribute didn't exist. */ public Object removeAttribute(String name) { return this.attributes.remove(name); } /** * Get names of all attributes for this ApfloatContext. * * @return Names of all attributes as strings. */ public Enumeration getAttributeNames() { return this.attributes.keys(); } /** * Loads properties from a properties file or resource bundle. * First the ResourceBundle by the name "apfloat" is * located, then all properties found from that resource bundle * are put to a Properties object.

* * The resource bundle is found basically using the following logic * (note that this is standard Java ResourceBundle * functionality), in this order whichever is found first: * *

    *
  1. From the class named apfloat (that should be a subclass of ResourceBundle), in the current class path
  2. *
  3. From the file "apfloat.properties" in the current class path
  4. *
* * @return Properties found in the "apfloat" resource bundle, or an empty Properties object, if the resource bundle is not found. */ public static Properties loadProperties() throws ApfloatRuntimeException { Properties properties = new Properties(); try { ResourceBundle resourceBundle = ResourceBundle.getBundle("apfloat"); Enumeration keys = resourceBundle.getKeys(); while (keys.hasMoreElements()) { String key = keys.nextElement(); properties.setProperty(key, resourceBundle.getString(key)); } } catch (MissingResourceException mre) { // Ignore - properties file or class is not found or can't be read } return properties; } /** * Returns a new instance of a default ExecutorService.

* * The default executor service is a {@link ForkJoinPool} * where the number of threads is one less than the number * of processors set with {@link #setNumberOfProcessors(int)}. * * @return A new instance of a default ExecutorService. * * @since 1.3 */ public static ExecutorService getDefaultExecutorService() { int numberOfThreads = Math.max(1, getContext().getNumberOfProcessors() - 1); ForkJoinPool forkJoinPool; try { forkJoinPool = new ForkJoinPool(numberOfThreads); } catch (SecurityException se) { // If we don't have permission to create a new ForkJoinPool (e.g. in an applet) then use the common pool forkJoinPool = ForkJoinPool.commonPool(); } return forkJoinPool; } /** * Set the values of all properties as strings. * The names of the properties can be all of the constants defined above. * * @param properties The properties. * * @exception org.apfloat.ApfloatConfigurationException If a property value can't be converted to the correct type. */ public void setProperties(Properties properties) throws ApfloatConfigurationException { for (String key : properties.stringPropertyNames()) { setProperty(key, properties.getProperty(key)); } } /** * Creates a copy of this object.

* * The clone has the same BuilderFactory and FilenameGenerator members * and the same shared memory lock and ExecutorService as the original * ApfloatContext.

* * A shallow copy of the property set and the attribute set is created. * Thus setting a property or attribute on the clone will not set it * in the original object. Since the actual attributes (values) are shared, * if an attribute is mutable and is modified in the clone, the modified * value will appear in the original also.

* * @return A mostly shallow copy of this object. */ @Override public Object clone() { try { ApfloatContext ctx = (ApfloatContext) super.clone(); // Copy all attributes by reference ctx.properties = (Properties) ctx.properties.clone(); // Create shallow copies ctx.attributes = new ConcurrentHashMap<>(ctx.attributes); return ctx; } catch (CloneNotSupportedException cnse) { // Should not occur throw new InternalError(); } } private static Properties loadSystemOverrides(Properties properties) { for (String propertyName : properties.stringPropertyNames()) { String propertyValue = properties.getProperty(propertyName); try { propertyValue = System.getProperty("apfloat." + propertyName, propertyValue); } catch (SecurityException se) { // Ignore, not allowed to read the property } properties.setProperty(propertyName, propertyValue); }; return properties; } private static ApfloatContext globalContext; private static Map threadContexts = new ConcurrentWeakHashMap<>(); // Use a weak hash map to automatically remove completed threads; concurrent to avoid blocking threads private static Properties defaultProperties; private static ExecutorService defaultExecutorService; private volatile BuilderFactory builderFactory; private volatile FilenameGenerator filenameGenerator; private volatile int defaultRadix; private volatile long maxMemoryBlockSize; private volatile int cacheL1Size; private volatile int cacheL2Size; private volatile int cacheBurst; private volatile long memoryThreshold; private volatile long sharedMemoryTreshold; private volatile int blockSize; private volatile int numberOfProcessors; private volatile CleanupThread cleanupThread; private volatile Properties properties; private volatile Object sharedMemoryLock = new Object(); private volatile ExecutorService executorService = ApfloatContext.defaultExecutorService; private volatile ConcurrentHashMap attributes = new ConcurrentHashMap<>(); static { ApfloatContext.defaultProperties = new Properties(); // Try to use up to 80% of total memory and all processors long totalMemory; try { MemoryMXBean memoryBean = ManagementFactory.getMemoryMXBean(); MemoryUsage memoryUsage = memoryBean.getHeapMemoryUsage(); totalMemory = Math.max(memoryUsage.getCommitted(), memoryUsage.getMax()); } catch (NoClassDefFoundError | NullPointerException e) { // The ManagementFactory class might be unavailable totalMemory = Runtime.getRuntime().maxMemory(); } long maxMemoryBlockSize = Util.round23down(totalMemory / 5 * 4); int numberOfProcessors = Runtime.getRuntime().availableProcessors(); long memoryThreshold = Math.max(maxMemoryBlockSize >> 10, 65536); int blockSize = Util.round2down((int) Math.min(memoryThreshold, Integer.MAX_VALUE)); ApfloatContext.defaultProperties.setProperty(BUILDER_FACTORY, "org.apfloat.internal.LongBuilderFactory"); ApfloatContext.defaultProperties.setProperty(DEFAULT_RADIX, "10"); ApfloatContext.defaultProperties.setProperty(MAX_MEMORY_BLOCK_SIZE, String.valueOf(maxMemoryBlockSize)); ApfloatContext.defaultProperties.setProperty(CACHE_L1_SIZE, "8192"); ApfloatContext.defaultProperties.setProperty(CACHE_L2_SIZE, "262144"); ApfloatContext.defaultProperties.setProperty(CACHE_BURST, "32"); ApfloatContext.defaultProperties.setProperty(MEMORY_THRESHOLD, String.valueOf(memoryThreshold)); ApfloatContext.defaultProperties.setProperty(SHARED_MEMORY_TRESHOLD, String.valueOf(maxMemoryBlockSize / numberOfProcessors / 32)); ApfloatContext.defaultProperties.setProperty(BLOCK_SIZE, String.valueOf(blockSize)); ApfloatContext.defaultProperties.setProperty(NUMBER_OF_PROCESSORS, String.valueOf(numberOfProcessors)); ApfloatContext.defaultProperties.setProperty(FILE_PATH, ""); ApfloatContext.defaultProperties.setProperty(FILE_INITIAL_VALUE, "0"); ApfloatContext.defaultProperties.setProperty(FILE_SUFFIX, ".ap"); ApfloatContext.defaultProperties.setProperty(CLEANUP_AT_EXIT, "true"); loadSystemOverrides(ApfloatContext.defaultProperties); // Set combination of default properties and properties specified in the resource bundle, with system property overrides ApfloatContext.globalContext = new ApfloatContext(loadSystemOverrides(loadProperties())); // ExecutorService depends on the properties so set it last ApfloatContext.defaultExecutorService = getDefaultExecutorService(); ApfloatContext.globalContext.setExecutorService(ApfloatContext.defaultExecutorService); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ApfloatHelper.java000066400000000000000000000724401461767713300251410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.BigInteger; import java.math.BigDecimal; import java.math.RoundingMode; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PushbackReader; import java.io.Writer; import java.io.IOException; import org.apfloat.spi.ApfloatBuilder; import org.apfloat.spi.ApfloatImpl; import org.apfloat.spi.Util; import static org.apfloat.spi.RadixConstants.*; /** * Various utility methods related to apfloats. * * @version 1.14.0 * @author Mikko Tommila */ class ApfloatHelper { private ApfloatHelper() { } public static ApfloatImpl createApfloat(String value, boolean isInteger) throws NumberFormatException, ApfloatRuntimeException { long precision = (isInteger ? Apfloat.INFINITE : Apfloat.DEFAULT); int radix = getDefaultRadix(); return implCreateApfloat(value, precision, radix, isInteger); } public static ApfloatImpl createApfloat(String value, long precision, boolean isInteger) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { int radix = getDefaultRadix(); return createApfloat(value, precision, radix, isInteger); } public static ApfloatImpl createApfloat(String value, long precision, int radix, boolean isInteger) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { if (precision != Apfloat.DEFAULT) { checkPrecision(precision); } return implCreateApfloat(value, precision, radix, isInteger); } private static ApfloatImpl implCreateApfloat(String value, long precision, int radix, boolean isInteger) throws NumberFormatException, ApfloatRuntimeException { ApfloatBuilder factory = getApfloatBuilder(); return factory.createApfloat(value, precision, radix, isInteger); } public static ApfloatImpl createApfloat(long value) throws NumberFormatException, ApfloatRuntimeException { int radix = getDefaultRadix(); return implCreateApfloat(value, Apfloat.INFINITE, radix); } public static ApfloatImpl createApfloat(long value, long precision) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { int radix = getDefaultRadix(); return createApfloat(value, precision, radix); } public static ApfloatImpl createApfloat(long value, long precision, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { precision = (precision == Apfloat.DEFAULT ? Apfloat.INFINITE : precision); checkPrecision(precision); return implCreateApfloat(value, precision, radix); } private static ApfloatImpl implCreateApfloat(long value, long precision, int radix) throws NumberFormatException, ApfloatRuntimeException { ApfloatBuilder factory = getApfloatBuilder(); return factory.createApfloat(value, precision, radix); } public static ApfloatImpl createApfloat(float value) throws NumberFormatException, ApfloatRuntimeException { int radix = getDefaultRadix(); int precision = getFloatPrecision(radix); return implCreateApfloat(value, precision, radix); } public static ApfloatImpl createApfloat(float value, long precision) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { int radix = getDefaultRadix(); return createApfloat(value, precision, radix); } public static ApfloatImpl createApfloat(float value, long precision, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { precision = (precision == Apfloat.DEFAULT ? getFloatPrecision(radix) : precision); checkPrecision(precision); return implCreateApfloat(value, precision, radix); } public static ApfloatImpl createApfloat(double value) throws NumberFormatException, ApfloatRuntimeException { int radix = getDefaultRadix(); int precision = getDoublePrecision(radix); return implCreateApfloat(value, precision, radix); } public static ApfloatImpl createApfloat(double value, long precision) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { int radix = getDefaultRadix(); return createApfloat(value, precision, radix); } public static ApfloatImpl createApfloat(double value, long precision, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { precision = (precision == Apfloat.DEFAULT ? getDoublePrecision(radix) : precision); checkPrecision(precision); return implCreateApfloat(value, precision, radix); } private static ApfloatImpl implCreateApfloat(double value, long precision, int radix) throws NumberFormatException, ApfloatRuntimeException { ApfloatBuilder factory = getApfloatBuilder(); return factory.createApfloat(value, precision, radix); } public static ApfloatImpl createApfloat(PushbackReader in, boolean isInteger) throws IOException, NumberFormatException, ApfloatRuntimeException { int radix = getDefaultRadix(); return implCreateApfloat(in, Apfloat.DEFAULT, radix, isInteger); } public static ApfloatImpl createApfloat(PushbackReader in, long precision, boolean isInteger) throws IOException, NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { int radix = getDefaultRadix(); return createApfloat(in, precision, radix, isInteger); } public static ApfloatImpl createApfloat(PushbackReader in, long precision, int radix, boolean isInteger) throws IOException, NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { if (precision != Apfloat.DEFAULT) { checkPrecision(precision); } return implCreateApfloat(in, precision, radix, isInteger); } private static ApfloatImpl implCreateApfloat(PushbackReader in, long precision, int radix, boolean isInteger) throws IOException, NumberFormatException, ApfloatRuntimeException { ApfloatBuilder factory = getApfloatBuilder(); return factory.createApfloat(in, precision, radix, isInteger); } public static ApfloatImpl createApfloat(BigInteger value) throws NumberFormatException, ApfloatRuntimeException { int radix = getDefaultRadix(); return createApfloat(value, Apfloat.INFINITE, radix); } public static ApfloatImpl createApfloat(BigInteger value, long precision) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { int radix = getDefaultRadix(); return createApfloat(value, precision, radix); } public static ApfloatImpl createApfloat(BigInteger value, long precision, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { if (precision != Apfloat.DEFAULT) { checkPrecision(precision); } checkRadix(radix); Apfloat a; try { a = new Apfloat(createApfloat(toPushbackReader(value), Apfloat.INFINITE, 16, true)); } catch (IOException ioe) { throw new ApfloatRuntimeException("Should not occur", ioe); } precision = (precision == Apfloat.DEFAULT ? Apfloat.INFINITE : precision); return a.toRadix(radix).getImpl(precision); } public static ApfloatImpl createApfloat(BigDecimal value) throws ApfloatRuntimeException { return implCreateApfloat(value.toString(), Apfloat.DEFAULT, 10, false); } public static ApfloatImpl createApfloat(BigDecimal value, long precision) throws IllegalArgumentException, ApfloatRuntimeException { return createApfloat(value.toString(), precision, 10, false); } /** * Extracts matching character from stream. * A non-matching character is pushed back to the stream. * * @param in The input. * @param c The character to expect from the stream. * * @return true if the specified character was extracted from the stream, false otherwise. * * @exception IOException In case of read error in the stream. */ public static boolean readMatch(PushbackReader in, int c) throws IOException { int i = in.read(); if (i != c) { if (i != -1) { in.unread(i); } return false; } return true; } /** * Extracts whitespace from stream. * * @param in The input. * * @exception IOException In case of read error in the stream. */ public static void extractWhitespace(PushbackReader in) throws IOException { int c; while (Character.isWhitespace((char) (c = in.read()))) { // Extracts any whitespace } if (c != -1) { in.unread(c); } } /** * Get working precisions for the arguments of e.g. an add, subtract or compare operation.

* * Note that the returned precision can be zero to indicate that the number is insignificant * in the calculation. This is the case if either operand is zero, or if one number lies * completely outside the significant range of the other number. Consider e.g. the case

* * x.scale() = 100
* x.precision() = 50
* y.scale() = 10
* y.precision() = 5

* * In e.g. the sum of x and y, the operand y would now be insignificant. * * @param x First argument. * @param y Second argument. * * @return Array of two longs containing the working precisions for x and y, correspondingly. */ public static long[] getMatchingPrecisions(Apfloat x, Apfloat y) throws ApfloatRuntimeException { if (x.signum() == 0 || y.signum() == 0) { return new long[] { 0, 0 }; } long xPrec = x.precision(), yPrec = y.precision(), xScale = x.scale(), yScale = y.scale(), maxScale = Math.max(xScale, yScale), xScaleDiff = (maxScale - xScale < 0 ? Apfloat.INFINITE : maxScale - xScale), yScaleDiff = (maxScale - yScale < 0 ? Apfloat.INFINITE : maxScale - yScale), maxPrec = Math.min(Util.ifFinite(xPrec, xPrec + xScaleDiff), Util.ifFinite(yPrec, yPrec + yScaleDiff)), destXPrec = (maxPrec - xScaleDiff <= 0 ? 0 : Util.ifFinite(maxPrec, maxPrec - xScaleDiff)), destYPrec = (maxPrec - yScaleDiff <= 0 ? 0 : Util.ifFinite(maxPrec, maxPrec - yScaleDiff)); return new long[] { destXPrec, destYPrec }; } /** * Get working precisions for the arguments of an multiply-add operation * a * b + c * d. Works as well for a multiply-subtract operation, of course.

* * The returned array contains three longs:

* * [0] Working precisions for a and b
* [1] Working precisions for c and d
* [2] Maximum precision of the final result a * b + c * d

* * Note that the precisions can be zero. See {@link #getMatchingPrecisions(Apfloat,Apfloat)} * for details. * * @param a First argument. * @param b Second argument. * @param c Third argument. * @param d Fourth argument. * * @return Array of three longs containing the precisions. */ public static long[] getMatchingPrecisions(Apfloat a, Apfloat b, Apfloat c, Apfloat d) throws ApfloatRuntimeException { long abPrec = (a.signum() == 0 || b.signum() == 0 ? 0 : Math.min(a.precision(), b.precision())), cdPrec = (c.signum() == 0 || d.signum() == 0 ? 0 : Math.min(c.precision(), d.precision())); if (abPrec == 0 || cdPrec == 0) { return new long[] { abPrec, cdPrec, Math.max(abPrec, cdPrec) }; } long abScale = a.scale() + b.scale(), cdScale = c.scale() + d.scale(), maxScale = Math.max(abScale, cdScale), abScaleDiff = (maxScale - abScale < 0 ? Apfloat.INFINITE : maxScale - abScale), cdScaleDiff = (maxScale - cdScale < 0 ? Apfloat.INFINITE : maxScale - cdScale), maxPrec = Math.min(Util.ifFinite(abPrec, abPrec + abScaleDiff), Util.ifFinite(cdPrec, cdPrec + cdScaleDiff)), destAbPrec = (maxPrec - abScaleDiff <= 0 ? 0 : Util.ifFinite(maxPrec, maxPrec - abScaleDiff + 1)), // Add 1 since the scale may be 1 less destCdPrec = (maxPrec - cdScaleDiff <= 0 ? 0 : Util.ifFinite(maxPrec, maxPrec - cdScaleDiff + 1)); return new long[] { destAbPrec, destCdPrec, maxPrec }; } public static void checkPrecision(long precision) throws IllegalArgumentException { if (precision <= 0) { throw new IllegalArgumentException("Precision " + precision + " is not positive"); } } public static void checkRadix(int radix) throws NumberFormatException { if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) { throw new NumberFormatException("Invalid radix " + radix + "; radix must be between " + Character.MIN_RADIX + " and " + Character.MAX_RADIX); } } private static void checkPowPrecision(long targetPrecision) throws InfiniteExpansionException { if (targetPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate power to infinite precision"); } } private static Apcomplex checkPowBasic(Apcomplex z, Apcomplex w, long targetPrecision) throws ArithmeticException, ApfloatRuntimeException { if (w.isZero()) { if (z.isZero()) { throw new ArithmeticException("Zero to power zero"); } return new Apcomplex(new Apfloat(1, Apfloat.INFINITE, z.radix())); } else if (z.isZero()) { if (w.real().signum() <= 0) { throw new ArithmeticException("Zero to power of " + (w.imag().signum() == 0 ? "negative number" : "number with nonpositive real part")); } return z; } else if (z.equals(Apcomplex.ONE) || w.equals(Apcomplex.ONE)) { return z.precision(targetPrecision); } return null; } public static Apcomplex checkPow(Apcomplex z, Apcomplex w, long targetPrecision) throws ArithmeticException, ApfloatRuntimeException { Apcomplex result = checkPowBasic(z, w, targetPrecision); if (result != null) { return result; } checkPowPrecision(targetPrecision); return null; } public static Apfloat checkPow(Apfloat x, Apfloat y, long targetPrecision) throws ArithmeticException, ApfloatRuntimeException { Apcomplex result = checkPowBasic(x, y, targetPrecision); if (result != null) { return result.real(); } else if (x.signum() < 0 && !y.isInteger()) { throw new ArithmeticException("Power of negative number to non-integer; result would be complex"); } checkPowPrecision(targetPrecision); return null; } public static int getFloatPrecision(int radix) { assert (radix > 0); return FLOAT_PRECISION[radix]; } public static int getDoublePrecision(int radix) { assert (radix > 0); return DOUBLE_PRECISION[radix]; } public static int getLongPrecision(int radix) { assert (radix > 0); return LONG_PRECISION[radix]; } // To handle accumulating round-off errors better in slow functions public static long getSmallExtraPrecision(int radix) { assert (radix > 0); return Math.min(3, (long) Math.ceil(5 / Math.log(radix))); } // Returns x with precision at most as specified public static Apfloat limitPrecision(Apfloat x, long precision) throws ApfloatRuntimeException { return x.precision(Math.min(x.precision(), precision)); } // Returns x with precision at least as specified public static Apfloat ensurePrecision(Apfloat x, long precision) throws ApfloatRuntimeException { return x.precision(Math.max(x.precision(), precision)); } // Returns given precision extended by specified amount public static long extendPrecision(long precision, long extraPrecision) { return Util.ifFinite(precision, precision + extraPrecision); } // Returns given precision extended by Apfloat.EXTRA_PRECISION public static long extendPrecision(long precision) { return extendPrecision(precision, Apfloat.EXTRA_PRECISION); } // Returns given precision reduced by specified amount public static long reducePrecision(long precision, long extraPrecision) throws ApfloatRuntimeException { if (precision == Apfloat.INFINITE) { return precision; } precision = precision - extraPrecision; if (precision <= 0) { throw new LossOfPrecisionException("Complete loss of precision"); } return precision; } // Returns given precision reduced by Apfloat.EXTRA_PRECISION public static long reducePrecision(long precision) throws ApfloatRuntimeException { return reducePrecision(precision, Apfloat.EXTRA_PRECISION); } // Returns x with precision extended by Apfloat.EXTRA_PRECISION public static Apfloat extendPrecision(Apfloat x) throws ApfloatRuntimeException { return x.precision(extendPrecision(x.precision())); } // Returns x with precision extended by specified amount public static Apfloat extendPrecision(Apfloat x, long extraPrecision) throws ApfloatRuntimeException { return x.precision(extendPrecision(x.precision(), extraPrecision)); } // Returns x with precision reduced by Apfloat.EXTRA_PRECISION public static Apfloat reducePrecision(Apfloat x) throws ApfloatRuntimeException { return x.precision(reducePrecision(x.precision())); } // Returns x with precision reduced by specified amount public static Apfloat reducePrecision(Apfloat x, long extraPrecision) throws ApfloatRuntimeException { return x.precision(reducePrecision(x.precision(), extraPrecision)); } // Returns z with precision as specified public static Apcomplex setPrecision(Apcomplex z, long precision) throws ApfloatRuntimeException { if (z.real().signum() == 0) { return new Apcomplex(z.real(), z.imag().precision(precision)); } else if (z.imag().signum() == 0) { return new Apcomplex(z.real().precision(precision), z.imag()); } long precisionChange = precision - z.precision(), realPrecision = z.real().precision(), imagPrecision = z.imag().precision(), newRealPrecision = Util.ifFinite(realPrecision, realPrecision + precisionChange), newImagPrecision = Util.ifFinite(imagPrecision, imagPrecision + precisionChange); if (precisionChange < 0) { if (realPrecision + precisionChange <= 0) { return new Apcomplex(Apfloat.ZEROS[z.radix()], z.imag().precision(precision)); } else if (imagPrecision + precisionChange <= 0) { return new Apcomplex(z.real().precision(precision), Apfloat.ZEROS[z.radix()]); } } return new Apcomplex(z.real().precision(newRealPrecision), z.imag().precision(newImagPrecision)); } // Returns z with precision at most as specified public static Apcomplex limitPrecision(Apcomplex z, long precision) throws ApfloatRuntimeException { return new Apcomplex(limitPrecision(z.real(), precision), limitPrecision(z.imag(), precision)); } // Returns z with precision at least as specified public static Apcomplex ensurePrecision(Apcomplex z, long precision) throws ApfloatRuntimeException { return new Apcomplex(ensurePrecision(z.real(), precision), ensurePrecision(z.imag(), precision)); } // Returns z with precision extended by Apfloat.EXTRA_PRECISION public static Apcomplex extendPrecision(Apcomplex z) throws ApfloatRuntimeException { return new Apcomplex(extendPrecision(z.real()), extendPrecision(z.imag())); } // Returns z with precision extended by specified precision public static Apcomplex extendPrecision(Apcomplex z, long extraPrecision) throws ApfloatRuntimeException { return new Apcomplex(extendPrecision(z.real(), extraPrecision), extendPrecision(z.imag(), extraPrecision)); } // Returns z with precision reduced by Apfloat.EXTRA_PRECISION public static Apcomplex reducePrecision(Apcomplex z) throws ApfloatRuntimeException { return new Apcomplex(reducePrecision(z.real()), reducePrecision(z.imag())); } // Returns z with precision reduced by specified amount public static Apcomplex reducePrecision(Apcomplex z, long extraPrecision) throws ApfloatRuntimeException { return new Apcomplex(reducePrecision(z.real(), extraPrecision), reducePrecision(z.imag(), extraPrecision)); } // Returns z so that gamma(z) should have the given precision public static Apcomplex ensureGammaPrecision(Apcomplex z, long precision) { Apint zRounded = RoundingHelper.roundToInteger(z.real(), RoundingMode.HALF_EVEN).truncate(); if (zRounded.signum() < 0) { long digitLoss = Math.min(precision, -z.subtract(zRounded).scale()); if (digitLoss > 0) { precision = Util.ifFinite(precision, precision + digitLoss); } } return ensurePrecision(z, precision); } public static long size(Aprational x) throws ApfloatRuntimeException { return Math.max(x.numerator().size(), x.denominator().size()); } public static BigInteger toBigInteger(Apint x) { assert (x.signum() != 0); // The naive approach to convert to String and then to BigInteger is highly // inefficient as the BigInteger String constructor has O(n^2) complexity. // Therefore we first convert to radix-16 and then to a byte array. Apint a = ApintMath.abs(x.toRadix(16)); long scale = a.scale(); long byteCount = (scale + 1) >> 1; if (byteCount > Integer.MAX_VALUE) { throw new IllegalArgumentException("Maximum array size exceeded"); } byte[] bytes = new byte[(int) byteCount]; boolean startHi = ((scale & 1) == 0); try { a.writeTo(new Writer() { @Override public void write(int c) { c = Character.digit(c, 16); if (this.hi) { this.b = (c << 4); } else { this.b += (c & 0x0F); bytes[this.bytePosition] = (byte) this.b; this.bytePosition++; } this.hi = !this.hi; } @Override public void write(char cbuf[], int off, int len) { for (int i = 0; i < len; i++) { write(cbuf[off + i]); } } @Override public void close() { } @Override public void flush() { } private int b; private int bytePosition; private boolean hi = startHi; }); } catch (IOException ioe) { throw new ApfloatRuntimeException("Should not occur", ioe); } BigInteger b = new BigInteger(x.signum(), bytes); return b; } // Get a reader for the radix-16 presentation of the BigInteger. // The BigInteger.toString() method has O(n^2) complexity, // therefore we convert to a byte array instead. public static PushbackReader toPushbackReader(BigInteger x) throws IOException { byte[] bytes = x.abs().toByteArray(); int startB = (x.signum() < 0 ? '-' : -1); // Start the stream with minus sign in case of negative number InputStream in = new ByteArrayInputStream(bytes) { @Override public int read() { int c; if (this.b == -1) { this.b = super.read(); if (this.b == -1) { c = -1; } else { c = Character.forDigit(this.b >> 4, 16); this.b = Character.forDigit(this.b & 0x0F, 16); } } else { c = this.b; this.b = -1; } return c; } @Override public int read(byte[] b, int off, int len) { int i = 0; for (; i < len; i++) { int c = read(); if (c == -1) { i = (i == 0 ? -1 : i); // In case of EOF; there was nothing to read in the stream break; } b[i + off] = (byte) c; } return i; } private int b = startB; }; return new PushbackReader(new InputStreamReader(in, "ISO-8859-1")); } // Converts ArithmeticException to OverflowException if the Apint overflows a long public static long longValueExact(Apint x) throws OverflowException { try { return x.longValueExact(); } catch (ArithmeticException ae) { throw new OverflowException("Overflow", ae); } } private static int getDefaultRadix() throws NumberFormatException { ApfloatContext ctx = ApfloatContext.getContext(); return ctx.getDefaultRadix(); } private static ApfloatBuilder getApfloatBuilder() { ApfloatContext ctx = ApfloatContext.getContext(); return ctx.getBuilderFactory().getApfloatBuilder(); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ApfloatInterruptedException.java000066400000000000000000000045451461767713300301070ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; /** * Exception indicating that the computation was interrupted.

* * This exception is semantically somewhat similar to {@link InterruptedException} * except that it's a runtime exception and not a checked exception.

* * @since 1.14.0 * @version 1.14.0 * @author Mikko Tommila */ public class ApfloatInterruptedException extends ApfloatRuntimeException { /** * Constructs a new apfloat interrupted exception with an empty detail message. */ public ApfloatInterruptedException() { } /** * Constructs a new apfloat interrupted exception with the specified detail message. * * @param message The detail message. */ public ApfloatInterruptedException(String message) { super(message); } /** * Constructs a new apfloat interrupted exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public ApfloatInterruptedException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = 1L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ApfloatMath.java000066400000000000000000005152401461767713300246130ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.Hashtable; import java.util.Iterator; import java.util.Queue; import java.util.PriorityQueue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Consumer; import java.util.function.Function; import org.apfloat.spi.Util; /** * Various mathematical functions for arbitrary precision floating-point numbers.

* * Due to different types of round-off errors that can occur in the implementation, * no guarantees about e.g. monotonicity are given for any of the methods. * * @see ApintMath * * @version 1.14.0 * @author Mikko Tommila */ public class ApfloatMath { private ApfloatMath() { } /** * Integer power. * * @param x Base of the power operator. * @param n Exponent of the power operator. * * @return x to the n:th power, that is xn. * * @exception ArithmeticException If both x and n are zero. */ public static Apfloat pow(Apfloat x, long n) throws ArithmeticException, ApfloatRuntimeException { if (n == 0) { if (x.signum() == 0) { throw new ArithmeticException("Zero to power zero"); } return new Apfloat(1, Apfloat.INFINITE, x.radix()); } else if (n < 0) { x = inverseRoot(x, 1); n = -n; } long precision = x.precision(); x = ApfloatHelper.extendPrecision(x); // Big exponents will accumulate round-off errors // Algorithm improvements by Bernd Kellner int b2pow = 0; while ((n & 1) == 0) { b2pow++; n >>>= 1; } Apfloat r = x; while ((n >>>= 1) > 0) { x = x.multiply(x); if ((n & 1) != 0) { r = r.multiply(x); } } while (b2pow-- > 0) { r = r.multiply(r); } return r.precision(precision); } /** * Square root. * * @param x The argument. * * @return Square root of x. * * @exception ArithmeticException If x is negative. */ public static Apfloat sqrt(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return root(x, 2); } /** * Cube root. * * @param x The argument. * * @return Cube root of x. */ public static Apfloat cbrt(Apfloat x) throws ApfloatRuntimeException { return root(x, 3); } /** * Positive integer root. * * @param x The argument. * @param n Which root to take. * * @return n:th root of x, that is x1/n. * * @exception ArithmeticException If n is zero, or x is negative and n is even. */ public static Apfloat root(Apfloat x, long n) throws ArithmeticException, ApfloatRuntimeException { if (n == 0) { throw new ArithmeticException("Zeroth root"); } else if (x.signum() == 0) { return Apfloat.ZEROS[x.radix()]; // Avoid division by zero } else if (n == 1) { return x; } else if (n == 0x8000000000000000L) { return sqrt(inverseRoot(x, n / -2)); } else if (n < 0) { return inverseRoot(x, -n); } else if (n == 2) { return x.multiply(inverseRoot(x, 2)); } else if (n == 3) { Apfloat y = x.multiply(x); return x.multiply(inverseRoot(y, 3)); } else { Apfloat y = inverseRoot(x, n); return inverseRoot(y, 1); } } /** * Inverse positive integer root. * * @param x The argument. * @param n Which inverse root to take. * * @return Inverse n:th root of x, that is x-1/n. * * @exception ArithmeticException If x or n is zero, or x is negative and n is even. */ public static Apfloat inverseRoot(Apfloat x, long n) throws ArithmeticException, ApfloatRuntimeException { return inverseRoot(x, n, x.precision()); } /** * Inverse positive integer root. * * @param x The argument. * @param n Which inverse root to take. * @param targetPrecision Precision of the desired result. * * @return Inverse n:th root of x, that is x-1/n. * * @exception IllegalArgumentException If targetPrecision <= 0. * @exception ArithmeticException If x or n is zero, or x is negative and n is even. */ public static Apfloat inverseRoot(Apfloat x, long n, long targetPrecision) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return inverseRoot(x, n, targetPrecision, null); } /** * Inverse positive integer root. * * @param x The argument. * @param n Which inverse root to take. * @param targetPrecision Precision of the desired result. * @param initialGuess Initial guess for the result value, or null if none is available. * * @return Inverse n:th root of x, that is x-1/n. * * @exception IllegalArgumentException If targetPrecision <= 0. * @exception ArithmeticException If x or n is zero, or x is negative and n is even. */ public static Apfloat inverseRoot(Apfloat x, long n, long targetPrecision, Apfloat initialGuess) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return inverseRoot(x, n, targetPrecision, initialGuess, initialGuess == null ? 0 : initialGuess.precision()); } /** * Inverse positive integer root.

* * This method is the basis for most of apfloat's non-elementary operations. * It is used e.g. in {@link Apfloat#divide(Apfloat)}, {@link #sqrt(Apfloat)} * and {@link #root(Apfloat,long)}. * * @param x The argument. * @param n Which inverse root to take. * @param targetPrecision Precision of the desired result. * @param initialGuess Initial guess for the result value, or null if none is available. * @param initialPrecision Precision of the initial guess, if available. * * @return Inverse n:th root of x, that is x-1/n. * * @exception IllegalArgumentException If targetPrecision <= 0 or initialPrecision <= 0. * @exception ArithmeticException If x or n is zero, or x is negative and n is even. */ public static Apfloat inverseRoot(Apfloat x, long n, long targetPrecision, Apfloat initialGuess, long initialPrecision) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0) { throw new ArithmeticException("Inverse root of zero"); } else if (n == 0) { throw new ArithmeticException("Inverse zeroth root"); } else if ((n & 1) == 0 && x.signum() < 0) { throw new ArithmeticException("Even root of negative number; result would be complex"); } else if (targetPrecision <= 0) { throw new IllegalArgumentException("Target precision " + targetPrecision + " is not positive"); } else if (x.equals(Apfloat.ONE)) { // Trivial case return x.precision(targetPrecision); } else if (targetPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate inverse root to infinite precision"); } else if (n == 0x8000000000000000L) { Apfloat y = inverseRoot(x, n / -2); return inverseRoot(y, 2); } else if (n < 0) { Apfloat y = inverseRoot(x, -n); return inverseRoot(y, 1); } long precision, doublePrecision = ApfloatHelper.getDoublePrecision(x.radix()); Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()), divisor = new Apfloat(n, Apfloat.INFINITE, x.radix()), result; if (initialGuess == null || initialPrecision < doublePrecision) { // Calculate initial guess from x long scaleQuot = x.scale() / n, scaleRem = x.scale() - scaleQuot * n; result = x.precision(doublePrecision); result = scale(result, -result.scale()); // Allow scales in exess of doubles' precision = doublePrecision; result = new Apfloat((double) result.signum() * Math.pow(Math.abs(result.doubleValue()), -1.0 / (double) n) * Math.pow((double) x.radix(), (double) -scaleRem / (double) n), precision, x.radix()); result = scale(result, -scaleQuot); } else { // Take initial guess as given result = initialGuess; precision = initialPrecision; } int iterations = 0; // Compute total number of iterations for (long maxPrec = precision; maxPrec < targetPrecision; maxPrec <<= 1) { iterations++; } int precisingIteration = iterations; // Check where the precising iteration should be done for (long minPrec = precision; precisingIteration > 0; precisingIteration--, minPrec <<= 1) { if ((minPrec - Apfloat.EXTRA_PRECISION) << precisingIteration >= targetPrecision) { break; } } x = ApfloatHelper.extendPrecision(x); // Newton's iteration while (iterations-- > 0) { precision *= 2; result = result.precision(Math.min(precision, targetPrecision)); Apfloat t = pow(result, n); t = lastIterationExtendPrecision(iterations, precisingIteration, t); t = one.subtract(x.multiply(t)); if (iterations < precisingIteration) { t = t.precision(precision / 2); } result = lastIterationExtendPrecision(iterations, precisingIteration, result); result = result.add(result.multiply(t).divide(divisor)); // Precising iteration if (iterations == precisingIteration) { t = pow(result, n); t = lastIterationExtendPrecision(iterations, -1, t); result = lastIterationExtendPrecision(iterations, -1, result); result = result.add(result.multiply(one.subtract(x.multiply(t))).divide(divisor)); } } return result.precision(targetPrecision); } /** * Floor function. Returns the largest (closest to positive infinity) value * that is not greater than the argument and is equal to a mathematical integer. * * @param x The argument. * * @return x rounded towards negative infinity. */ public static Apint floor(Apfloat x) throws ApfloatRuntimeException { return x.floor(); } /** * Ceiling function. Returns the smallest (closest to negative infinity) value * that is not less than the argument and is equal to a mathematical integer. * * @param x The argument. * * @return x rounded towards positive infinity. */ public static Apint ceil(Apfloat x) throws ApfloatRuntimeException { return x.ceil(); } /** * Truncates fractional part. * * @param x The argument. * * @return x rounded towards zero. */ public static Apint truncate(Apfloat x) throws ApfloatRuntimeException { return x.truncate(); } /** * Extracts fractional part. * * @param x The argument. * * @return The fractional part of x. * * @since 1.7.0 */ public static Apfloat frac(Apfloat x) throws ApfloatRuntimeException { return x.frac(); } /** * Rounds the given number to the specified precision with the specified rounding mode. * * @deprecated Use {@link #roundToPrecision(Apfloat,long,RoundingMode)}. * * @param x The number to round. * @param precision The precision to round to. * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception IllegalArgumentException If precision is less than zero or zero. * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.7.0 */ @Deprecated public static Apfloat round(Apfloat x, long precision, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return roundToPrecision(x, precision, roundingMode); } /** * Rounds the given number to the specified precision with the specified rounding mode. * * @param x The number to round. * @param precision The precision to round to. * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception IllegalArgumentException If precision is less than zero or zero. * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public static Apfloat roundToPrecision(Apfloat x, long precision, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return RoundingHelper.roundToPrecision(x, precision, roundingMode); } /** * Rounds x to integer using the specified rounding mode. * * @param x The number to round. * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public static Apint roundToInteger(Apfloat x, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return RoundingHelper.roundToInteger(x, roundingMode); } /** * Rounds x to the specified number of places using the specified rounding mode. * * @param x The number to round. * @param places The number of places to round to (in base 10, the number of decimal places). * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public static Apfloat roundToPlaces(Apfloat x, long places, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return RoundingHelper.roundToPlaces(x, places, roundingMode); } /** * Rounds x to the nearest multiple of y using the specified rounding mode. * * @param x The number to round. * @param y The integer multiple to round to. * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public static Apfloat roundToMultiple(Apfloat x, Apfloat y, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return RoundingHelper.roundToMultiple(x, y, roundingMode); } /** * Returns an apfloat whose value is -x. * * @deprecated Use {@link Apfloat#negate()}. * * @param x The argument. * * @return -x. */ @Deprecated public static Apfloat negate(Apfloat x) throws ApfloatRuntimeException { return x.negate(); } /** * Absolute value. * * @param x The argument. * * @return Absolute value of x. */ public static Apfloat abs(Apfloat x) throws ApfloatRuntimeException { if (x.signum() >= 0) { return x; } else { return x.negate(); } } /** * Copy sign from one argument to another. * * @param x The value whose sign is to be adjusted. * @param y The value whose sign is to be used. * * @return x with its sign changed to match the sign of y. * * @since 1.1 */ public static Apfloat copySign(Apfloat x, Apfloat y) throws ApfloatRuntimeException { if (y.signum() == 0) { return y; } else if (x.signum() != y.signum()) { return x.negate(); } else { return x; } } /** * Multiply by a power of the radix. * * @param x The argument. * @param scale The scaling factor. * * @return x * x.radix()scale. */ public static Apfloat scale(Apfloat x, long scale) throws ApfloatRuntimeException { if (scale == 0 || x.signum() == 0) { return x; } Apfloat radix = new Apfloat(x.radix(), Apfloat.INFINITE, x.radix()), result; if ((Math.abs(scale) & 0xC000000000000000L) != 0) { // The exponent might overflow in the string or in intermediate calculations Apfloat scaler1 = pow(radix, Math.abs(scale) >>> 1), scaler2 = ((scale & 1) == 0 ? scaler1 : scaler1.multiply(radix)); result = (scale >= 0 ? x.multiply(scaler1).multiply(scaler2) : x.divide(scaler1).divide(scaler2)); } else if (x.radix() <= 14) { Apfloat scaler = new Apfloat("1e" + scale, Apfloat.INFINITE, x.radix()); result = x.multiply(scaler); } else { // "e" would be interpreted as a digit Apfloat scaler = pow(radix, Math.abs(scale)); result = (scale >= 0 ? x.multiply(scaler) : x.divide(scaler)); } return result; } /** * Split to integer and fractional parts. * The integer part is simply i = floor(x). * For the fractional part f the following is always true:

* * 0 <= f < 1 * * @param x The argument. * * @return An array of two apfloats, [i, f], the first being the integer part and the last being the fractional part. */ public static Apfloat[] modf(Apfloat x) throws ApfloatRuntimeException { Apfloat[] result = new Apfloat[2]; result[0] = x.floor(); result[1] = (x.signum() >= 0 ? x.frac() : x.subtract(result[0])); return result; } /** * Returns x modulo y.

* * This function calculates the remainder f of x / y * such that x = i * y + f, where i is an integer, * f has the same sign as x, * and the absolute value of f is less than the absolute value of y.

* * If y is zero, then zero is returned. * * @param x The dividend. * @param y The divisor. * * @return The remainder when x is divided by y. */ public static Apfloat fmod(Apfloat x, Apfloat y) throws ApfloatRuntimeException { if (y.signum() == 0) { return y; // By definition } else if (x.signum() == 0) { // 0 % x = 0 return x; } long precision; Apfloat t, a, b, tx, ty; a = abs(x); b = abs(y); if (a.compareTo(b) < 0) { return x; // abs(x) < abs(y) } long scaleDiff = x.scale() - y.scale(); // We now know that x.scale() >= y.scale() scaleDiff = (scaleDiff < 0 ? Apfloat.INFINITE : scaleDiff); // Check for overflow if (x.precision() <= scaleDiff) // We now know that scaleDiff >= 0 { return Apfloat.ZEROS[x.radix()]; // Degenerate case; not enough precision to make any sense } else { precision = ApfloatHelper.extendPrecision(scaleDiff); // Some extra precision to avoid round-off errors } tx = x.precision(precision); ty = y.precision(precision); t = tx.divide(ty).truncate(); // Approximate division precision = Math.min(Util.ifFinite(y.precision(), y.precision() + x.scale() - y.scale()), x.precision()); tx = x.precision(precision); ty = y.precision(precision); a = abs(tx).subtract(abs(t.multiply(ty))); b = abs(ty); if (a.compareTo(b) >= 0) // Fix division round-off error { a = a.subtract(b); } else if (a.signum() < 0) // Fix division round-off error { a = a.add(b); } t = copySign(a, x); return t; } /** * Fused multiply-add. Calculates a * b + c * d * so that the precision used in the multiplications is only * what is needed for the end result. Performance can this way * be better than by calculating a.multiply(b).add(c.multiply(d)). * * @param a First argument. * @param b Second argument. * @param c Third argument. * @param d Fourth argument. * * @return a * b + c * d. */ public static Apfloat multiplyAdd(Apfloat a, Apfloat b, Apfloat c, Apfloat d) throws ApfloatRuntimeException { return multiplyAddOrSubtract(a, b, c, d, false); } /** * Fused multiply-subtract. Calculates a * b - c * d * so that the precision used in the multiplications is only * what is needed for the end result. Performance can this way * be better than by calculating a.multiply(b).subtract(c.multiply(d)). * * @param a First argument. * @param b Second argument. * @param c Third argument. * @param d Fourth argument. * * @return a * b - c * d. */ public static Apfloat multiplySubtract(Apfloat a, Apfloat b, Apfloat c, Apfloat d) throws ApfloatRuntimeException { return multiplyAddOrSubtract(a, b, c, d, true); } private static Apfloat multiplyAddOrSubtract(Apfloat a, Apfloat b, Apfloat c, Apfloat d, boolean subtract) throws ApfloatRuntimeException { long[] precisions; Apfloat ab, cd; precisions = ApfloatHelper.getMatchingPrecisions(a, b, c, d); if (precisions[0] == 0) { ab = Apfloat.ZEROS[a.radix()]; } else { a = a.precision(precisions[0]); b = b.precision(precisions[0]); ab = a.multiply(b); } if (precisions[1] == 0) { cd = Apfloat.ZEROS[c.radix()]; } else { c = c.precision(precisions[1]); d = d.precision(precisions[1]); cd = c.multiply(d); } Apfloat result = (subtract ? ab.subtract(cd) : ab.add(cd)); return (result.signum() == 0 ? result : result.precision(precisions[2])); } /** * Arithmetic-geometric mean. * * @param a First argument. * @param b Second argument. * * @return Arithmetic-geometric mean of a and b. */ public static Apfloat agm(Apfloat a, Apfloat b) throws ApfloatRuntimeException { return agm(a, b, null); } static Apfloat agm(Apfloat a, Apfloat b, Consumer consumer) throws ApfloatRuntimeException { if (a.signum() == 0 || b.signum() == 0) // Would not converge quadratically { return Apfloat.ZEROS[a.radix()]; } if (abs(a).equals(abs(b))) // Would not converge quadratically { return a.signum() == b.signum() ? a.precision(Math.min(a.precision(), b.precision())) : Apfloat.ZEROS[a.radix()]; } if (a.signum() != b.signum()) { throw new ArithmeticException("Non-real result"); } boolean negate = a.signum() < 0; // Thanks to Marko Gaspersic for finding several bugs in issue #12 if (negate) { a = a.negate(); b = b.negate(); } long workingPrecision = Math.min(a.precision(), b.precision()), targetPrecision = workingPrecision; if (workingPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate agm to infinite precision"); } // Some extra precision is required for the algorithm to work accurately workingPrecision = ApfloatHelper.extendPrecision(workingPrecision); a = ApfloatHelper.ensurePrecision(a, workingPrecision); b = ApfloatHelper.ensurePrecision(b, workingPrecision); long precision = 0, halfWorkingPrecision = (workingPrecision + 1) / 2; final long CONVERGING = 1000; // Arbitrarily chosen value... Apfloat two = new Apfloat(2, Apfloat.INFINITE, a.radix()), c2 = null; if (consumer != null) { c2 = ApfloatHelper.ensurePrecision(a.multiply(a).subtract(b.multiply(b)), workingPrecision); consumer.accept(c2); } // First check convergence while (precision < CONVERGING && precision < halfWorkingPrecision) { Apfloat t = a.add(b).divide(two); b = sqrt(a.multiply(b)); a = t; // Conserve precision in case of accumulating round-off errors a = ApfloatHelper.ensurePrecision(a, workingPrecision); b = ApfloatHelper.ensurePrecision(b, workingPrecision); precision = a.equalDigits(b); c2 = agmConsume(consumer, a, c2, workingPrecision); } // Now we know quadratic convergence while (precision <= halfWorkingPrecision) { Apfloat t = a.add(b).divide(two); b = sqrt(a.multiply(b)); a = t; // Conserve precision in case of accumulating round-off errors a = ApfloatHelper.ensurePrecision(a, workingPrecision); b = ApfloatHelper.ensurePrecision(b, workingPrecision); precision *= 2; c2 = agmConsume(consumer, a, c2, workingPrecision); } Apfloat result = a.add(b).divide(two).precision(targetPrecision); agmConsume(consumer, result, c2, workingPrecision); return (negate ? result.negate() : result); } private static Apfloat agmConsume(Consumer consumer, Apfloat a, Apfloat c2, long workingPrecision) { if (consumer != null) { Apfloat four = new Apfloat(4, Apfloat.INFINITE, a.radix()), c = ApfloatHelper.ensurePrecision(c2.divide(four.multiply(a)), workingPrecision); c2 = ApfloatHelper.ensurePrecision(c.multiply(c), workingPrecision); consumer.accept(c2); } return c2; } /** * Calculates π. Uses default radix. * * @param precision Number of digits of π to calculate. * * @return π accurate to precision digits, in the default radix. * * @exception NumberFormatException If the default radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. */ public static Apfloat pi(long precision) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return pi(precision, radix); } /** * Calculates π. * * @param precision Number of digits of π to calculate. * @param radix The radix in which the number should be presented. * * @return π accurate to precision digits, in base radix. * * @exception NumberFormatException If the radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. */ public static Apfloat pi(long precision, int radix) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { if (precision <= 0) { throw new IllegalArgumentException("Precision " + precision + " is not positive"); } else if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate pi to infinite precision"); } // Get synchronization lock - getting the lock is also synchronized Object radixKey = getRadixKey(ApfloatMath.radixPiKeys, radix); Apfloat pi; // Synchronize getting pre-calculated pi by radix key // - two threads won't try to calculate it at the same time // - doesn't block getting it for other radixes synchronized (radixKey) { pi = ApfloatMath.radixPi.get(radix); if (pi == null || pi.precision() < precision) { pi = calculatePi(precision, radix); } else { pi = pi.precision(precision); } } return pi; } /** * Simple JavaBean to hold one apfloat. This class can * also be thought of as a pointer to an apfloat. */ static class ApfloatHolder { public ApfloatHolder() { this(null); } public ApfloatHolder(Apfloat apfloat) { this.apfloat = apfloat; } public Apfloat getApfloat() { return this.apfloat; } public void setApfloat(Apfloat apfloat) { this.apfloat = apfloat; } private Apfloat apfloat; } private static class PiCalculator { public PiCalculator(int radix) throws ApfloatRuntimeException { this.A = new Apfloat(13591409, Apfloat.INFINITE, radix); this.B = new Apfloat(545140134, Apfloat.INFINITE, radix); this.J = new Apfloat(10939058860032000L, Apfloat.INFINITE, radix); this.ONE = new Apfloat(1, Apfloat.INFINITE, radix); this.TWO = new Apfloat(2, Apfloat.INFINITE, radix); this.FIVE = new Apfloat(5, Apfloat.INFINITE, radix); this.SIX = new Apfloat(6, Apfloat.INFINITE, radix); this.radix = radix; } private Apfloat a(long n) throws ApfloatRuntimeException { Apfloat s = new Apfloat(n, Apfloat.INFINITE, this.radix), v = this.A.add(this.B.multiply(s)); v = ((n & 1) == 0 ? v : v.negate()); return v; } private Apfloat p(long n) throws ApfloatRuntimeException { Apfloat v; if (n == 0) { v = this.ONE; } else { Apfloat f = new Apfloat(n, Apfloat.INFINITE, this.radix), sixf = this.SIX.multiply(f); v = sixf.subtract(this.ONE).multiply(this.TWO.multiply(f).subtract(this.ONE)).multiply(sixf.subtract(this.FIVE)); } return v; } private Apfloat q(long n) throws ApfloatRuntimeException { Apfloat v; if (n == 0) { v = this.ONE; } else { Apfloat f = new Apfloat(n, Apfloat.INFINITE, this.radix); v = this.J.multiply(f).multiply(f).multiply(f); } return v; } public void r(long n1, long n2, ApfloatHolder T, ApfloatHolder Q, ApfloatHolder P) throws ApfloatRuntimeException { assert (n1 != n2); long length = n2 - n1; if (length == 1) { Apfloat p0 = p(n1); T.setApfloat(a(n1).multiply(p0)); Q.setApfloat(q(n1)); P.setApfloat(p0); } else { long nMiddle = (n1 + n2) / 2; ApfloatHolder LT = new ApfloatHolder(), LQ = new ApfloatHolder(), LP = new ApfloatHolder(); r(n1, nMiddle, LT, LQ, LP); r(nMiddle, n2, T, Q, P); T.setApfloat(Q.getApfloat().multiply(LT.getApfloat()).add(LP.getApfloat().multiply(T.getApfloat()))); Q.setApfloat(LQ.getApfloat().multiply(Q.getApfloat())); P.setApfloat(LP.getApfloat().multiply(P.getApfloat())); } } private final Apfloat A; private final Apfloat B; private final Apfloat J; private final Apfloat ONE; private final Apfloat TWO; private final Apfloat FIVE; private final Apfloat SIX; private int radix; } // Perform actual calculation of pi for radix, and store the result to pre-calulation maps. // Uses the Chudnovskys' binary splitting algorithm. // Uses previously calculated terms (if such exist) to improve the precision of the calculation. private static Apfloat calculatePi(long precision, int radix) throws ApfloatRuntimeException { PiCalculator piCalculator = ApfloatMath.radixPiCalculator.get(radix); if (piCalculator == null) { piCalculator = new PiCalculator(radix); ApfloatMath.radixPiCalculator.put(radix, piCalculator); } Apfloat LT, LQ, LP, inverseRoot; ApfloatHolder RT = new ApfloatHolder(), RQ = new ApfloatHolder(), RP = new ApfloatHolder(); // Perform the calculation of T, Q and P to infinite precision // to make possible to use them later for further calculations long neededTerms = (long) ((double) precision * Math.log((double) radix) / 32.65445004177), workingPrecision = ApfloatHelper.extendPrecision(precision); // To avoid cumulative round-off errors Long terms = ApfloatMath.radixPiTerms.get(radix); LT = ApfloatMath.radixPiT.get(radix); LQ = ApfloatMath.radixPiQ.get(radix); LP = ApfloatMath.radixPiP.get(radix); inverseRoot = ApfloatMath.radixPiInverseRoot.get(radix); if (terms != null && LT != null && LQ != null && LP != null && inverseRoot != null) { // Some terms have been calculated already previously and cached long currentTerms = terms; // Check if there actually are more needed terms or if the needed // extra precision is just a few digits achievable with current terms if (currentTerms != neededTerms + 1) { piCalculator.r(currentTerms, neededTerms + 1, RT, RQ, RP); LT = RQ.getApfloat().multiply(LT).add(LP.multiply(RT.getApfloat())); LQ = LQ.multiply(RQ.getApfloat()); LP = LP.multiply(RP.getApfloat()); } // Improve the inverse root value from the current precision inverseRoot = inverseRoot(new Apfloat(1823176476672000L, workingPrecision, radix), 2, workingPrecision, inverseRoot); } else { piCalculator.r(0, neededTerms + 1, RT, RQ, RP); LT = RT.getApfloat(); LQ = RQ.getApfloat(); LP = RP.getApfloat(); inverseRoot = inverseRoot(new Apfloat(1823176476672000L, workingPrecision, radix), 2); } Apfloat pi = inverseRoot(inverseRoot.multiply(LT), 1).multiply(LQ); // Limit precisions to actual after extended working precisions inverseRoot = inverseRoot.precision(precision); pi = pi.precision(precision); // Put the updated values to the caches ApfloatMath.radixPiT.put(radix, LT); ApfloatMath.radixPiQ.put(radix, LQ); ApfloatMath.radixPiP.put(radix, LP); ApfloatMath.radixPiInverseRoot.put(radix, inverseRoot); ApfloatMath.radixPiTerms.put(radix, neededTerms + 1); ApfloatMath.radixPi.put(radix, pi); return pi; } /** * Natural logarithm.

* * The logarithm is calculated using the arithmetic-geometric mean. * See the Borweins' book for the formula. * * @param x The argument. * * @return Natural logarithm of x. * * @exception ArithmeticException If x <= 0. */ public static Apfloat log(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return log(x, true); } /** * Logarithm in arbitrary base.

* * The logarithm is calculated using the arithmetic-geometric mean. * See the Borweins' book for the formula. * * @param x The argument. * @param b The base. * * @return Base-b logarithm of x. * * @exception ArithmeticException If x <= 0 or b <= 0. * * @since 1.6 */ public static Apfloat log(Apfloat x, Apfloat b) throws ArithmeticException, ApfloatRuntimeException { long targetPrecision = Math.min(x.precision(), b.precision()); Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); long xPrecision = Util.ifFinite(targetPrecision, targetPrecision + one.equalDigits(x)); // If the log() argument is close to 1, the result is less accurate x = x.precision(Math.min(x.precision(), xPrecision)); long bPrecision = Util.ifFinite(targetPrecision, targetPrecision + one.equalDigits(b)); b = b.precision(Math.min(b.precision(), bPrecision)); return log(x, false).divide(log(b, false)); } private static Apfloat log(Apfloat x, boolean multiplyByPi) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() <= 0) { throw new ArithmeticException("Logarithm of " + (x.signum() == 0 ? "zero" : "negative number; result would be complex")); } else if (x.equals(Apfloat.ONE)) { return Apfloat.ZEROS[x.radix()]; } // Calculate the log using 1 / radix <= x < 1 and the log addition formula // because the agm converges badly for big x. long targetPrecision = x.precision(); Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); long finalPrecision = Util.ifFinite(targetPrecision, targetPrecision - one.equalDigits(x)); // If the argument is close to 1, the result is less accurate if (x.scale() > 1) { double logScale = Math.log((double) x.scale() - 1) / Math.log((double) x.radix()); logScale += Math.ulp(logScale); finalPrecision = Util.ifFinite(finalPrecision, finalPrecision + (long) logScale); // If the argument is very big, the result is more accurate } long originalScale = x.scale(); x = scale(x, -originalScale); // Set x's scale to zero Apfloat radixPower; if (originalScale == 0) { radixPower = Apfloat.ZERO; } else { Apfloat logRadix = ApfloatHelper.extendPrecision(logRadix(targetPrecision, x.radix(), multiplyByPi)); radixPower = new Apfloat(originalScale, Apfloat.INFINITE, x.radix()).multiply(logRadix); } return ApfloatHelper.extendPrecision(rawLog(x, multiplyByPi)).add(radixPower).precision(finalPrecision); } // Raw logarithm, regardless of x // Doesn't work for big x, but is faster if used alone for small numbers private static Apfloat rawLog(Apfloat x, boolean multiplyByPi) throws ApfloatRuntimeException { assert (x.signum() > 0); // Must be real logarithm long targetPrecision = x.precision(); if (targetPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate logarithm to infinite precision"); } Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); final int EXTRA_PRECISION = 25; long workingPrecision = ApfloatHelper.extendPrecision(targetPrecision), n = targetPrecision / 2 + EXTRA_PRECISION; // Very rough estimate x = ApfloatHelper.extendPrecision(x, EXTRA_PRECISION); Apfloat e = one.precision(workingPrecision); e = scale(e, -n); x = scale(x, -n); Apfloat agme = ApfloatHelper.extendPrecision(agm(one, e)), agmex = ApfloatHelper.extendPrecision(agm(one, x)); Apfloat log = agmex.subtract(agme).precision(workingPrecision); if (multiplyByPi) { Apfloat pi = ApfloatHelper.extendPrecision(pi(targetPrecision, x.radix())); log = pi.multiply(log); } log = log.divide(new Apfloat(2, Apfloat.INFINITE, x.radix()).multiply(agme).multiply(agmex)); return log.precision(targetPrecision); } /** * Gets or calculates logarithm of a radix to required precision. * The calculated value is stored in a cache for later usage. * * @param precision The needed precision. * @param radix The radix. * * @return Natural logarithm of radix to the specified precision. * * @exception NumberFormatException If the radix is invalid. */ public static Apfloat logRadix(long precision, int radix) throws ApfloatRuntimeException { return logRadix(precision, radix, true); } private static Apfloat logRadix(long precision, int radix, boolean multiplyByPi) throws ApfloatRuntimeException { // Get synchronization lock - getting the lock is also synchronized Object radixKey = getRadixKey(ApfloatMath.radixLogKeys, radix); Apfloat logRadix; // Synchronize getting pre-calculated log by radix key // - two threads won't try to calculate it at the same time // - doesn't block getting it for other radixes synchronized (radixKey) { Map cache = (multiplyByPi ? ApfloatMath.radixLogPi : ApfloatMath.radixLog); // Which cache to use, the one multiplied by pi or not logRadix = cache.get(radix); if (logRadix == null || logRadix.precision() < precision) { if (multiplyByPi) { // We want the multiplied-by-pi version so get first the not-multiplied-by-pi version logRadix = ApfloatHelper.extendPrecision(logRadix(precision, radix, false)); Apfloat pi = ApfloatHelper.extendPrecision(pi(precision, radix)); logRadix = logRadix.multiply(pi).precision(precision); } else { Apfloat f = new Apfloat("0.1", precision, radix); logRadix = rawLog(f, multiplyByPi).negate(); } cache.put(radix, logRadix); } else { logRadix = logRadix.precision(precision); } } return logRadix; } /** * Exponent function. * Calculated using Newton's iteration for the inverse of logarithm. * * @param x The argument. * * @return ex. */ public static Apfloat exp(Apfloat x) throws ApfloatRuntimeException { int radix = x.radix(); if (x.signum() == 0) { return new Apfloat(1, Apfloat.INFINITE, radix); } long targetPrecision = x.precision(), precision, doublePrecision = ApfloatHelper.getDoublePrecision(radix); if (x.compareTo(new Apfloat(Long.MIN_VALUE * Math.log((double) radix), doublePrecision, radix)) <= 0) { // Underflow return Apfloat.ZEROS[radix]; } // If the argument is close to 0, the result is more accurate if (x.scale() < 1) { targetPrecision = Util.ifFinite(targetPrecision, targetPrecision + 1 - x.scale()); } // If the argument is very big, the result is less accurate long finalPrecision = targetPrecision; if (x.scale() > 1) { if (x.scale() - 1 >= targetPrecision) { throw new LossOfPrecisionException("Complete loss of accurate digits"); } finalPrecision = Util.ifFinite(targetPrecision, targetPrecision - (x.scale() - 1)); } if (targetPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate exponent to infinite precision"); } else if (x.compareTo(new Apfloat((double) Long.MAX_VALUE * Math.log((double) radix), doublePrecision, radix)) >= 0) { throw new OverflowException("Overflow"); } else if (x.scale() <= Long.MIN_VALUE / 2 + Apfloat.EXTRA_PRECISION) { // Taylor series: exp(x) = 1 + x + x^2/2 + ... return new Apfloat(1, Apfloat.INFINITE, radix).add(x).precision(Apfloat.INFINITE); } Apfloat result; if (x.scale() < -doublePrecision / 2) { // Taylor series: exp(x) = 1 + x + x^2/2 + ... precision = -2 * x.scale(); result = new Apfloat(1, precision, radix).add(x); } else { // Approximate starting value for iteration // An overflow or underflow should not occur long scaledXPrecision = Math.max(0, x.scale()) + doublePrecision; Apfloat logRadix = log(new Apfloat((double) radix, scaledXPrecision, radix)), scaledX = x.precision(scaledXPrecision).divide(logRadix), integerPart = scaledX.truncate(), fractionalPart = scaledX.frac(); result = new Apfloat(Math.pow((double) radix, fractionalPart.doubleValue()), doublePrecision, radix); result = scale(result, integerPart.longValue()); if (result.signum() == 0) { // Underflow return Apfloat.ZEROS[radix]; } precision = doublePrecision; } int iterations = 0; // Compute total number of iterations for (long maxPrec = precision; maxPrec < targetPrecision; maxPrec <<= 1) { iterations++; } int precisingIteration = iterations; // Check where the precising iteration should be done for (long minPrec = precision; precisingIteration > 0; precisingIteration--, minPrec <<= 1) { if ((minPrec - Apfloat.EXTRA_PRECISION) << precisingIteration >= targetPrecision) { break; } } if (iterations > 0) { // Precalculate the needed values once to the required precision logRadix(targetPrecision, radix); } x = ApfloatHelper.extendPrecision(x); // Newton's iteration while (iterations-- > 0) { precision *= 2; result = result.precision(Math.min(precision, targetPrecision)); Apfloat t = log(result); t = lastIterationExtendPrecision(iterations, precisingIteration, t); t = x.subtract(t); if (iterations < precisingIteration) { t = t.precision(precision / 2); } result = lastIterationExtendPrecision(iterations, precisingIteration, result); result = result.add(result.multiply(t)); // Precising iteration if (iterations == precisingIteration) { t = log(result); t = lastIterationExtendPrecision(iterations, -1, t); result = lastIterationExtendPrecision(iterations, -1, result); result = result.add(result.multiply(x.subtract(t))); } } return result.precision(finalPrecision); } /** * Arbitrary power. Calculated using log() and exp(). * * @param x The base. * @param y The exponent. * * @return xy. * * @exception ArithmeticException If both x and y are zero, or x is negative and y is not an integer. */ public static Apfloat pow(Apfloat x, Apfloat y) throws ArithmeticException, ApfloatRuntimeException { long targetPrecision = Math.min(x.precision(), y.precision()); Apfloat result = ApfloatHelper.checkPow(x, y, targetPrecision); if (result != null) { return result; } else if (x.signum() < 0 && y.isInteger()) { return ApcomplexMath.pow(x, y).real(); } // Try to precalculate the needed values just once to the required precision, // this may not work too efficiently if x is close to 1 or y is close to zero logRadix(targetPrecision, x.radix()); // Limits precision for log() but may be sub-optimal; precision could be limited more Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); targetPrecision = Util.ifFinite(targetPrecision, targetPrecision + one.equalDigits(x)); // If the log() argument is close to 1, the result is less accurate x = x.precision(Math.min(x.precision(), targetPrecision)); result = log(x); long intermediatePrecision = Math.min(y.precision(), result.precision()); result = ApfloatHelper.extendPrecision(result); result = ApfloatHelper.extendPrecision(y).multiply(result); result = exp(result.precision(intermediatePrecision)); return result; } /** * Inverse hyperbolic cosine. Calculated using log(). * * @param x The argument. * * @return Inverse hyperbolic cosine of x. * * @exception ArithmeticException If x < 1. */ public static Apfloat acosh(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); return log(x.add(sqrt(x.multiply(x).subtract(one)))); } /** * Inverse hyperbolic sine. Calculated using log(). * * @param x The argument. * * @return Inverse hyperbolic sine of x. */ public static Apfloat asinh(Apfloat x) throws ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); if (x.signum() >= 0) { return log(sqrt(x.multiply(x).add(one)).add(x)); } else { return log(sqrt(x.multiply(x).add(one)).subtract(x)).negate(); } } /** * Inverse hyperbolic tangent. Calculated using log(). * * @param x The argument. * * @return Inverse hyperbolic tangent of x. * * @exception ArithmeticException If abs(x) >= 1. */ public static Apfloat atanh(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()), two = new Apfloat(2, Apfloat.INFINITE, x.radix()); return log(one.add(x).divide(one.subtract(x))).divide(two); } /** * Hyperbolic cosine. Calculated using exp(). * * @param x The argument. * * @return Hyperbolic cosine of x. */ public static Apfloat cosh(Apfloat x) throws ApfloatRuntimeException { Apfloat y = exp(x), one = new Apfloat(1, Apfloat.INFINITE, x.radix()), two = new Apfloat(2, Apfloat.INFINITE, x.radix()); return y.add(one.divide(y)).divide(two); } /** * Hyperbolic sine. Calculated using exp(). * * @param x The argument. * * @return Hyperbolic sine of x. */ public static Apfloat sinh(Apfloat x) throws ApfloatRuntimeException { Apfloat y = exp(x), one = new Apfloat(1, Apfloat.INFINITE, x.radix()), two = new Apfloat(2, Apfloat.INFINITE, x.radix()); return y.subtract(one.divide(y)).divide(two); } /** * Hyperbolic tangent. Calculated using exp(). * * @param x The argument. * * @return Hyperbolic tangent of x. */ public static Apfloat tanh(Apfloat x) throws ApfloatRuntimeException { return tanh(x, x.signum() > 0); } static Apfloat tanhFixedPrecision(Apfloat x) throws ApfloatRuntimeException { return tanh(x, x.signum() < 0); } private static Apfloat tanh(Apfloat x, boolean negate) throws ApfloatRuntimeException { x = (negate ? x.negate() : x); Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()), two = new Apfloat(2, Apfloat.INFINITE, x.radix()), y = exp(two.multiply(x)); y = y.subtract(one).divide(y.add(one)); return (negate ? y.negate() : y); } /** * Inverse cosine. Calculated using complex functions. * * @param x The argument. * * @return Inverse cosine of x. * * @exception ArithmeticException If abs(x) > 1. */ public static Apfloat acos(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); Apcomplex i = new Apcomplex(Apfloat.ZERO, one); return ApcomplexMath.log(x.add(i.multiply(sqrt(one.subtract(x.multiply(x)))))).imag(); } static Apfloat acos(Apfloat x, long precision) { if (x.signum() == 0) { return halfPi(x.radix(), precision); } return acos(x); } static Apfloat halfPi(int radix, long precision) { return pi(precision, radix).divide(new Apfloat(2, precision, radix)); } /** * Inverse sine. Calculated using complex functions. * * @param x The argument. * * @return Inverse sine of x. * * @exception ArithmeticException If abs(x) > 1. */ public static Apfloat asin(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()); Apcomplex i = new Apcomplex(Apfloat.ZERO, one); return ApcomplexMath.log(sqrt(one.subtract(x.multiply(x))).subtract(i.multiply(x))).imag().negate(); } /** * Inverse tangent. Calculated using complex functions. * * @param x The argument. * * @return Inverse tangent of x. */ public static Apfloat atan(Apfloat x) throws ApfloatRuntimeException { Apfloat one = new Apfloat(1, Apfloat.INFINITE, x.radix()), two = new Apfloat(2, Apfloat.INFINITE, x.radix()); Apcomplex i = new Apcomplex(Apfloat.ZERO, one); return ApcomplexMath.log(i.subtract(x).divide(i.add(x))).imag().divide(two); } /** * Converts cartesian coordinates to polar coordinates. Calculated using complex functions.

* * Computes the phase angle by computing an arc tangent of y/x in the range of -π < angle <= π. * * @param y The argument. * @param x The argument. * * @return The angle of the point (x, y) in the plane. * * @exception ArithmeticException If y and x are both zero. */ public static Apfloat atan2(Apfloat y, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0) { if (y.signum() == 0) { throw new ArithmeticException("Angle of (0, 0)"); } Apfloat pi = pi(y.precision(), y.radix()), two = new Apfloat(2, Apfloat.INFINITE, y.radix()); return new Apfloat(y.signum(), Apfloat.INFINITE, y.radix()).multiply(pi).divide(two); } else if (y.signum() == 0) { if (x.signum() > 0) { return Apfloat.ZEROS[x.radix()]; } return pi(x.precision(), x.radix()); } else if (Math.min(y.precision(), x.precision()) == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate atan2 to infinite precision"); } else if (x.signum() > 0 && y.scale() < x.scale()) { // The log formula below is inaccurate if y is small in magnitude compared to x return atan(y.divide(x)); } else { long maxScale = Math.max(y.scale(), x.scale()); y = scale(y, -maxScale); // Now neither y nor x is zero x = scale(x, -maxScale); return ApcomplexMath.log(new Apcomplex(x, y)).imag(); } } /** * Cosine. Calculated using complex functions. * * @param x The argument (in radians). * * @return Cosine of x. */ public static Apfloat cos(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.exp(new Apcomplex(Apfloat.ZERO, x)).real(); } /** * Sine. Calculated using complex functions. * * @param x The argument (in radians). * * @return Sine of x. */ public static Apfloat sin(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.exp(new Apcomplex(Apfloat.ZERO, x)).imag(); } /** * Tangent. Calculated using complex functions. * * @param x The argument (in radians). * * @return Tangent of x. * * @exception ArithmeticException If x is π/2 + n π where n is an integer. */ public static Apfloat tan(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apcomplex w = ApcomplexMath.exp(new Apcomplex(Apfloat.ZERO, x)); return w.imag().divide(w.real()); } /** * Sinc. * * @param x The argument. * * @return sinc(x) * * @since 1.14.0 */ public static Apfloat sinc(Apfloat x) throws ApfloatRuntimeException { if (x.isZero()) { return Apfloat.ONES[x.radix()]; } return sin(x).divide(x); } /** * Lambert W function. The W function gives the solution to the equation * W eW = x. Also known as the product logarithm.

* * This function only gives the solution to the principal branch, W0. * For the real-valued W-1 branch, use {@link ApcomplexMath#w(Apcomplex,long)}. * * @param x The argument. * * @return W0(x). * * @exception ArithmeticException If x is less than -1/e. * * @since 1.8.0 */ public static Apfloat w(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return LambertWHelper.w(x); } /** * Converts an angle measured in radians to degrees.

* * @param x The angle, in radians. * * @return The angle in degrees. * * @since 1.8.0 */ public static Apfloat toDegrees(Apfloat x) throws ApfloatRuntimeException { return x.signum() == 0 ? x : x.multiply(new Apfloat(180, Apfloat.INFINITE, x.radix())).divide(pi(x.precision(), x.radix())); // Thanks to Marko Gaspersic for finding the bug in issue #11 } /** * Converts an angle measured in degrees to radians.

* * @param x The angle, in degrees. * * @return The angle in radians. * * @since 1.8.0 */ public static Apfloat toRadians(Apfloat x) throws ApfloatRuntimeException { return x.signum() == 0 ? x : x.divide(new Apfloat(180, Apfloat.INFINITE, x.radix())).multiply(pi(x.precision(), x.radix())); // Thanks to Marko Gaspersic for finding the bug in issue #11 } /** * Product of numbers. * The precision used in the multiplications is only * what is needed for the end result. This method may * perform significantly better than simply multiplying * the numbers sequentially.

* * If there are no arguments, the return value is 1. * * @param x The argument(s). * * @return The product of the given numbers. * * @since 1.3 */ public static Apfloat product(Apfloat... x) throws ApfloatRuntimeException { if (x.length == 0) { return Apfloat.ONE; } // Determine working precision long maxPrec = Apfloat.INFINITE; for (int i = 0; i < x.length; i++) { if (x[i].signum() == 0) { return Apfloat.ZEROS[x[i].radix()]; } maxPrec = Math.min(maxPrec, x[i].precision()); } // Do not use x.clone() as the array might be of some subclass type, resulting in ArrayStoreException later Apfloat[] tmp = new Apfloat[x.length]; // Add sqrt length digits for round-off errors long extraPrec = (long) Math.sqrt((double) x.length), destPrec = ApfloatHelper.extendPrecision(maxPrec, extraPrec); for (int i = 0; i < x.length; i++) { tmp[i] = x[i].precision(destPrec); } x = tmp; // Create a heap, ordered by size Queue heap = new PriorityQueue<>(x.length, Comparator.comparing(Apfloat::size)); // Perform the multiplications in parallel ParallelHelper.ProductKernel kernel = (h) -> { Apfloat a = h.remove(); Apfloat b = h.remove(); Apfloat c = a.multiply(b); h.add(c); }; ParallelHelper.parallelProduct(x, heap, kernel); return heap.remove().precision(maxPrec); } /** * Sum of numbers. * The precision used in the additions is only * what is needed for the end result. This method may * perform significantly better than simply adding * the numbers sequentially.

* * If there are no arguments, the return value is 0. * * @param x The argument(s). * * @return The sum of the given numbers. * * @since 1.3 */ public static Apfloat sum(Apfloat... x) throws ApfloatRuntimeException { if (x.length == 0) { return Apfloat.ZERO; } // Determine working precision long maxScale = -Apfloat.INFINITE, maxPrec = Apfloat.INFINITE; for (int i = 0; i < x.length; i++) { long oldScale = maxScale, oldPrec = maxPrec, newScale = x[i].scale(), newPrec = x[i].precision(); maxScale = Math.max(oldScale, newScale); long oldScaleDiff = (maxScale - oldScale < 0 ? Apfloat.INFINITE : maxScale - oldScale), newScaleDiff = (maxScale - newScale < 0 ? Apfloat.INFINITE : maxScale - newScale); maxPrec = Math.min(Util.ifFinite(oldPrec, oldPrec + oldScaleDiff), Util.ifFinite(newPrec, newPrec + newScaleDiff)); } // Do not use x.clone() as the array might be of some subclass type, resulting in ArrayStoreException later Apfloat[] tmp = new Apfloat[x.length]; for (int i = 0; i < x.length; i++) { long scale = x[i].scale(), scaleDiff = (maxScale - scale < 0 ? Apfloat.INFINITE : maxScale - scale), destPrec = (maxPrec - scaleDiff <= 0 ? 0 : Util.ifFinite(maxPrec, maxPrec - scaleDiff)); if (destPrec > 0) { tmp[i] = x[i].precision(destPrec); } else { tmp[i] = Apfloat.ZERO; } } x = tmp; // Sort by scale (might be mostly equal to size) Comparator comparator = Comparator.comparing(Apfloat::scale); Arrays.sort(x, comparator); // The list of numbers to be added List list; // If there are lots of numbers then use a fully parallel algorithm, for small sums the overhead is not worth it // Also note that memory (or worse - disk) bandwidth is likely a bottleneck, preventing efficient parallelization if (x.length >= 1000) { // Only add in parallel numbers, which are (probably) below the memory threshold in size ApfloatContext ctx = ApfloatContext.getContext(); long maxSize = (long) (ctx.getMemoryThreshold() * 5.0 / Math.log((double) ctx.getDefaultRadix())); // Create a queue of small numbers where the parallel algorithm can add and remove elements Queue queue = new ConcurrentLinkedQueue<>(); // The large numbers go to the list where they will be added using a single thread algorithm list = new ArrayList<>(); // Put all the numbers to either the parallel queue or single thread list for (Apfloat a : x) { (a.size() <= maxSize ? queue : list).add(a); } Runnable runnable = () -> { // Add numbers as long as there are any left in the queue Apfloat s = Apfloat.ZERO, a; while ((a = queue.poll()) != null) { s = s.add(a); } // Finally, put the sub-sum back in the queue queue.add(s); }; // Run the runnable in multiple threads ParallelHelper.runParallel(runnable); // Put the remaining sub-sums to the list to be added once more list.addAll(queue); // Sort again the list as it has been now mixed up Collections.sort(list, comparator); } else { // Single thread case - just add all the numbers list = Arrays.asList(x); } // Add the remaining elements in the queue (all, for the single-thread case, and sub-sums for the parallel case) Apfloat s = Apfloat.ZERO; for (Apfloat a : list) { s = s.add(a); } return s; } /** * Calculates e. Uses default radix. * * @param precision Number of digits of e to calculate. * * @return e accurate to precision digits, in the default radix. * * @throws NumberFormatException If the default radix is not valid. * @throws IllegalArgumentException In case the precision is invalid. * * @since 1.11.0 */ public static Apfloat e(long precision) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return e(precision, radix); } /** * Calculates e. * * @param precision Number of digits of e to calculate. * @param radix The radix in which the number should be presented. * * @return e accurate to precision digits, in base radix. * * @throws NumberFormatException If the radix is not valid. * @throws IllegalArgumentException In case the precision is invalid. * * @since 1.11.0 */ public static Apfloat e(long precision, int radix) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { if (precision <= 0) { throw new IllegalArgumentException("Precision " + precision + " is not positive"); } else if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate e to infinite precision"); } long terms = inverseFactorial(precision, radix); Apfloat[] pq = e(1, terms, precision, radix); return pq[0].divide(pq[1]).add(Apfloat.ONES[radix]); } // Rough approximation of log(n!) = n log n - n private static long inverseFactorial(long precision, int radix) { double x = precision * Math.log(radix) + 7, // Does not work with extremely low precision n = x, p; do { p = n; n = x / (Math.log(n) - 1); } while ((long) p != (long) n); return (long) Math.ceil(n); } private static Apfloat[] e(long start, long end, long precision, int radix) { if (end - start == 1) { Apfloat[] pq = { Apfloat.ONES[radix], new Apfloat(start, precision, radix) }; return pq; } long mid = start + end >>> 1; Apfloat[] first = e(start, mid, precision, radix), last = e(mid, end, precision, radix), pq = { first[0].multiply(last[1]).add(last[0]), first[1].multiply(last[1]) }; return pq; } /** * Calculates γ, the Euler-Mascheroni constant. Uses default radix. * * @param precision Number of digits of γ to calculate. * * @return γ accurate to precision digits, in the default radix. * * @exception NumberFormatException If the default radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @since 1.10.0 */ public static Apfloat euler(long precision) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return euler(precision, radix); } /** * Calculates γ, the Euler-Mascheroni constant. * * @param precision Number of digits of γ to calculate. * @param radix The radix in which the number should be presented. * * @return γ accurate to precision digits, in base radix. * * @exception NumberFormatException If the radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @since 1.10.0 */ public static Apfloat euler(long precision, int radix) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { if (precision <= 0) { throw new IllegalArgumentException("Precision " + precision + " is not positive"); } else if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate Euler gamma to infinite precision"); } return (precision <= 2000 ? eulerSmall(precision, radix) : EulerHelper.euler(precision, radix)); } static Apfloat eulerSmall(long precision, int radix) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { // See https://www.ams.org/journals/mcom/1980-34-149/S0025-5718-1980-0551307-4/S0025-5718-1980-0551307-4.pdf // Mathematics of Computation, volume 34, number 149, January 1980, pages 305-312 // "Some new algorithms for high-precision computation of Euler's constant" by Richard P. Brent and Edwin M. McMillan long n = (long) (Apfloat.EXTRA_PRECISION + 0.25 * Math.log(radix) * precision), workingPrecision = ApfloatHelper.extendPrecision(precision), targetPrecision = ApfloatHelper.extendPrecision(precision, Apfloat.EXTRA_PRECISION / 2); Apfloat a = log(new Apfloat(n, workingPrecision, radix)).negate(), b = new Apfloat(1, workingPrecision, radix), u = a, v = b, ou, ov; Apint one = new Apint(1, radix), k = one, n2 = ApintMath.pow(new Apint(n, radix), 2); do { ou = u; ov = v; b = b.multiply(n2).divide(pow(k, 2)); a = a.multiply(n2).divide(k).add(b).divide(k); u = u.add(a); v = v.add(b); k = k.add(one); } while (u.equalDigits(ou) < targetPrecision || v.equalDigits(ov) < targetPrecision); return u.divide(v).precision(precision); } /** * Calculates Catalan's constant, G. Uses the default radix.

* * @implNote * This implementation is slow. * * @param precision Number of digits of G to calculate. * * @return G accurate to precision digits, in the default radix. * * @exception NumberFormatException If the default radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @since 1.11.0 */ public static Apfloat catalan(long precision) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return catalan(precision, radix); } /** * Calculates Catalan's constant, G. Uses the specified radix.

* * @implNote * This implementation is slow. * * @param precision Number of digits of G to calculate. * @param radix The radix in which the number should be presented. * * @return G accurate to precision digits, in base radix. * * @exception NumberFormatException If the radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @since 1.11.0 */ public static Apfloat catalan(long precision, int radix) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { if (precision <= 0) { throw new IllegalArgumentException("Precision " + precision + " is not positive"); } else if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate C to infinite precision"); } long workingPrecision = ApfloatHelper.extendPrecision(precision); Apfloat one = new Apfloat(1, workingPrecision, radix), two = new Apfloat(2, workingPrecision, radix), three = new Apfloat(3, workingPrecision, radix), four = new Apfloat(4, workingPrecision, radix); return zeta(two, one.divide(four)).subtract(zeta(two, three.divide(four))).divide(new Apint(16, radix)).precision(precision); } /** * Calculates the Glaisher‐Kinkelin constant, A. Uses the default radix.

* * @implNote * This implementation is slow. At the time of implementation no * efficient algorithm is known for the Glaisher‐Kinkelin constant. * * @param precision Number of digits of A to calculate. * * @return A accurate to precision digits, in the default radix. * * @exception NumberFormatException If the default radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @since 1.11.0 */ public static Apfloat glaisher(long precision) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return glaisher(precision, radix); } /** * Calculates the Glaisher‐Kinkelin constant, A. Uses the specified radix.

* * @implNote * This implementation is slow. At the time of implementation no * efficient algorithm is known for the Glaisher‐Kinkelin constant. * * @param precision Number of digits of A to calculate. * @param radix The radix in which the number should be presented. * * @return A accurate to precision digits, in base radix. * * @exception NumberFormatException If the radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @since 1.11.0 */ public static Apfloat glaisher(long precision, int radix) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { if (precision <= 0) { throw new IllegalArgumentException("Precision " + precision + " is not positive"); } else if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate A to infinite precision"); } // Calculated using A = exp(euler/12 - zeta'(2)/(2 pi^2)) (2 pi)^(1/12) // The tricky part is the derivative of the zeta function // See: An Efficient Algorithm for the Riemann Zeta Function (1995) by P. Borwein, http://www.cecm.sfu.ca/~pborwein/PAPERS/P155.pdf // d_k = n sum((n + i - 1)! 4^i / ((n - i)! (2i)!), i=0..k) // zeta'(2) = 1/d_n sum((-1)^(k+1) (d_n - d_k) (log(4) + 2 log(1 + k))/(1 + k)^2, k=0..n-1) // d_n - d_k = n sum((n + i - 1)! 4^i / ((n - i)! (2i)!), i=k+1..n) long workingPrecision = ApfloatHelper.extendPrecision(precision), n = (long) Math.ceil(workingPrecision * Math.log(radix) / Math.log(3 + Math.sqrt(8))); Apfloat two = new Apfloat(2, workingPrecision, radix), four = new Apfloat(4, workingPrecision, radix), log4 = log(four), pi = pi(workingPrecision, radix), d = pow(two, Util.multiplyExact(2, n) - 1), dnk = d, z = Apfloat.ZERO; for (long k = n - 1; k >= 0; k--) { Apfloat k1 = new Apfloat(k + 1, workingPrecision, radix), term = dnk.multiply(log4.add(two.multiply(log(k1)))).divide(k1.multiply(k1)); z = (k & 1) == 0 ? z.subtract(term): z.add(term); d = d.multiply(new Apint(2 * k + 2, radix)).multiply(new Apint(2 * k + 1, radix)).divide(four.multiply(new Apint(n + k, radix)).multiply(new Apint(n - k, radix))); dnk = dnk.add(d); } z = z.divide(dnk); return exp(euler(workingPrecision, radix).divide(new Apint(12, radix)).subtract(z.divide(two.multiply(pi).multiply(pi)))).multiply(root(two.multiply(pi), 12)).precision(precision); } /** * Calculates Khinchin's constant, K.Uses the default radix.

* * @implNote * This implementation is slow. At the time of implementation no * efficient algorithm is known for Khinchin's constant. * * @param precision Number of digits of K to calculate. * * @return K accurate to precision digits, in the default radix. * * @exception NumberFormatException If the default radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @since 1.11.0 */ public static Apfloat khinchin(long precision) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return khinchin(precision, radix); } /** * Calculates Khinchin's constant, K. Uses the specified radix.

* * @implNote * This implementation is slow. At the time of implementation no * efficient algorithm is known for Khinchin's constant. * * @param precision Number of digits of K to calculate. * @param radix The radix in which the number should be presented. * * @return K accurate to precision digits, in base radix. * * @exception NumberFormatException If the radix is not valid. * @exception IllegalArgumentException In case the precision is invalid. * * @since 1.11.0 */ public static Apfloat khinchin(long precision, int radix) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { if (precision <= 0) { throw new IllegalArgumentException("Precision " + precision + " is not positive"); } else if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate K to infinite precision"); } // log(K) = 1/log(2) sum((zeta(2n) - 1) / n sum((-1)^k / k, k=1..2n-1), n=1..infinity) // zeta(2n) = (-1)^(n+1) B_2n (2 pi)^2n / (2 (2n)!) long workingPrecision = ApfloatHelper.extendPrecision(precision); Apint one = Apfloat.ONES[radix], two = new Apint(2, radix); Apfloat twopi2 = pow(pi(workingPrecision, radix).multiply(two), 2), f = new Aprational(one, two), s = Apfloat.ZERO; Iterator bernoullis2 = AprationalMath.bernoullis2Small(radix); for (long n = 1; ; n++) { f = f.multiply(twopi2).divide(new Apint(Util.multiplyExact(2, n) - 1, radix).multiply(new Apint(2 * n, radix))); Apfloat z = abs(bernoullis2.next()).multiply(f).subtract(one); if (z.scale() < -precision) { break; } Apfloat a = Apfloat.ZERO; for (long k = 1; k < 2 * n; k++) { a = a.add(((k & 1) == 1 ? one : one.negate()).divide(new Apfloat(k, workingPrecision, radix))); } s = s.add(z.divide(new Apfloat(n, workingPrecision, radix)).multiply(a)); } return exp(s.divide(log(new Apfloat(2, workingPrecision, radix)))).precision(precision); } /** * Gamma function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the gamma function. * * @param x The argument. * * @return Γ(x) * * @throws ArithmeticException If x is a nonpositive integer. * * @since 1.9.0 */ public static Apfloat gamma(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.gamma(x).real(); } /** * Incomplete gamma function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the gamma function. * * @param a The first argument. * @param x The second argument. * * @return Γ(a, x) * * @throws ArithmeticException If a is not a positive integer and x is nonpositive. * * @since 1.10.0 */ public static Apfloat gamma(Apfloat a, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() < 0 && !(a.signum() > 0 && a.isInteger())) { // For a real result, in the case x < 0, a must be a positive integer throw new ArithmeticException("Non-real result"); } return ApcomplexMath.gamma(a, x).real(); } /** * Generalized incomplete gamma function.

* * This function is defined as: Γ(a, x0, x1) = Γ(a, x0) - Γ(a, x1)

* * The lower gamma function can be calculated with: γ(a, x) = Γ(a, 0, x)

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the gamma function. * * @param a The first argument. * @param x0 The second argument. * @param x1 The third argument. * * @return Γ(a, x0, x1) * * @throws ArithmeticException If a is not a positive integer and either x0 or x1 is nonpositive. * * @since 1.10.0 */ public static Apfloat gamma(Apfloat a, Apfloat x0, Apfloat x1) throws ArithmeticException, ApfloatRuntimeException { if ((x0.signum() < 0 || x1.signum() < 0) && !(a.signum() > 0 && a.isInteger())) { // For a real result, in the case x < 0, a must be a positive integer throw new ArithmeticException("Non-real result"); } return ApcomplexMath.gamma(a, x0, x1).real(); } /** * Logarithm of the gamma function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the gamma function. * * @param x The argument. * * @return logΓ(x) * * @throws ArithmeticException If x is nonpositive. * * @since 1.11.0 */ public static Apfloat logGamma(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() < 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.logGamma(x).real(); } /** * Digamma function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the digamma function. * * @param x The argument. * * @return ψ(x) * * @throws ArithmeticException If x is a nonpositive integer. * * @since 1.11.0 */ public static Apfloat digamma(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.digamma(x).real(); } /** * Polygamma function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the polygamma function. * * @param n The order. * @param x The argument. * * @return ψ(n)(x) * * @throws ArithmeticException If n is negative or x is a nonpositive integer. * * @since 1.13.0 */ public static Apfloat polygamma(long n, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.polygamma(n, x).real(); } /** * Beta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the beta function. * * @param a The first argument. * @param b The second argument. * * @return B(a, b) * * @throws ArithmeticException If a or b is a nonpositive integer but a + b is not. Also if both a and b are nonpositive integers. * * @since 1.13.0 */ public static Apfloat beta(Apfloat a, Apfloat b) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.beta(a, b).real(); } /** * Incomplete beta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The first argument. * @param a The second argument. * @param b The third argument. * * @return Bx(a, b) * * @throws ArithmeticException If a is a nonpositive integer or x is zero and a is nonpositive or x is negative and a is not an integer. Also if x > 1 and the result is not a polynomial. * * @since 1.13.0 */ public static Apfloat beta(Apfloat x, Apfloat a, Apfloat b) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0 && a.signum() < 0 && !a.isInteger() || x.signum() < 0 && !a.isInteger()) { throw new ArithmeticException("Result would be complex"); } Apint one = Apint.ONES[x.radix()]; checkHypergeometric2F1(a, one.subtract(b), x); return ApcomplexMath.beta(x, a, b).real(); } /** * Generalized incomplete beta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x1 The first argument. * @param x2 The second argument. * @param a The third argument. * @param b The fourth argument. * * @return B(x1, x2)(a, b) * * @throws ArithmeticException If a is a nonpositive integer or x1 or x2 is zero and a is nonpositive or x1 or x2 is negative and a is not an integer. Also if x1 > 1 or x2 > 1 and the result is not a polynomial. * * @since 1.13.0 */ public static Apfloat beta(Apfloat x1, Apfloat x2, Apfloat a, Apfloat b) throws ArithmeticException, ApfloatRuntimeException { if ((x1.signum() == 0 || x2.signum() == 0) && a.signum() < 0 && !a.isInteger() || (x1.signum() < 0 || x2.signum() < 0) && !a.isInteger()) { throw new ArithmeticException("Result would be complex"); } Apint one = Apint.ONES[x1.radix()]; checkHypergeometric2F1(a, one.subtract(b), x1); checkHypergeometric2F1(a, one.subtract(b), x2); return ApcomplexMath.beta(x1, x2, a, b).real(); } /** * Pochhammer symbol.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the pochhammer symbol. * * @param x The first argument. * @param n The second argument. * * @return (x)n * * @throws ArithmeticException If x + n is a nonpositive integer but x is not. * * @since 1.13.0 */ public static Apfloat pochhammer(Apfloat x, Apfloat n) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.pochhammer(x, n).real(); } /** * Binomial coefficient. Calculated using the {@link #gamma(Apfloat)} function. * * @param n The first argument. * @param k The second argument. * * @return * * ( * * n * k * * ) * * * * @throws ArithmeticException If n is a negative integer and k is noninteger. * * @since 1.11.0 */ public static Apfloat binomial(Apfloat n, Apfloat k) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.binomial(n, k).real(); } /** * Riemann zeta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few hundred digits. At the time of * implementation no generic fast algorithm is known for the zeta function. * * @param s The argument. * * @return ζ(s) * * @throws ArithmeticException If s is 1. * * @since 1.11.0 */ public static Apfloat zeta(Apfloat s) throws ArithmeticException, ApfloatRuntimeException { return ZetaHelper.zeta(s).real(); } /** * Hurwitz zeta function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few hundred digits. At the time of * implementation no generic fast algorithm is known for the zeta function. * * @param s The first argument. * @param a The second argument. * * @return ζ(s, a) * * @throws ArithmeticException If s is 1 or if a is a nonpositive integer or if s is not an integer and a is nonpositive. * * @since 1.11.0 */ public static Apfloat zeta(Apfloat s, Apfloat a) throws ArithmeticException, ApfloatRuntimeException { if (!s.isInteger() && a.signum() < 0) { throw new ArithmeticException("Result would be complex"); } return HurwitzZetaHelper.zeta(s, a).real(); } /** * Confluent hypergeometric function 0F1.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param x The second argument. * * @return 0F1(; a; x) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public static Apfloat hypergeometric0F1(Apfloat a, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.hypergeometric0F1(a, x).real(); } /** * Regularized confluent hypergeometric function 01.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param x The second argument. * * @return 01(; a; x) * * @since 1.13.0 */ public static Apfloat hypergeometric0F1Regularized(Apfloat a, Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.hypergeometric0F1Regularized(a, x).real(); } /** * Kummer confluent hypergeometric function 1F1. * Also known as the confluent hypergeometric function of the first kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param x The third argument. * * @return 1F1(a; b; x) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public static Apfloat hypergeometric1F1(Apfloat a, Apfloat b, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.hypergeometric1F1(a, b, x).real(); } /** * Regularized Kummer confluent hypergeometric function 11. * Also known as the regularized confluent hypergeometric function of the first kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param x The third argument. * * @return 11(a; b; x) * * @since 1.13.0 */ public static Apfloat hypergeometric1F1Regularized(Apfloat a, Apfloat b, Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.hypergeometric1F1Regularized(a, b, x).real(); } /** * Hypergeometric function 2F1. * Also known as the Gaussian or ordinary hypergeometric function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param c The third argument. * @param x The fourth argument. * * @return 2F1(a, b; c; x) * * @throws ArithmeticException If the function value is not finite or real. * * @since 1.11.0 */ public static Apfloat hypergeometric2F1(Apfloat a, Apfloat b, Apfloat c, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { checkHypergeometric2F1(a, b, x); return ApcomplexMath.hypergeometric2F1(a, b, c, x).real(); } private static void checkHypergeometric2F1(Apfloat a, Apfloat b, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { // With real a, b and c the result is real if z <= 1 except if it's a polynomial, in which case it's always real (nb. additional checks might throw an exception later) Apint one = Apint.ONES[x.radix()]; if (x.compareTo(one) > 0 && HypergeometricHelper.maxNonPositiveInteger(a, b) == null) { throw new ArithmeticException("Result would be complex"); } } /** * Regularized hypergeometric function 21. * Also known as the regularized Gaussian or ordinary hypergeometric function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param c The third argument. * @param x The fourth argument. * * @return 21(a, b; c; x) * * @since 1.13.0 */ public static Apfloat hypergeometric2F1Regularized(Apfloat a, Apfloat b, Apfloat c, Apfloat x) throws ApfloatRuntimeException { // With real a, b and c the result is real if z <= 1 except if it's a polynomial, in which case it's always real (nb. additional checks might throw an exception later) Apint one = Apint.ONES[x.radix()]; if (x.compareTo(one) > 0 && HypergeometricHelper.maxNonPositiveInteger(a, b) == null) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.hypergeometric2F1Regularized(a, b, c, x).real(); } /** * Tricomi's confluent hypergeometric function U. * Also known as the confluent hypergeometric function of the second kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param x The third argument. * * @return U(a, b, x) * * @throws ArithmeticException If the result would be complex or not finite. * * @since 1.13.0 */ public static Apfloat hypergeometricU(Apfloat a, Apfloat b, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() >= 0 || a.isInteger() && a.signum() <= 0 || a.isInteger() && b.isInteger() && b.compareTo(a) > 0) { return ApcomplexMath.hypergeometricU(a, b, x).real(); } throw new ArithmeticException("Result would be complex"); } /** * Error function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return erf(x) * * @since 1.13.0 */ public static Apfloat erf(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.erf(x).real(); } static Apfloat erfFixedPrecision(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.erfFixedPrecision(x).real(); } /** * Complementary error function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return erfc(x) * * @since 1.13.0 */ public static Apfloat erfc(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.erfc(x).real(); } static Apfloat erfcFixedPrecision(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.erfcFixedPrecision(x).real(); } /** * Imaginary error function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return erfi(x) * * @since 1.13.0 */ public static Apfloat erfi(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.erfi(x).real(); } static Apfloat erfiFixedPrecision(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.erfiFixedPrecision(x).real(); } /** * Inverse error function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return erf−1(x) * * @throws ArithmeticException If |x| is ≥ 1. * * @since 1.13.0 */ public static Apfloat inverseErf(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0) { return x; } if (x.signum() < 0) { return inverseErf(x.negate()).negate(); } int radix = x.radix(); Apint one = Apint.ONES[radix]; if (x.compareTo(one) >= 0) { throw new ArithmeticException("Result would be complex"); } long targetPrecision = x.precision(); Apint two = new Apint(2, radix); Apfloat pi = pi(targetPrecision, radix), sqrtPi = sqrt(pi), initialGuess; long doublePrecision = ApfloatHelper.getDoublePrecision(radix); if (x.compareTo(new Apfloat(0.8, Apfloat.DEFAULT, radix)) >= 0) { Apfloat x1 = x.subtract(one).precision(doublePrecision), log2pix = log(two.divide(pi.multiply(pow(x1, 2)))); initialGuess = sqrt(log2pix.subtract(log(log2pix)).divide(two)); } else { long precision = doublePrecision; Apint zero = Apfloat.ZEROS[radix]; Apfloat xp = x.multiply(sqrtPi.precision(precision)).divide(two), xp2 = xp.multiply(xp), s = zero, t; List c = new ArrayList<>(); int k = 0; do { Apfloat ck = (k == 0 ? one : zero); for (int m = 0; m < k; m++) { Apfloat m121 = new Apfloat((m + 1) * (2 * m + 1), precision, radix); ck = ck.add(c.get(m).multiply(c.get(k - 1 - m)).divide(m121)); } c.add(ck); Apint k21 = new Apint(2 * k + 1, radix); t = c.get(k).multiply(xp).divide(k21); xp = xp.multiply(xp2); s = s.add(t); k++; } while (s.signum() == 0 || s.scale() - t.scale() <= precision); initialGuess = s; } initialGuess = ApfloatHelper.ensurePrecision(initialGuess, doublePrecision); Function f = ApfloatMath::erf, fp = y -> two.multiply(exp(pow(y, 2).negate())).divide(sqrtPi); Apfloat result = RootFinder.findRoot(f, (y, fy) -> fp.apply(y), x, initialGuess, targetPrecision); long precisionLoss = x.equalDigits(one); return ApfloatHelper.reducePrecision(result, precisionLoss); } /** * Inverse complementary error function.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return erfc−1(x) * * @throws ArithmeticException If x is ≤ 0 or ≥ 2. * * @since 1.13.0 */ public static Apfloat inverseErfc(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apint one = Apint.ONES[x.radix()]; return inverseErf(one.subtract(x)); } /** * Fresnel integral S.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return S(x) * * @since 1.13.0 */ public static Apfloat fresnelS(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.fresnelS(x).real(); } /** * Fresnel integral C.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return C(x) * * @since 1.13.0 */ public static Apfloat fresnelC(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.fresnelC(x).real(); } /** * Exponential integral E.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param x The second argument. * * @return Eν(x) * * @throws ArithmeticException If ν is < 0 and x is zero or ν is nonzero and x is negative. * * @since 1.13.0 */ public static Apfloat expIntegralE(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (ν.signum() != 0 && x.signum() < 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.expIntegralE(ν, x).real(); } /** * Exponential integral Ei.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Ei(x) * * @throws ArithmeticException If x is zero. * * @since 1.13.0 */ public static Apfloat expIntegralEi(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.expIntegralEi(x).real(); } /** * Logarithmic integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return li(x) * * @throws ArithmeticException If x is nonpositive or 1. * * @since 1.13.0 */ public static Apfloat logIntegral(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() < 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.logIntegral(x).real(); } /** * Sine integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Si(x) * * @since 1.13.0 */ public static Apfloat sinIntegral(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.sinIntegral(x).real(); } /** * Cosine integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Ci(x) * * @throws ArithmeticException If x is nonpositive. * * @since 1.13.0 */ public static Apfloat cosIntegral(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() < 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.cosIntegral(x).real(); } /** * Hyperbolic sine integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Shi(x) * * @since 1.13.0 */ public static Apfloat sinhIntegral(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.sinhIntegral(x).real(); } /** * Hyperbolic cosine integral.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Chi(x) * * @throws ArithmeticException If x is nonpositive. * * @since 1.13.0 */ public static Apfloat coshIntegral(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() < 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.coshIntegral(x).real(); } /** * Airy function Ai.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Ai(x) * * @throws InfiniteExpansionException If x is zero. * * @since 1.13.0 */ public static Apfloat airyAi(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.airyAi(x).real(); } static Apfloat airyAi(Apfloat x, long precision) throws ApfloatRuntimeException { return ApcomplexMath.airyAi(x, precision).real(); } /** * Derivative of the Airy function Ai.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Ai′(x) * * @throws InfiniteExpansionException If x is zero. * * @since 1.13.0 */ public static Apfloat airyAiPrime(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.airyAiPrime(x).real(); } static Apfloat airyAiPrime(Apfloat x, long precision) throws ApfloatRuntimeException { return ApcomplexMath.airyAiPrime(x, precision).real(); } /** * Airy function Bi.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Bi(x) * * @throws InfiniteExpansionException If x is zero. * * @since 1.13.0 */ public static Apfloat airyBi(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.airyBi(x).real(); } static Apfloat airyBi(Apfloat x, long precision) throws ApfloatRuntimeException { return ApcomplexMath.airyBi(x, precision).real(); } /** * Derivative of the Airy function Bi.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Bi′(x) * * @throws InfiniteExpansionException If x is zero. * * @since 1.13.0 */ public static Apfloat airyBiPrime(Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.airyBiPrime(x).real(); } static Apfloat airyBiPrime(Apfloat x, long precision) throws ApfloatRuntimeException { return ApcomplexMath.airyBiPrime(x, precision).real(); } /** * Bessel function of the first kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The order. * @param x The argument. * * @return Jν(x) * * @throws ArithmeticException If ν is < 0 and ν is not an integer and x is zero. Also if ν is not an integer and x is < 0. * * @since 1.13.0 */ public static Apfloat besselJ(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() < 0 && !ν.isInteger()) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.besselJ(ν, x).real(); } /** * Modified Bessel function of the first kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The order. * @param x The argument. * * @return Iν(x) * * @throws ArithmeticException If ν is < 0 and ν is not an integer and x is zero. Also if ν is not an integer and x is < 0. * * @since 1.13.0 */ public static Apfloat besselI(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() < 0 && !ν.isInteger()) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.besselI(ν, x).real(); } /** * Bessel function of the second kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The order. * @param x The argument. * * @return Yν(x) * * @throws ArithmeticException If x is ≤ 0. * * @since 1.13.0 */ public static Apfloat besselY(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() < 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.besselY(ν, x).real(); } /** * Modified Bessel function of the second kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The order. * @param x The argument. * * @return Kν(x) * * @throws ArithmeticException If x is ≤ 0. * * @since 1.13.0 */ public static Apfloat besselK(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() < 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.besselK(ν, x).real(); } /** * Complete elliptic integral of the first kind.

* * Note that this function uses the definition: * * * * * K * ( * x * ) * * * * * * 0 * * π * 2 * * * * * 1 * * * 1 * - * * x * * * * sin * 2 * * ( * t * ) * * * * * * * * * t * * * * * * * * @param x The argument. * * @return K(x) * * @throws InfiniteExpansionException If x is zero. * @throws ArithmeticException If x is ≥ 1. * * @since 1.13.0 */ public static Apfloat ellipticK(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return ellipticK(x, x.precision()); } static Apfloat ellipticK(Apfloat x, long precision) throws ApfloatRuntimeException { if (x.compareTo(Apfloat.ONES[x.radix()]) > 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.ellipticK(x, precision).real(); } /** * Complete elliptic integral of the second kind.

* * Note that this function uses the definition: * * * * * E * ( * x * ) * * * * * * 0 * * π * 2 * * * * * * 1 * - * * x * * * * sin * 2 * * ( * t * ) * * * * * * * * t * * * * * * * * @param x The argument. * * @return E(x) * * @throws InfiniteExpansionException If x is zero. * @throws ArithmeticException If x is > 1. * * @since 1.13.0 */ public static Apfloat ellipticE(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return ellipticE(x, x.precision()); } static Apfloat ellipticE(Apfloat x, long precision) throws ArithmeticException, ApfloatRuntimeException { if (x.compareTo(Apfloat.ONES[x.radix()]) > 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.ellipticE(x, precision).real(); } /** * Hermite function. For integer values of ν gives the Hermite polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param x The second argument. * * @return Hν(x) * * @since 1.14.0 */ public static Apfloat hermiteH(Apfloat ν, Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.hermiteH(ν, x).real(); } /** * Laguerre function. For integer values of ν gives the Laguerre polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param x The second argument. * * @return Lν(x) * * @since 1.14.0 */ public static Apfloat laguerreL(Apfloat ν, Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.laguerreL(ν, x).real(); } /** * Generalized Laguerre function. For integer values of ν gives the generalized Laguerre polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param λ The second argument. * @param x The third argument. * * @return Lνλ(x) * * @since 1.14.0 */ public static Apfloat laguerreL(Apfloat ν, Apfloat λ, Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.laguerreL(ν, λ, x).real(); } /** * Legendre function. For integer values of ν gives the Legendre polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param x The second argument. * * @return Pν(x) * * @throws ArithmeticException If ν is not an integer and x ≤ -1. * * @since 1.14.0 */ public static Apfloat legendreP(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { if (!ν.isInteger()) { Apfloat minusOne = Apint.ONES[ν.radix()].negate(); if (x.compareTo(minusOne) < 0) { throw new ArithmeticException("Result would be complex"); } } return ApcomplexMath.legendreP(ν, x).real(); } /** * Associated Legendre function of the first kind. Gives Legendre functions of type 2.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param μ The second argument. * @param x The third argument. * * @return Pνμ(x) * * @throws ArithmeticException If x is ≤ -1 or ≥ 1 and ν or μ is not an integer or μ is not even or μ is not positive and ν < μ. * * @since 1.14.0 */ public static Apfloat legendreP(Apfloat ν, Apfloat μ, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apfloat one = Apint.ONES[ν.radix()]; if (x.compareTo(one.negate()) < 0 || x.compareTo(one) > 0) { boolean isReal = (isEven(μ) && (ν.isInteger() || x.signum() > 0) || ν.isInteger() && μ.isInteger() && μ.signum() > 0 && ν.compareTo(μ) < 0 && ν.compareTo(μ.negate()) >= 0); if (!isReal) { throw new ArithmeticException("Result would be complex"); } } return ApcomplexMath.legendreP(ν, μ, x).real(); } private static boolean isEven(Apfloat x) { return (x.isInteger() && x.truncate().mod(new Apint(2, x.radix())).signum() == 0); } /** * Legendre function of the second kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param x The second argument. * * @return Qν(x) * * @throws ArithmeticException If x is ≥ 1 or ≤ -1. * * @since 1.14.0 */ public static Apfloat legendreQ(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apfloat one = Apint.ONES[ν.radix()]; if (x.compareTo(one.negate()) < 0 || x.compareTo(one) > 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.legendreQ(ν, x).real(); } /** * Associated Legendre function of the second kind. Gives Legendre functions of type 2.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param μ The second argument. * @param x The third argument. * * @return Qνμ(x) * * @throws ArithmeticException If x is ≥ 1 or ≤ -1. * * @since 1.14.0 */ public static Apfloat legendreQ(Apfloat ν, Apfloat μ, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apfloat one = Apint.ONES[ν.radix()]; if (x.compareTo(one.negate()) < 0 || x.compareTo(one) > 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.legendreQ(ν, μ, x).real(); } /** * Chebyshev function of the first kind. For integer values of ν gives the Chebyshev polynomial of the first kind.

* * @param ν The first argument. * @param x The second argument. * * @return Tν(x) * * @throws ArithmeticException If x is < -1 and ν is not an integer. * * @since 1.14.0 */ public static Apfloat chebyshevT(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { checkMinusOneNonInteger(ν, x); return ApcomplexMath.chebyshevT(ν, x).real(); } private static void checkMinusOneNonInteger(Apfloat ν, Apfloat x) { Apfloat one = Apint.ONES[ν.radix()]; if (x.compareTo(one.negate()) < 0 && !ν.isInteger()) { throw new ArithmeticException("Result would be complex"); } } /** * Chebyshev function of the second kind. For integer values of ν gives the Chebyshev polynomial of the second kind.

* * @param ν The first argument. * @param x The second argument. * * @return Uν(x) * * @throws ArithmeticException If x is ≤ -1 and ν is not an integer. * * @since 1.14.0 */ public static Apfloat chebyshevU(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { checkMinusOneNonInteger(ν, x); return ApcomplexMath.chebyshevU(ν, x).real(); } /** * Renormalized Gegenbauer function.

* * @param ν The first argument. * @param x The second argument. * * @return Cν(0)(x) * * @throws ArithmeticException If ν is zero. Also if x is < -1 and ν is not an integer. * * @since 1.14.0 */ public static Apfloat gegenbauerC(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { checkMinusOneNonInteger(ν, x); return ApcomplexMath.gegenbauerC(ν, x).real(); } /** * Gegenbauer function. For nonnegative integer values of ν gives the Gegenbauer polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param λ The second argument. * @param x The third argument. * * @return Cνλ(x) * * @throws ArithmeticException If x is < -1 and ν is not an integer. Also if x is -1 and λ is > 1/2. Also if x is -1 and λ is 1/2 and ν is not an integer. * * @since 1.14.0 */ public static Apfloat gegenbauerC(Apfloat ν, Apfloat λ, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { checkMinusOneNonInteger(ν, x); return ApcomplexMath.gegenbauerC(ν, λ, x).real(); } /** * Jacobi function. For nonnegative integer values of ν gives the Jacobi polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param a The second argument. * @param b The third argument. * @param x The fourth argument. * * @return Pν(a,b)(x) * * @throws ArithmeticException If ν is not a positive integer and either x is -1 and b is > 0 or x is < -1. Also if ν + a is a negative integer and ν is not an integer. * * @since 1.14.0 */ public static Apfloat jacobiP(Apfloat ν, Apfloat a, Apfloat b, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { checkMinusOneNonInteger(ν, x); return ApcomplexMath.jacobiP(ν, a, b, x).real(); } /** * Fibonacci function. For nonnegative integer values of ν gives the Fibonacci polynomial.

* * @param ν The first argument. * @param x The second argument. * * @return Fν(x) * * @since 1.14.0 */ public static Apfloat fibonacci(Apfloat ν, Apfloat x) throws ApfloatRuntimeException { return ApcomplexMath.fibonacci(ν, x).real(); } /** * Euler polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param n The first argument. * @param x The second argument. * * @return En(x) * * @throws IllegalArgumentException If n < 0. * * @since 1.14.0 */ public static Apfloat eulerE(long n, Apfloat x) throws IllegalArgumentException, ApfloatRuntimeException { return ApcomplexMath.eulerE(n, x).real(); } static Apfloat eulerE(long n, Apfloat x, long precision) throws IllegalArgumentException, ApfloatRuntimeException { return ApcomplexMath.eulerE(n, x, precision).real(); } /** * Bernoulli polynomial.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param n The first argument. * @param x The second argument. * * @return Bn(x) * * @throws IllegalArgumentException If n < 0. * * @since 1.14.0 */ public static Apfloat bernoulliB(long n, Apfloat x) throws IllegalArgumentException, ApfloatRuntimeException { return ApcomplexMath.bernoulliB(n, x).real(); } static Apfloat bernoulliB(long n, Apfloat x, long precision) throws IllegalArgumentException, ApfloatRuntimeException { return ApcomplexMath.bernoulliB(n, x, precision).real(); } /** * Harmonic number.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The argument. * * @return Hx * * @throws ArithmeticException If x is a negative integer. * * @since 1.14.0 */ public static Apfloat harmonicNumber(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return ApcomplexMath.harmonicNumber(x).real(); } /** * Generalized harmonic number.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param x The first argument. * @param r The second argument. * * @return Hx(r) * * @throws ArithmeticException If x is a negative integer, unless r is a nonpositive integer. Also if x is < -1 and r is not an integer. * * @since 1.14.0 */ public static Apfloat harmonicNumber(Apfloat x, Apfloat r) throws ArithmeticException, ApfloatRuntimeException { checkMinusOneNonInteger(r, x); return ApcomplexMath.harmonicNumber(x, r).real(); } /** * Polylogarithm.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param ν The first argument. * @param x The second argument. * * @return Liν(x) * * @throws ArithmeticException If ν is ≤ 1 and x is 1 or if x is > 1. * * @since 1.14.0 */ public static Apfloat polylog(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apfloat one = Apint.ONES[ν.radix()]; if (x.compareTo(one) > 0) { throw new ArithmeticException("Result would be complex"); } return ApcomplexMath.polylog(ν, x).real(); } /** * Logistic sigmoid. * * @param x The argument. * * @return σ(x) * * @since 1.14.0 */ public static Apfloat logisticSigmoid(Apfloat x) throws ApfloatRuntimeException { int radix = x.radix(); Apint one = Apint.ONES[radix]; if (x.isZero()) { Apint two = new Apint(2, radix); return new Aprational(one, two); } long precision = x.precision(); Apint minusOne = new Apint(-1, radix); Apfloat e = (x.scale() < -precision ? one : exp(x.negate())); return one.precision(precision).divide(one.precision(ApfloatHelper.extendPrecision(precision, e.equalDigits(minusOne))).add(e)); } /** * Generates a random number. Uses the default radix. * Returned values are chosen pseudorandomly with (approximately) * uniform distribution from the range 0 ≤ x < 1. * The generated random numbers may have leading zeros and may thus not * always have exactly the requested number of significant digits. * The precision of the numbers is the requested number of digits minus * the number of leading zeros. Trailing zeros do not affect the precision. * * @param digits Maximum number of digits in the number. * * @return A random number, uniformly distributed between 0 ≤ x < 1. * * @exception NumberFormatException If the default radix is not valid. * @exception IllegalArgumentException In case the number of specified digits is invalid. * * @since 1.9.0 */ public static Apfloat random(long digits) { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return random(digits, radix); } /** * Generates a random number. * Returned values are chosen pseudorandomly with (approximately) * uniform distribution from the range 0 ≤ x < 1. * The generated random numbers may have leading zeros and may thus not * always have exactly the requested number of significant digits. * The precision of the numbers is the requested number of digits minus * the number of leading zeros. Trailing zeros do not affect the precision. * * @param digits Maximum number of digits in the number. * @param radix The radix in which the number should be generated. * * @return A random number, uniformly distributed between 0 ≤ x < 1, in base radix. * * @exception NumberFormatException If the radix is not valid. * @exception IllegalArgumentException In case the number of specified digits is invalid. * * @since 1.9.0 */ public static Apfloat random(long digits, int radix) { Apfloat random = ApintMath.random(digits, radix); if (random.signum() != 0) { random = random.precision(random.scale()); } return scale(random, -digits); } /** * Generates a random, Gaussian ("normally") distributed * number value with mean 0 and standard deviation 1. * Uses the default radix. * * @param digits Maximum number of digits in the number. * * @return A random number, Gaussian ("normally") distributed with mean 0 and standard deviation 1. * * @exception NumberFormatException If the default radix is not valid. * @exception IllegalArgumentException In case the number of specified digits is invalid. * * @since 1.9.0 */ public static Apfloat randomGaussian(long digits) { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return randomGaussian(digits, radix); } /** * Generates a random, Gaussian ("normally") distributed * number value with mean 0 and standard deviation 1. * Uses the default radix. * * @param digits Maximum number of digits in the number. * @param radix The radix in which the number should be generated. * * @return A random number, Gaussian ("normally") distributed with mean 0 and standard deviation 1. * * @exception NumberFormatException If the radix is not valid. * @exception IllegalArgumentException In case the number of specified digits is invalid. * * @since 1.9.0 */ public static Apfloat randomGaussian(long digits, int radix) { // Get synchronization lock - getting the lock is also synchronized Object radixKey = getRadixKey(ApfloatMath.radixGaussianKeys, radix); synchronized (radixKey) { Apfloat nextGaussian = ApfloatMath.nextGaussian.remove(radix); Long nextGaussianPrecision = ApfloatMath.nextGaussianPrecision.remove(radix); if (nextGaussian != null && nextGaussianPrecision == digits) { return nextGaussian; } else { Apint one = new Apint(1, radix), two = new Apint(2, radix); Apfloat v1, v2, s; do { v1 = two.multiply(random(digits, radix)).subtract(one).precision(digits); v2 = two.multiply(random(digits, radix)).subtract(one).precision(digits); s = multiplyAdd(v1, v1, v2, v2); } while (s.compareTo(one) >= 1 || s.signum() == 0); Apfloat multiplier = sqrt(two.negate().multiply(log(s)).divide(s)); nextGaussian = v2.multiply(multiplier); ApfloatMath.nextGaussian.put(radix, nextGaussian); ApfloatMath.nextGaussianPrecision.put(radix, digits); return v1.multiply(multiplier); } } } /** * Generates the first n terms in the continued fraction representation of x.

* * Note that the result length might be less than n, depending on the input value and precision. * The last terms could be incorrect due to accumulating round-off errors. * * @param x The number whose continued fraction terms should be generated. * @param n The maximum number of terms to generate. * * @return The continued fraction. * * @exception IllegalArgumentException If n is less than one. * * @since 1.12.0 */ public static Apint[] continuedFraction(Apfloat x, int n) { if (n <= 0) { throw new IllegalArgumentException("Maximum number of terms is not positive"); } return Util.stream(ContinuedFractionHelper.continuedFraction(x)).limit(n).toArray(Apint[]::new); } /** * Generates the first n convergents corresponding to the continued fraction of x.

* * Note that the result length might be less than n, depending on the input value and precision. * The last convergents could be incorrect due to accumulating round-off errors. * * @param x The number whose continued fraction convergents should be generated. * @param n The maximum number of convergents to generate. * * @return The convergents. * * @exception IllegalArgumentException If n is less than one. * * @since 1.12.0 */ public static Aprational[] convergents(Apfloat x, int n) { if (n <= 0) { throw new IllegalArgumentException("Maximum number of convergents is not positive"); } Iterator continuedFraction = ContinuedFractionHelper.continuedFraction(x); return Util.stream(ContinuedFractionHelper.convergents(continuedFraction, x.radix())).limit(n).toArray(Aprational[]::new); } /** * Returns the greater of the two values. * * @param x An argument. * @param y Another argument. * * @return The greater of the two values. * * @since 1.9.0 */ public static Apfloat max(Apfloat x, Apfloat y) { return (x.compareTo(y) > 0 ? x : y); } /** * Returns the smaller of the two values. * * @param x An argument. * @param y Another argument. * * @return The smaller of the two values. * * @since 1.9.0 */ public static Apfloat min(Apfloat x, Apfloat y) { return (x.compareTo(y) < 0 ? x : y); } /** * Returns the number adjacent to the first argument in the direction of * the second argument, considering the scale and precision of the first * argument. If the precision of the first argument is infinite, the * first argument is returned. If both arguments compare as equal then * the first argument is returned. * * @param start The starting value. * @param direction Value indicating which of start's neighbors or start should be returned. * * @return The number adjacent to start in the direction of direction. * * @since 1.10.0 */ public static Apfloat nextAfter(Apfloat start, Apfloat direction) { return nextInDirection(start, direction.compareTo(start)); } /** * Returns the number adjacent to the argument in the direction of * positive infinity, considering the scale and precision of the * argument. If the precision of the argument is infinite, the * argument is returned. * * @param x The starting value. * * @return The adjacent value closer to positive infinity. * * @since 1.10.0 */ public static Apfloat nextUp(Apfloat x) { return nextInDirection(x, 1); } /** * Returns the number adjacent to the argument in the direction of * negative infinity, considering the scale and precision of the * argument. If the precision of the argument is infinite, the * argument is returned. * * @param x The starting value. * * @return The adjacent value closer to negative infinity. * * @since 1.10.0 */ public static Apfloat nextDown(Apfloat x) { return nextInDirection(x, -1); } /** * Returns the unit in the last place of the argument, considering the * scale and precision. This is same as the difference between the argument * and the value returned from {@link #nextUp(Apfloat)}. * If the precision of the argument is infinite, zero is returned.

* * For example, ulp of 1. is 1, ulp of 1.1 is 0.1 * and ulp of 1.001 is 0.001 (considering significant digits only). * * @param x The argument. * * @return The ulp of the argument. * * @since 1.10.0 */ public static Apfloat ulp(Apfloat x) { return ulp(x, 1); } private static Apfloat nextInDirection(Apfloat x, int direction) { return x.add(ulp(x, direction)); } private static Apfloat ulp(Apfloat x, int direction) { long scale = x.scale() - x.precision(); if (x.precision() == Apfloat.INFINITE || x.scale() < 0 && scale >= 0) // Detect overflow { return Apfloat.ZEROS[x.radix()]; } return scale(new Apfloat(direction, 1, x.radix()), scale); } // Extend the precision on last iteration private static Apfloat lastIterationExtendPrecision(int iterations, int precisingIteration, Apfloat x) throws ApfloatRuntimeException { return (iterations == 0 && precisingIteration != 0 ? ApfloatHelper.extendPrecision(x) : x); } // Get shared radix key for synchronizing getting and calculating something per radix private static Object getRadixKey(Map radixKeys, int radix) { Object value = new Object(); Object radixKey = radixKeys.putIfAbsent(radix, value); if (radixKey == null) { radixKey = value; } return radixKey; } static Apfloat factorial(long n, long precision) throws ArithmeticException, NumberFormatException, ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return factorial(n, precision, radix); } static Apfloat factorial(long n, long precision, int radix) throws ArithmeticException, NumberFormatException, ApfloatRuntimeException { if (n < 0) { throw new ArithmeticException("Factorial of negative number"); } else if (n < 2) { return new Apfloat(1, precision, radix); } long targetPrecision = precision; precision = ApfloatHelper.extendPrecision(precision); // Thanks to Peter Luschny for the improved algorithm. // The idea is to split the factorial to two parts: // a product of odd numbers, and a power of two. // This saves some operations, as squaring is more // efficient than multiplication, in the power of two. // For any n, factorial(n) = oddProduct(n) * factorial(m) * 2^m, // where m = n >>> 1, which gives the following algorithm. Apfloat oddProduct = new Apfloat(1, precision, radix), factorialProduct = oddProduct; long exponentOfTwo = 0; for (int i = 62 - Long.numberOfLeadingZeros(n); i >= 0; i--) { long m = n >>> i, k = m >>> 1; exponentOfTwo += k; oddProduct = oddProduct.multiply(oddProduct(k + 1, m, precision, radix)); factorialProduct = factorialProduct.multiply(oddProduct); } return factorialProduct.multiply(pow(new Apfloat(2, precision, radix), exponentOfTwo)).precision(targetPrecision); } private static Apfloat oddProduct(long n, long m, long precision, int radix) throws ApfloatRuntimeException { n = n | 1; // Round n up to the next odd number m = (m - 1) | 1; // Round m down to the next odd number if (n > m) { return new Apfloat(1, precision, radix); } else if (n == m) { return new Apfloat(n, precision, radix); } else { long k = (n + m) >>> 1; return oddProduct(n, k, precision, radix).multiply(oddProduct(k + 1, m, precision, radix)); } } static Apfloat doubleFactorial(long n, long precision) throws ArithmeticException, NumberFormatException, ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return doubleFactorial(n, precision, radix); } static Apfloat doubleFactorial(long n, long precision, int radix) throws ArithmeticException, NumberFormatException, ApfloatRuntimeException { if (n < 0) { throw new ArithmeticException("Double factorial of negative number"); } if ((n & 1) == 1) { return oddProduct(1, n, precision, radix); } long n2 = n >>> 1; return pow(new Apfloat(2, precision, radix), n2).multiply(factorial(n2, precision, radix)); } // Clean up static maps at shutdown, to allow garbage collecting temporary files static void cleanUp() { ApfloatMath.radixPi = SHUTDOWN_MAP; ApfloatMath.radixPiT = SHUTDOWN_MAP; ApfloatMath.radixPiQ = SHUTDOWN_MAP; ApfloatMath.radixPiP = SHUTDOWN_MAP; ApfloatMath.radixPiInverseRoot = SHUTDOWN_MAP; ApfloatMath.radixLog = SHUTDOWN_MAP; ApfloatMath.radixLogPi = SHUTDOWN_MAP; ApfloatMath.nextGaussian = SHUTDOWN_MAP; } // Map that always throws ApfloatRuntimeException, to be used after clean-up has been initiated private static final Map SHUTDOWN_MAP = new ShutdownMap<>(); // Synchronization keys for pi calculation private static ConcurrentMap radixPiKeys = new ConcurrentHashMap<>(); // Shared cached values related to pi for different radixes private static Map radixPi = new ConcurrentSoftHashMap<>(); private static Map radixPiCalculator = new Hashtable<>(); private static Map radixPiT = new ConcurrentSoftHashMap<>(); private static Map radixPiQ = new ConcurrentSoftHashMap<>(); private static Map radixPiP = new ConcurrentSoftHashMap<>(); private static Map radixPiInverseRoot = new ConcurrentSoftHashMap<>(); private static Map radixPiTerms = new Hashtable<>(); // Synchronization keys for logarithm calculation private static ConcurrentMap radixLogKeys = new ConcurrentHashMap<>(); // Shared cached values related to logarithm for different radixes private static Map radixLog = new ConcurrentHashMap<>(); private static Map radixLogPi = new ConcurrentHashMap<>(); // Synchronization keys for random Gaussian calculation private static ConcurrentMap radixGaussianKeys = new ConcurrentHashMap<>(); // Used by randomGaussian private static Map nextGaussian = new ConcurrentHashMap<>(); private static Map nextGaussianPrecision = new ConcurrentHashMap<>(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ApfloatRuntimeException.java000066400000000000000000000056621461767713300272260ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; /** * Exception indicating some unexpected error situation. * This exception can be thrown in different situations, for example: * *

    *
  • The result of an operation would have infinite size. For example, * new Apfloat(2).divide(new Apfloat(3)), in radix 10.
  • *
  • Overflow. If the exponent is too large to fit in a long, * the situation can't be handled. Also, there is no "infinity" apfloat * value that could be returned as the result.
  • *
  • Total loss of precision. For example, ApfloatMath.sin(new Apfloat(1e100)). * If the magnitude (100) is far greater than the precision (1) then * the value of the sin() function can't be determined * to any accuracy.
  • *
  • Some other internal limitation.
  • *
* * @version 1.1 * @author Mikko Tommila */ public class ApfloatRuntimeException extends RuntimeException { /** * Constructs a new apfloat runtime exception with an empty detail message. */ public ApfloatRuntimeException() { } /** * Constructs a new apfloat runtime exception with the specified detail message. * * @param message The detail message. */ public ApfloatRuntimeException(String message) { super(message); } /** * Constructs a new apfloat runtime exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public ApfloatRuntimeException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/Apint.java000066400000000000000000000471341461767713300234700ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.BigInteger; import java.io.PushbackReader; import java.io.Writer; import java.io.IOException; import java.util.Formatter; import static java.util.FormattableFlags.*; import java.util.FormatFlagsConversionMismatchException; import java.util.IllegalFormatPrecisionException; import org.apfloat.spi.ApfloatImpl; /** * Arbitrary precision integer class.

* * In addition to the constructors, it is possible to create an apint * from an apfloat or aprational via the methods that round these * numbers to an integer value: {@link Apfloat#floor() }, {@link Apfloat#ceil() }, * and {@link Apfloat#truncate() }. * * @see ApintMath * * @version 1.10.1 * @author Mikko Tommila */ public class Apint extends Aprational { /** * Default constructor. To be used only by subclasses that * overload all needed methods. */ protected Apint() { } // Package private constructor that skips validating that the provided value actually is an integer Apint(Apfloat value) { this.value = value; } /** * Constructs an apfloat from the specified string. * The default radix will be used.

* * @param value The string representing the number. * * @exception NumberFormatException In case the number is invalid. */ public Apint(String value) throws NumberFormatException, ApfloatRuntimeException { this.value = new Apfloat(ApfloatHelper.createApfloat(value, true)); } /** * Constructs an apfloat from the specified string and radix. * * @param value The string representing the number. * @param radix The radix of the number. * * @exception NumberFormatException In case the number is invalid. */ public Apint(String value, int radix) throws NumberFormatException, ApfloatRuntimeException { this.value = new Apfloat(ApfloatHelper.createApfloat(value, INFINITE, radix, true)); } /** * Constructs an apfloat from the specified long. * The default radix will be used. * * @param value The value of the number. * * @exception NumberFormatException In case the number is invalid. */ public Apint(long value) throws NumberFormatException, ApfloatRuntimeException { this.value = new Apfloat(ApfloatHelper.createApfloat(value)); } /** * Constructs an apfloat from the specified long * and radix. * * @param value The value of the number. * @param radix The radix of the number. * * @exception NumberFormatException In case the number is invalid. */ public Apint(long value, int radix) throws NumberFormatException, ApfloatRuntimeException { this.value = new Apfloat(ApfloatHelper.createApfloat(value, INFINITE, radix)); } /** * Reads an apint from a stream using the default radix. * * @param in The stream to read from * * @exception IOException If an I/O error occurs accessing the stream. * @exception NumberFormatException If the number is not valid. */ public Apint(PushbackReader in) throws IOException, NumberFormatException, ApfloatRuntimeException { this.value = new Apfloat(ApfloatHelper.createApfloat(in, INFINITE, true)); } /** * Reads an apint from a stream using the specified radix. * * @param in The stream to read from * @param radix The radix of the number. * * @exception IOException If an I/O error occurs accessing the stream. * @exception NumberFormatException If the number is not valid. */ public Apint(PushbackReader in, int radix) throws IOException, NumberFormatException, ApfloatRuntimeException { this.value = new Apfloat(ApfloatHelper.createApfloat(in, INFINITE, radix, true)); } /** * Constructs an apint from a BigInteger. The default radix is used. * * @param value The value of the number. * * @exception NumberFormatException If the default radix is not valid. */ public Apint(BigInteger value) throws NumberFormatException, ApfloatRuntimeException { this.value = new Apfloat(value); } /** * Constructs an apint from a BigInteger using the specified radix. * * @param value The value of the number. * @param radix The radix of the number. * * @exception NumberFormatException If the radix is not valid. */ public Apint(BigInteger value, int radix) throws NumberFormatException, ApfloatRuntimeException { this.value = new Apfloat(value, INFINITE, radix); } /** * Numerator of this aprational. * * @return this. */ @Override public Apint numerator() { return this; } /** * Denominator of this aprational. * * @return {@link #ONE}. */ @Override public Apint denominator() { return ONES[radix()]; } /** * Radix of this apint. * * @return Radix of this apint. */ @Override public int radix() { return this.value.radix(); } /** * Returns the scale of this apint. Scale is equal to the number of digits in an apint.

* * Zero has a scale of -INFINITE. * * @return Number of digits in this apint in the radix in which it's presented. * * @see Apfloat#scale() */ @Override public long scale() throws ApfloatRuntimeException { return this.value.scale(); } /** * Returns the size of this apint. Size is equal to the number of significant * digits in the number, excluding any trailing zeros.

* * Zero has a size of 0. * * @return Number of significant digits in this number, excluding trailing zeros, in the radix in which it's presented. * * @see Apfloat#size() * * @since 1.6 */ @Override public long size() throws ApfloatRuntimeException { return this.value.size(); } /** * Returns the signum function of this apint. * * @return -1, 0 or 1 as the value of this apint is negative, zero or positive. */ @Override public int signum() { return this.value.signum(); } /** * Returns if this apint is "short". * * @return true if the apint is "short", false if not. * * @see Apfloat#isShort() */ @Override public boolean isShort() throws ApfloatRuntimeException { return this.value.isShort(); } /** * Returns if this number has an integer value.

* * For Apint this method always returns true. * * @return true. * * @since 1.9.0 */ @Override public boolean isInteger() throws ApfloatRuntimeException { return true; } /** * Negative value. * * @return -this. * * @since 1.1 */ @Override public Apint negate() throws ApfloatRuntimeException { return new Apint(this.value.negate()); } /** * Adds two apints. * * @param x The number to be added to this number. * * @return this + x. */ public Apint add(Apint x) throws ApfloatRuntimeException { return new Apint(this.value.add(x.value)); } /** * Subtracts two apints. * * @param x The number to be subtracted from this number. * * @return this - x. */ public Apint subtract(Apint x) throws ApfloatRuntimeException { return new Apint(this.value.subtract(x.value)); } /** * Multiplies two apints. * * @param x The number to be multiplied by this number. * * @return this * x. */ public Apint multiply(Apint x) throws ApfloatRuntimeException { return new Apint(this.value.multiply(x.value)); } /** * Divides two apints. * * @param x The number by which this number is to be divided. * * @return this / x. * * @exception ArithmeticException In case the divisor is zero. */ public Apint divide(Apint x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0) { throw new ArithmeticException(signum() == 0 ? "Zero divided by zero" : "Division by zero"); } else if (signum() == 0) { // 0 / x = 0 return this; } else if (x.equals(ONE)) { // x / 1 = x return this; } long precision; Apfloat a, b, tx, ty; Apint t; a = ApfloatMath.abs(this.value); b = ApfloatMath.abs(x.value); if (a.compareTo(b) < 0) { return ZEROS[a.radix()]; // abs(this) < abs(x) } else { precision = scale() - x.scale() + EXTRA_PRECISION; // Some extra precision } tx = this.value.precision(precision); ty = x.value.precision(precision); t = tx.divide(ty).truncate(); // Approximate division a = a.subtract(ApfloatMath.abs(t.multiply(x.value))); if (a.compareTo(b) >= 0) // Fix division round-off error { t = t.add(new Apint(signum() * x.signum(), x.radix())); } else if (a.signum() < 0) // Fix division round-off error { t = t.subtract(new Apint(signum() * x.signum(), x.radix())); } return t; } /** * Calculates the remainder when divided by an apint. * The result has the same sign as this number. * If x is zero, then zero is returned. * * @param x The number that is used as the divisor in the remainder calculation. * * @return this % x. * * @see ApfloatMath#fmod(Apfloat,Apfloat) */ public Apint mod(Apint x) throws ApfloatRuntimeException { return new Apint(this.value.mod(x.value)); } /** * Floor function. Returns the largest (closest to positive infinity) value * that is not greater than this apfloat and is equal to a mathematical integer. * * @return This apint. */ @Override public Apint floor() { return this; } /** * Ceiling function. Returns the smallest (closest to negative infinity) value * that is not less than this apfloat and is equal to a mathematical integer. * * @return This apint. */ @Override public Apint ceil() { return this; } /** * Truncates fractional part. * * @return This apint. */ @Override public Apint truncate() { return this; } /** * Returns the fractional part. * * @return Always zero. * * @since 1.7.0 */ @Override public Apint frac() throws ApfloatRuntimeException { return ZEROS[radix()]; } /** * Converts this apint to Java's BigInteger. * This method can be greatly faster than converting to String * and then to BigInteger. * * @return This apint converted to a BigInteger. * * @exception IllegalArgumentException If this number is too big to fit in a BigInteger. * * @since 1.6 */ public BigInteger toBigInteger() throws IllegalArgumentException { if (signum() == 0) { return BigInteger.ZERO; } return ApfloatHelper.toBigInteger(this); } /** * Convert this apint to the specified radix. * * @param radix The radix. * * @exception NumberFormatException If the radix is invalid. * * @since 1.2 */ @Override public Apint toRadix(int radix) throws NumberFormatException, ApfloatRuntimeException { return new Apint(this.value.toRadix(radix)); } /** * Compare this apint to the specified apint.

* * @param x Apint to which this apint is to be compared. * * @return -1, 0 or 1 as this apint is numerically less than, equal to, or greater than x. */ public int compareTo(Apint x) { return this.value.compareTo(x.value); } /** * Compare this apint to the specified aprational.

* * @param x Aprational to which this apint is to be compared. * * @return -1, 0 or 1 as this apint is numerically less than, equal to, or greater than x. */ @Override public int compareTo(Aprational x) { if (x instanceof Apint) { return compareTo((Apint) x); } else { return super.compareTo(x); } } /** * Compare this apint to the specified apfloat.

* * @param x Apfloat to which this apint is to be compared. * * @return -1, 0 or 1 as this apint is numerically less than, equal to, or greater than x. */ @Override public int compareTo(Apfloat x) { if (x instanceof Aprational) { return compareTo((Aprational) x); } else { return this.value.compareTo(x); } } /** * Compares this object to the specified object.

* * Note: if two apfloats are compared where one number doesn't have enough * precise digits, the mantissa is assumed to contain zeros. * See {@link Apfloat#compareTo(Apfloat)}. * * @param obj The object to compare with. * * @return true if the objects are the same; false otherwise. */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } else if (obj instanceof Apint) { Apint that = (Apint) obj; return this.value.equals(that.value); } else if (obj instanceof Apfloat && !(obj instanceof Aprational)) { Apfloat that = (Apfloat) obj; return this.value.equals(that); } else { return super.equals(obj); } } /** * Tests two apint numbers for equality. * Returns false if the numbers are definitely known to be not equal. * If true is returned, equality is unknown and should be verified by * calling {@link #equals(Object)}. * This method is usually significantly faster than calling equals(Object). * * @param x The number to test against. * * @return false if the numbers are definitely not equal, true if unknown. * * @since 1.10.0 */ public boolean test(Apint x) { return this.value.test(x.value); } @Override public boolean test(Aprational x) { if (x instanceof Apint) { return test((Apint) x); } else { return super.test(x); } } @Override public boolean test(Apfloat x) { if (x instanceof Aprational) { return test((Aprational) x); } else { return this.value.test(x); } } /** * Returns a hash code for this apint. * * @return The hash code value for this object. */ @Override public int hashCode() { return this.value.hashCode(); } /** * Returns a string representation of this aprational. * * @param pretty true to use a fixed-point notation, false to use an exponential notation. * * @return A string representing this object. */ @Override public String toString(boolean pretty) throws ApfloatRuntimeException { return this.value.toString(pretty); } /** * Write a string representation of this aprational to a Writer. * * @param out The output Writer. * @param pretty true to use a fixed-point notation, false to use an exponential notation. * * @exception IOException In case of I/O error writing to the stream. */ @Override public void writeTo(Writer out, boolean pretty) throws IOException, ApfloatRuntimeException { this.value.writeTo(out, pretty); } @Override public void formatTo(Formatter formatter, int flags, int width, int precision) { if ((flags & ALTERNATE) == ALTERNATE) { throw new FormatFlagsConversionMismatchException("#", 's'); } if (precision != -1) { throw new IllegalFormatPrecisionException(precision); } this.value.formatTo(formatter, flags | ALTERNATE, width, precision); } /** * Returns an ApfloatImpl representing this apint up to the requested precision. * * @param precision Precision of the ApfloatImpl that is needed. * * @return An ApfloatImpl representing this object to the requested precision. */ @Override protected ApfloatImpl getImpl(long precision) throws ApfloatRuntimeException { return this.value.getImpl(precision); } @Override Apint roundAway() { return this; } @Override Apint abs() { return ApintMath.abs(this); } private static final long serialVersionUID = 5409721945040465491L; private Apfloat value; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ApintMath.java000066400000000000000000000726241461767713300243040ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.io.IOException; import java.io.PushbackReader; import java.io.Reader; import java.util.Random; /** * Various mathematical functions for arbitrary precision integers. * * @version 1.14.0 * @author Mikko Tommila */ public class ApintMath { private ApintMath() { } /** * Integer power. * * @param x Base of the power operator. * @param n Exponent of the power operator. * * @return x to the n:th power, that is xn. * * @exception ArithmeticException If both x and n are zero. */ public static Apint pow(Apint x, long n) throws ArithmeticException, ApfloatRuntimeException { if (n == 0) { if (x.signum() == 0) { throw new ArithmeticException("Zero to power zero"); } return new Apint(1, x.radix()); } else if (n < 0) { return Apint.ZEROS[x.radix()]; } // Algorithm improvements by Bernd Kellner int b2pow = 0; while ((n & 1) == 0) { b2pow++; n >>= 1; } Apint r = x; while ((n >>= 1) > 0) { x = x.multiply(x); if ((n & 1) != 0) { r = r.multiply(x); } } while (b2pow-- > 0) { r = r.multiply(r); } return r; } /** * Square root and remainder. * * @param x The argument. * * @return An array of two apints: [q, r], where q2 + r = x. * * @exception ArithmeticException If x is negative. */ public static Apint[] sqrt(Apint x) throws ArithmeticException, ApfloatRuntimeException { return root(x, 2); } /** * Cube root and remainder. * * @param x The argument. * * @return An array of two apints: [q, r], where q3 + r = x. */ public static Apint[] cbrt(Apint x) throws ApfloatRuntimeException { return root(x, 3); } /** * Positive integer root and remainder.

* * Returns the n:th root of x, * that is x1/n, rounded towards zero. * * @param x The argument. * @param n Which root to take. * * @return An array of two apints: [q, r], where qn + r = x. * * @exception ArithmeticException If n and x are zero, or x is negative and n is even. */ public static Apint[] root(Apint x, long n) throws ArithmeticException, ApfloatRuntimeException { if (n == 0) { if (x.signum() == 0) { throw new ArithmeticException("Zeroth root of zero"); } Apint one = new Apint(1, x.radix()); return new Apint[] { one, x.subtract(one) }; } else if (x.signum() == 0) { return new Apint[] { x, x }; // Avoid division by zero } else if (x.equals(Apint.ONE) || n == 1) { return new Apint[] { x, Apint.ZEROS[x.radix()] }; } else if (n < 0) { return new Apint[] { Apint.ZEROS[x.radix()], x }; // 1 / x where x > 1 } long precision = x.scale() / n + Apint.EXTRA_PRECISION; Apfloat approxX = x.precision(precision); Apfloat approxRoot; approxRoot = ApfloatMath.root(approxX, n); Apint root = approxRoot.truncate(), // May be one too big or one too small pow = pow(root, n); if (abs(pow).compareTo(abs(x)) > 0) { // Approximate root was one too big pow = (x.signum() >= 0 ? powXMinus1(pow, root, n) : powXPlus1(pow, root, n)); root = root.subtract(new Apint(x.signum(), x.radix())); } else { // Approximate root was correct or one too small Apint powPlus1 = (x.signum() >= 0 ? powXPlus1(pow, root, n) : powXMinus1(pow, root, n)); if (abs(powPlus1).compareTo(abs(x)) <= 0) { // Approximate root was one too small pow = powPlus1; root = root.add(new Apint(x.signum(), x.radix())); } } Apint remainder = x.subtract(pow); assert (remainder.signum() * x.signum() >= 0); return new Apint[] { root, remainder }; } private static Apint powXMinus1(Apint pow, Apint x, long n) throws ApfloatRuntimeException { Apint one = new Apint(1, x.radix()); if (n == 2) { // (x - 1)^2 = x^2 - 2*x + 1 pow = pow.subtract(x).subtract(x).add(one); } else if (n == 3) { // (x - 1)^3 = x^3 - 3*x^2 + 3*x - 1 = x^3 - 3*x*(x - 1) - 1 pow = pow.subtract(new Apint(3, x.radix()).multiply(x).multiply(x.subtract(one))).subtract(one); } else { pow = pow(x.subtract(one), n); } return pow; } private static Apint powXPlus1(Apint pow, Apint x, long n) throws ApfloatRuntimeException { Apint one = new Apint(1, x.radix()); if (n == 2) { // (x + 1)^2 = x^2 + 2*x + 1 pow = pow.add(x).add(x).add(one); } else if (n == 3) { // (x + 1)^3 = x^3 + 3*x^2 + 3*x + 1 = x^3 + 3*x*(x + 1) + 1 pow = pow.add(new Apint(3, x.radix()).multiply(x).multiply(x.add(one))).add(one); } else { pow = pow(x.add(one), n); } return pow; } /** * Returns an apint whose value is -x. * * @deprecated Use {@link Apint#negate()}. * * @param x The argument. * * @return -x. */ @Deprecated public static Apint negate(Apint x) throws ApfloatRuntimeException { return x.negate(); } /** * Absolute value. * * @param x The argument. * * @return Absolute value of x. */ public static Apint abs(Apint x) throws ApfloatRuntimeException { if (x.signum() >= 0) { return x; } else { return x.negate(); } } /** * Copy sign from one argument to another. * * @param x The value whose sign is to be adjusted. * @param y The value whose sign is to be used. * * @return x with its sign changed to match the sign of y. * * @since 1.1 */ public static Apint copySign(Apint x, Apint y) throws ApfloatRuntimeException { if (y.signum() == 0) { return y; } else if (x.signum() != y.signum()) { return x.negate(); } else { return x; } } /** * Multiply by a power of the radix. * Any rounding will occur towards zero. * * @param x The argument. * @param scale The scaling factor. * * @return x * x.radix()scale. */ public static Apint scale(Apint x, long scale) throws ApfloatRuntimeException { return ApfloatMath.scale(x, scale).truncate(); } /** * Quotient and remainder. * * @param x The dividend. * @param y The divisor. * * @return An array of two apints: [quotient, remainder], that is [x / y, x % y]. * * @exception ArithmeticException In case the divisor is zero. */ public static Apint[] div(Apint x, Apint y) throws ArithmeticException, ApfloatRuntimeException { if (y.signum() == 0) { throw new ArithmeticException("Division by zero"); } else if (x.signum() == 0) { // 0 / x = 0 return new Apint[] { x, x }; } else if (y.equals(Apint.ONE)) { // x / 1 = x return new Apint[] { x, Apint.ZEROS[x.radix()] }; } long precision; Apfloat tx, ty; Apint a, b, q, r; a = abs(x); b = abs(y); if (a.compareTo(b) < 0) { return new Apint[] { Apint.ZEROS[x.radix()], x }; // abs(x) < abs(y) } else { precision = x.scale() - y.scale() + Apint.EXTRA_PRECISION; // Some extra precision to avoid round-off errors } tx = x.precision(precision); ty = y.precision(precision); q = tx.divide(ty).truncate(); // Approximate division a = a.subtract(abs(q.multiply(y))); if (a.compareTo(b) >= 0) // Fix division round-off error { q = q.add(new Apint(x.signum() * y.signum(), x.radix())); a = a.subtract(b); } else if (a.signum() < 0) // Fix division round-off error { q = q.subtract(new Apint(x.signum() * y.signum(), x.radix())); a = a.add(b); } r = copySign(a, x); return new Apint[] { q, r }; } /** * Greatest common divisor. * This method returns a positive number even if one of a * and b is negative. * * @param a First argument. * @param b Second argument. * * @return Greatest common divisor of a and b. */ public static Apint gcd(Apint a, Apint b) throws ApfloatRuntimeException { return GCDHelper.gcd(a, b); } /** * Least common multiple. * This method returns a positive number even if one of a * and b is negative. * * @param a First argument. * @param b Second argument. * * @return Least common multiple of a and b. */ public static Apint lcm(Apint a, Apint b) throws ApfloatRuntimeException { if (a.signum() == 0 && b.signum() == 0) { return Apint.ZEROS[a.radix()]; } else { return abs(a.multiply(b)).divide(gcd(a, b)); } } /** * Modular multiplication. Returns a * b % m * * @param a First argument. * @param b Second argument. * @param m Modulus. * * @return a * b mod m */ public static Apint modMultiply(Apint a, Apint b, Apint m) throws ApfloatRuntimeException { return a.multiply(b).mod(m); } private static Apint modMultiply(Apint x1, Apint x2, Apint y, Apfloat inverseY) throws ApfloatRuntimeException { Apint x = x1.multiply(x2); if (x.signum() == 0) { // 0 % x = 0 return x; } long precision = x.scale() - y.scale() + Apfloat.EXTRA_PRECISION; // Some extra precision to avoid round-off errors Apint a, b, t; a = abs(x); b = abs(y); if (a.compareTo(b) < 0) { return x; // abs(x) < abs(y) } t = x.multiply(inverseY.precision(precision)).truncate(); // Approximate division a = a.subtract(abs(t.multiply(y))); if (a.compareTo(b) >= 0) // Fix division round-off error { a = a.subtract(b); } else if (a.signum() < 0) // Fix division round-off error { a = a.add(b); } t = copySign(a, x); return t; } /** * Modular power. * * @param a Base. * @param b Exponent. * @param m Modulus. * * @return ab mod m * * @exception ArithmeticException If the exponent is negative but the GCD of a and m is not 1 and the modular inverse does not exist. */ public static Apint modPow(Apint a, Apint b, Apint m) throws ArithmeticException, ApfloatRuntimeException { if (b.signum() == 0) { if (a.signum() == 0) { throw new ArithmeticException("Zero to power zero"); } return new Apint(1, a.radix()); } else if (m.signum() == 0) { return m; // By definition } m = abs(m); Apfloat inverseModulus = ApfloatMath.inverseRoot(m, 1, m.scale() + Apfloat.EXTRA_PRECISION); a = a.mod(m); if (b.signum() < 0) { // Calculate modular inverse first a = modInverse(a, m); b = b.negate(); } Apint two = new Apint(2, b.radix()); // Sub-optimal; the divisor could be some power of two Apint[] qr; while ((qr = div(b, two))[1].signum() == 0) { a = modMultiply(a, a, m, inverseModulus); b = qr[0]; } Apint r = a; qr = div(b, two); while ((b = qr[0]).signum() > 0) { a = modMultiply(a, a, m, inverseModulus); qr = div(b, two); if (qr[1].signum() != 0) { r = modMultiply(r, a, m, inverseModulus); } } return r; } private static Apint modInverse(Apint a, Apint m) throws ArithmeticException, ApfloatRuntimeException { // Extended Euclidean algorithm Apint one = new Apint(1, m.radix()), x = Apint.ZERO, y = one, oldX = one, oldY = Apint.ZERO, oldA = a, b = m; while (b.signum() != 0) { Apint q = a.divide(b); Apint tmp = b; b = a.mod(b); a = tmp; tmp = x; x = oldX.subtract(q.multiply(x)); oldX = tmp; tmp = y; y = oldY.subtract(q.multiply(y)); oldY = tmp; } if (!abs(a).equals(one)) { // GCD is not 1 throw new ArithmeticException("Modular inverse does not exist"); } if (oldX.signum() != oldA.signum()) { // Adjust by one modulus if sign is wrong oldX = oldX.add(copySign(m, oldA)); } return oldX; } /** * Factorial function. Uses the default radix. * * @param n The number whose factorial is to be calculated. Should be non-negative. * * @return n! * * @exception ArithmeticException If n is negative. * @exception NumberFormatException If the default radix is not valid. * * @since 1.1 */ public static Apint factorial(long n) throws ArithmeticException, NumberFormatException, ApfloatRuntimeException { return new Apint(ApfloatMath.factorial(n, Apfloat.INFINITE)); } /** * Factorial function. Returns a number in the specified radix. * * @param n The number whose factorial is to be calculated. Should be non-negative. * @param radix The radix to use. * * @return n! * * @exception ArithmeticException If n is negative. * @exception NumberFormatException If the radix is not valid. * * @since 1.1 */ public static Apint factorial(long n, int radix) throws ArithmeticException, NumberFormatException, ApfloatRuntimeException { return new Apint(ApfloatMath.factorial(n, Apfloat.INFINITE, radix)); } /** * Double factorial function. Uses the default radix. * * @param n The number whose double factorial is to be calculated. Should be non-negative. * * @return n!! * * @exception ArithmeticException If n is negative. * @exception NumberFormatException If the default radix is not valid. * * @since 1.14.0 */ public static Apint doubleFactorial(long n) throws ArithmeticException, NumberFormatException, ApfloatRuntimeException { return new Apint(ApfloatMath.doubleFactorial(n, Apfloat.INFINITE)); } /** * Double factorial function. Returns a number in the specified radix. * * @param n The number whose double factorial is to be calculated. Should be non-negative. * @param radix The radix to use. * * @return n!! * * @exception ArithmeticException If n is negative. * @exception NumberFormatException If the radix is not valid. * * @since 1.14.0 */ public static Apint doubleFactorial(long n, int radix) throws ArithmeticException, NumberFormatException, ApfloatRuntimeException { return new Apint(ApfloatMath.doubleFactorial(n, Apfloat.INFINITE, radix)); } /** * Binomial coefficient. Uses the default radix. * * @param n The first argument. * @param k The second argument. * * @return * * ( * * n * k * * ) * * * * @since 1.11.0 */ public static Apint binomial(long n, long k) throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return binomial(n, k, radix); } /** * Binomial coefficient. Uses the specified radix. * * @param n The first argument. * @param k The second argument. * @param radix The radix. * * @return * * ( * * n * k * * ) * * * * @throws NumberFormatException If the radix is not valid. * * @since 1.11.0 */ public static Apint binomial(long n, long k, int radix) throws NumberFormatException, ApfloatRuntimeException { // See https://mathworld.wolfram.com/BinomialCoefficient.html for the logic on negative values boolean negate = false; if (n < 0) { if (k >= 0) { try { n = Math.subtractExact(k, n) - 1; } catch (ArithmeticException ae) { return binomial(new Apint(n, radix), new Apint(k, radix)); } } else if (k <= n) { long n1 = -k - 1; k = n - k; n = n1; } else { return Apint.ZEROS[radix]; } negate = ((k & 1) == 1); } else if (k < 0) { try { k = Math.subtractExact(n, k); } catch (ArithmeticException ae) { return binomial(new Apint(n, radix), new Apint(k, radix)); } } if (k < 0 || k > n) { return Apint.ZEROS[radix]; } assert (n >= 0); assert (k >= 0); if (k > n / 2) { // Optimize performance k = n - k; } Apint b = pochhammer(n - k + 1, k, radix).divide(factorial(k, radix)); return (negate ? b.negate() : b); } /** * Binomial coefficient. * * @param n The first argument. * @param k The second argument. * * @return * * ( * * n * k * * ) * * * * @since 1.11.0 */ public static Apint binomial(Apint n, Apint k) throws ApfloatRuntimeException { // See https://mathworld.wolfram.com/BinomialCoefficient.html for the logic on negative values boolean negate = false; int radix = n.radix(); Apint one = Apint.ONES[radix], two = new Apint(2, radix); if (n.signum() < 0) { if (k.signum() >= 0) { n = k.subtract(n).subtract(one); } else if (k.compareTo(n) <= 0) { Apint n1 = k.negate().subtract(one); k = n.subtract(k); n = n1; } else { return Apint.ZEROS[radix]; } negate = (k.mod(two).signum() != 0); } else if (k.signum() < 0) { k = n.subtract(k); } if (k.signum() < 0 || k.compareTo(n) > 0) { return Apint.ZEROS[radix]; } assert (n.signum() >= 0); assert (k.signum() >= 0); if (k.compareTo(n.divide(two)) > 0) { // Optimize performance k = n.subtract(k); } Apint f = factorial(ApfloatHelper.longValueExact(k), radix), b = pochhammer(n.subtract(k).add(one), k).divide(f); return (negate ? b.negate() : b); } // Product of the numbers n * (n + 1) * (n + 2) * ... * (n + m - 1) private static Apint pochhammer(long n, long m, int radix) { assert (m >= 0); if (m == 0) { return Apint.ONES[radix]; } if (m == 1) { return new Apint(n, radix); } long k = m >>> 1; return pochhammer(n, k, radix).multiply(pochhammer(n + k, m - k, radix)); } // Product of the numbers n * (n + 1) * (n + 2) * ... * (n + m - 1) private static Apint pochhammer(Apint n, Apint m) { assert (m.signum() >= 0); Apint one = Apint.ONES[n.radix()]; if (m.signum() == 0) { return one; } if (m.equals(one)) { return n; } Apint two = new Apint(2, n.radix()); Apint k = m.divide(two); return pochhammer(n, k).multiply(pochhammer(n.add(k), m.subtract(k))); } /** * Product of numbers. * This method may perform significantly better * than simply multiplying the numbers sequentially.

* * If there are no arguments, the return value is 1. * * @param x The argument(s). * * @return The product of the given numbers. * * @since 1.3 */ public static Apint product(Apint... x) throws ApfloatRuntimeException { return new Apint(ApfloatMath.product(x)); } /** * Sum of numbers.

* * If there are no arguments, the return value is 0. * * @param x The argument(s). * * @return The sum of the given numbers. * * @since 1.3 */ public static Apint sum(Apint... x) throws ApfloatRuntimeException { return new Apint(ApfloatMath.sum(x)); } /** * Generates a random number. Uses the default radix. * Returned values are chosen pseudorandomly with (approximately) * uniform distribution from the range 0 ≤ x < radixdigits. * The generated random numbers may have leading zeros and may thus not * always have exactly the requested number of digis. * * @param digits Maximum number of digits in the number. * * @return A random number, uniformly distributed between 0 ≤ x < radixdigits. * * @exception NumberFormatException If the default radix is not valid. * @exception IllegalArgumentException In case the number of specified digits is invalid. * * @since 1.9.0 */ public static Apint random(long digits) { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return random(digits, radix); } /** * Generates a random number. * Returned values are chosen pseudorandomly with (approximately) * uniform distribution from the range 0 ≤ x < radixdigits. * The generated random numbers may have leading zeros and may thus not * always have exactly the requested number of digis. * * @param digits Maximum number of digits in the number. * @param radix The radix in which the number should be generated. * * @return A random number, uniformly distributed between 0 ≤ x < radixdigits, in base radix. * * @exception NumberFormatException If the radix is not valid. * @exception IllegalArgumentException In case the number of specified digits is invalid. * * @since 1.9.0 */ public static Apint random(long digits, int radix) { if (digits <= 0) { throw new IllegalArgumentException(digits + " is not positive"); } else if (digits == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot generate an infinite number of random digits"); } PushbackReader reader = new PushbackReader(new Reader() { @Override public int read(char[] buffer, int offset, int length) { if (this.remaining == 0) { return -1; } length = (int) Math.min(length, this.remaining); for (int i = 0; i < length; i++) { buffer[i + offset] = Character.forDigit(RANDOM.nextInt(radix), radix); } this.remaining -= length; return length; } @Override public void close() { } private long remaining = digits; }); try { return new Apint(reader, radix); } catch (IOException ioe) { throw new ApfloatRuntimeException("Error generating random number"); } } /** * Returns the greater of the two values. * * @param x An argument. * @param y Another argument. * * @return The greater of the two values. * * @since 1.9.0 */ public static Apint max(Apint x, Apint y) { return (x.compareTo(y) > 0 ? x : y); } /** * Returns the smaller of the two values. * * @param x An argument. * @param y Another argument. * * @return The smaller of the two values. * * @since 1.9.0 */ public static Apint min(Apint x, Apint y) { return (x.compareTo(y) < 0 ? x : y); } private static final Random RANDOM = new Random(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/Aprational.java000066400000000000000000001036221461767713300245020ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.BigInteger; import java.io.PushbackReader; import java.io.Writer; import java.io.IOException; import java.lang.ref.SoftReference; import java.util.Formatter; import static java.util.FormattableFlags.*; import org.apfloat.spi.ApfloatImpl; import static org.apfloat.spi.RadixConstants.*; /** * Arbitrary precision rational number class. An aprational consists of * a numerator and a denominator of type {@link Apint}.

* * @see Apint * @see AprationalMath * * @version 1.10.0 * @author Mikko Tommila */ public class Aprational extends Apfloat { /** * Default constructor. To be used only by subclasses that * overload all needed methods. */ protected Aprational() { } /** * Construct an integer aprational whose denominator is one. * * @param value The numerator of the number. */ public Aprational(Apint value) throws ApfloatRuntimeException { this(value, ONES[value.radix()]); } /** * Construct an aprational with the specified numerator and denominator. * * @param numerator The numerator. * @param denominator The denominator. * * @exception IllegalArgumentException In case the denominator is zero, or if the denominator is not one or the numerator is not zero, and the radix of the numerator and denominator are different. */ public Aprational(Apint numerator, Apint denominator) throws IllegalArgumentException, ApfloatRuntimeException { this.numerator = numerator; this.denominator = denominator; checkDenominator(); reduce(); } /** * Constructs an aprational from a string. The default radix is used.

* * The input must be of one of the formats

* * integer
* numerator [whitespace] "/" [whitespace] denominator
* * @param value The input string. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the denominator is zero. */ public Aprational(String value) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(value, ApfloatContext.getContext().getDefaultRadix()); } /** * Constructs an aprational from a string with the specified radix.

* * The input must be of one of the formats

* * integer
* numerator [whitespace] "/" [whitespace] denominator
* * @param value The input string. * @param radix The radix to be used. * * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the denominator is zero. */ public Aprational(String value, int radix) throws NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { int index = value.indexOf('/'); if (index < 0) { this.numerator = new Apint(value, radix); this.denominator = ONES[radix]; return; } this.numerator = new Apint(value.substring(0, index).trim(), radix); this.denominator = new Apint(value.substring(index + 1).trim(), radix); checkDenominator(); reduce(); } /** * Reads an aprational from a reader. The default radix is used. The constructor * stops reading at the first character it doesn't understand. The reader must * thus be a PushbackReader so that the invalid character can be * returned back to the stream.

* * The input must be of one of the formats

* * integer [whitespace]
* numerator [whitespace] "/" [whitespace] denominator
* * @param in The input stream. * * @exception IOException In case of I/O error reading the stream. * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the denominator is zero. */ public Aprational(PushbackReader in) throws IOException, NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this(in, ApfloatContext.getContext().getDefaultRadix()); } /** * Reads an aprational from a reader. The specified radix is used. * * @param in The input stream. * @param radix The radix to be used. * * @exception IOException In case of I/O error reading the stream. * @exception NumberFormatException In case the number is invalid. * @exception IllegalArgumentException In case the denominator is zero. * * @see #Aprational(PushbackReader) */ public Aprational(PushbackReader in, int radix) throws IOException, NumberFormatException, IllegalArgumentException, ApfloatRuntimeException { this.numerator = new Apint(in, radix); ApfloatHelper.extractWhitespace(in); if (!ApfloatHelper.readMatch(in, '/')) { this.denominator = ONES[radix]; return; } ApfloatHelper.extractWhitespace(in); this.denominator = new Apint(in, radix); checkDenominator(); reduce(); } /** * Constructs an aprational from a BigInteger. * The default radix is used. * * @param value The numerator of the number. */ public Aprational(BigInteger value) throws ApfloatRuntimeException { this.numerator = new Apint(value); this.denominator = ONE; } /** * Constructs an aprational from a BigInteger using the specified radix. * * @param value The numerator of the number. * @param radix The radix of the number. */ public Aprational(BigInteger value, int radix) throws ApfloatRuntimeException { this.numerator = new Apint(value, radix); this.denominator = ONES[radix]; } /** * Constructs an aprational from a double. * The exact value represented by the double is used. * The default radix is used.

* * Note that doubles are presented as an integer multiplied by * a power of two (positive or negative). Many numbers can't be represented * exactly this way, e.g. new Aprational(0.1) won't result * in 1/10 but in 3602879701896397/36028797018963968. * * @param value The numerator of the number. */ public Aprational(double value) throws ApfloatRuntimeException { this(value, ApfloatContext.getContext().getDefaultRadix()); } /** * Constructs an aprational from a double using the specified radix. * The exact value represented by the double is used.

* * Note that doubles are presented as an integer multiplied by * a power of two (positive or negative). Many numbers can't be represented * exactly this way, e.g. new Aprational(0.1) won't result * in 1/10 but in 3602879701896397/36028797018963968. * * @param value The numerator of the number. * @param radix The radix of the number. */ public Aprational(double value, int radix) throws ApfloatRuntimeException { if (Double.isInfinite(value) || Double.isNaN(value)) { throw new NumberFormatException(value + " is not a valid number"); } long bits = Double.doubleToLongBits(value), sign = ((bits >> 63) == 0 ? 1 : -1), exponent = (bits >> 52) & 0x7FFL, significand = (exponent == 0 ? (bits & ((1L << 52) - 1)) << 1 : (bits & ((1L << 52) - 1)) | (1L << 52)); exponent -= 1075; // At this point, value == sign * significand * 2^exponent if (significand == 0) // Zero { this.numerator = new Apint(0, radix); this.denominator = ONES[radix]; return; } // Normalize so that the significand does not have a factor of two while ((significand & 1) == 0) // i.e. the significand is even { significand >>= 1; exponent++; } this.numerator = new Apint(sign * significand, radix); Apint powerOfTwo = ApintMath.pow(new Apint(2, radix), Math.abs(exponent)); if (exponent >= 0) { this.numerator = this.numerator.multiply(powerOfTwo); this.denominator = ONES[radix]; // No need to reduce as the value is an integer } else { this.denominator = powerOfTwo; // No need to reduce as the denominator is a power of two and the numerator does not have a factor of two } } /** * Numerator of this aprational. * * @return n where this = n / m. */ public Apint numerator() { return this.numerator; } /** * Denominator of this aprational. * * @return m where this = n / m. */ public Apint denominator() { return this.denominator; } /** * Radix of this aprational. * * @return Radix of this aprational. */ @Override public int radix() { return (numerator() == ONE ? denominator().radix() : numerator().radix()); } /** * Returns the precision of this aprational. * * @return INFINITE */ @Override public long precision() throws ApfloatRuntimeException { return INFINITE; } /** * Returns the scale of this aprational. Scale is equal to the number of digits in the aprational's truncated value.

* * Zero has a scale of -INFINITE. * * @return Number of digits in the truncated value of this aprational in the radix in which it's presented. * * @see Apfloat#scale() */ @Override public long scale() throws ApfloatRuntimeException { if (signum() == 0) { return -INFINITE; } if (this.scale == UNDEFINED) { long scale = numerator().scale() - denominator().scale(); if (scale > 0) { scale = truncate().scale(); } else { scale = AprationalMath.scale(this, 1 - scale).truncate().scale() + scale - 1; } // Writes and reads of volatile long values are always atomic so multiple threads can read and write this at the same time this.scale = scale; } return this.scale; } /** * Returns the size of this aprational. Size is equal to the number of significant * digits in the aprational's floating-point expansion. If the expansion is infinite * then this method returns INFINITE.

* * Zero has a size of 0. * * @return Number of significant digits in the floating-point expansion of this aprational in the radix in which it's presented. * * @see Apfloat#size() * * @since 1.6 */ @Override public long size() throws ApfloatRuntimeException { if (signum() == 0) { return 0; } if (denominator().equals(ONE)) { return numerator().size(); } if (this.size == 0) { long size; // Check that the factorization of the divisor consists entirely of factors of the base // E.g. if base is 10=2*5 then the divisor should be 2^n*5^m Apint dividend = denominator(); for (int i = 0; i < RADIX_FACTORS[radix()].length; i++) { Apint factor = new Apint(RADIX_FACTORS[radix()][i], radix()); Apint[] quotientAndRemainder; // Keep dividing by factor as long as dividend % factor == 0 // that is remove factors of the base from the divisor while ((quotientAndRemainder = ApintMath.div(dividend, factor))[1].signum() == 0) { dividend = quotientAndRemainder[0]; } } // Check if the divisor was factored all the way to one by just dividing by factors of the base if (!dividend.equals(ONE)) { // No - infinite floating-point expansion size = INFINITE; } else { // Yes - calculate the number of digits // Scale the number so that all significant digits will fit in the integer part // The factor 5 is a rough estimate; e.g. if the denominator is 2^n then in base 34 we get close to that value size = ApintMath.scale(numerator(), denominator().scale() * 5).divide(denominator()).size(); } // Writes and reads of volatile long values are always atomic so multiple threads can read and write this at the same time this.size = size; } return this.size; } /** * Returns the signum function of this aprational. * * @return -1, 0 or 1 as the value of this aprational is negative, zero or positive. */ @Override public int signum() { return numerator().signum(); } /** * Returns if this aprational is "short". * * @return true if the aprational is "short", false if not. * * @see Apfloat#isShort() */ @Override public boolean isShort() throws ApfloatRuntimeException { return numerator().isShort() && denominator().equals(ONE); } /** * Returns if this number has an integer value. Note that this does not * necessarily mean that this object is an instance of {@link Apint}.

* * A rational number is an integer if the denominator is one. * * @return If this number's value is an integer. * * @since 1.9.0 */ @Override public boolean isInteger() throws ApfloatRuntimeException { return denominator().equals(ONE); } /** * Negative value. * * @return -this. * * @since 1.1 */ @Override public Aprational negate() throws ApfloatRuntimeException { return new Aprational(numerator().negate(), denominator()); } /** * Adds two aprational numbers. * * @param x The number to be added to this number. * * @return this + x. */ public Aprational add(Aprational x) throws ApfloatRuntimeException { return new Aprational(numerator().multiply(x.denominator()).add(denominator().multiply(x.numerator())), denominator().multiply(x.denominator())).reduce(); } /** * Subtracts two aprational numbers. * * @param x The number to be subtracted from this number. * * @return this - x. */ public Aprational subtract(Aprational x) throws ApfloatRuntimeException { return new Aprational(numerator().multiply(x.denominator()).subtract(denominator().multiply(x.numerator())), denominator().multiply(x.denominator())).reduce(); } /** * Multiplies two aprational numbers. * * @param x The number to be multiplied by this number. * * @return this * x. */ public Aprational multiply(Aprational x) throws ApfloatRuntimeException { Aprational result = new Aprational(numerator().multiply(x.numerator()), denominator().multiply(x.denominator())); if (this == x) { // When squaring we know that no reduction is needed return result; } else { return result.reduce(); } } /** * Divides two aprational numbers. * * @param x The number by which this number is to be divided. * * @return this / x. * * @exception ArithmeticException In case the divisor is zero. */ public Aprational divide(Aprational x) throws ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0) { throw new ArithmeticException(signum() == 0 ? "Zero divided by zero" : "Division by zero"); } else if (signum() == 0) { // 0 / x = 0 return this; } // Comparison against one would be inefficient at this point return new Aprational(numerator().multiply(x.denominator()), denominator().multiply(x.numerator())).reduce(); } /** * Calculates the remainder when divided by an aprational. * The result has the same sign as this number. * If x is zero, then zero is returned. * * @param x The number that is used as the divisor in the remainder calculation. * * @return this % x. * * @since 1.2 */ public Aprational mod(Aprational x) throws ApfloatRuntimeException { if (x.signum() == 0) { return x; // By definition } else if (signum() == 0) { // 0 % x = 0 return this; } return subtract(divide(x).truncate().multiply(x)); } /** * Floor function. Returns the largest (closest to positive infinity) value * that is not greater than this aprational and is equal to a mathematical integer. * * @return This aprational rounded towards negative infinity. */ @Override public Apint floor() throws ApfloatRuntimeException { if (signum() >= 0) { return truncate(); } else { return roundAway(); } } /** * Ceiling function. Returns the smallest (closest to negative infinity) value * that is not less than this aprational and is equal to a mathematical integer. * * @return This aprational rounded towards positive infinity. */ @Override public Apint ceil() throws ApfloatRuntimeException { if (signum() <= 0) { return truncate(); } else { return roundAway(); } } /** * Truncates fractional part. * * @return This aprational rounded towards zero. */ @Override public Apint truncate() throws ApfloatRuntimeException { return numerator().divide(denominator()); } /** * Returns the fractional part. The fractional part is always 0 <= abs(x.frac()) < 1. * The fractional part has the same sign as the number. For the fractional and integer parts, this always holds:

* * x = x.truncate() + x.frac() * * @return The fractional part of this aprational. * * @since 1.7.0 */ @Override public Aprational frac() throws ApfloatRuntimeException { return new Aprational(numerator().mod(denominator()), denominator()); } /** * Convert this aprational to the specified radix. * * @param radix The radix. * * @exception NumberFormatException If the radix is invalid. * * @since 1.2 */ @Override public Aprational toRadix(int radix) throws NumberFormatException, ApfloatRuntimeException { return new Aprational(numerator().toRadix(radix), denominator().toRadix(radix)); } /** * Compare this aprational to the specified aprational.

* * @param x Aprational to which this aprational is to be compared. * * @return -1, 0 or 1 as this aprational is numerically less than, equal to, or greater than x. */ public int compareTo(Aprational x) { Apint a = numerator().multiply(x.denominator()), b = x.numerator().multiply(denominator()); return a.compareTo(b); } /** * Compare this aprational to the specified apfloat.

* * @param x Apfloat to which this aprational is to be compared. * * @return -1, 0 or 1 as this aprational is numerically less than, equal to, or greater than x. */ @Override public int compareTo(Apfloat x) { if (x instanceof Aprational) { return compareTo((Aprational) x); } else { // Sub-optimal performance wise, but works Apfloat a = numerator().precision(INFINITE), // Actual class must be Apfloat b = x.multiply(denominator()).precision(INFINITE); // Actual class must be Apfloat return a.compareTo(b); } } @Override public boolean preferCompare(Apfloat x) { return !(x instanceof Aprational); } /** * Compares this object to the specified object.

* * Note: if two apfloats are compared where one number doesn't have enough * precise digits, the mantissa is assumed to contain zeros. * See {@link Apfloat#compareTo(Apfloat)}. * * @param obj The object to compare with. * * @return true if the objects are the same; false otherwise. */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } else if (obj instanceof Aprational) { Aprational that = (Aprational) obj; return numerator().equals(that.numerator()) && denominator().equals(that.denominator()); } else if (obj instanceof Apfloat) { Apfloat that = (Apfloat) obj; // Sub-optimal performance wise, but works Apfloat a = numerator().precision(INFINITE), // Actual class must be Apfloat b = that.multiply(denominator()).precision(INFINITE); // Actual class must be Apfloat return a.equals(b); } else { return super.equals(obj); } } /** * Tests two aprational numbers for equality. * Returns false if the numbers are definitely known to be not equal. * If true is returned, equality is unknown and should be verified by * calling {@link #equals(Object)}. * This method is usually significantly faster than calling equals(Object). * * @param x The number to test against. * * @return false if the numbers are definitely not equal, true if unknown. * * @since 1.10.0 */ public boolean test(Aprational x) { return numerator().test(x.numerator()) && denominator().test(x.denominator()); } @Override public boolean test(Apfloat x) throws ApfloatRuntimeException { if (x instanceof Aprational) { return test((Aprational) x); } else { return !isInteger() || numerator().test(x); } } /** * Returns a hash code for this aprational. * * @return The hash code value for this object. */ @Override public int hashCode() { return numerator().hashCode() * 3 + denominator().hashCode(); } /** * Returns a string representation of this aprational. * * @return A string representing this object. */ @Override public String toString() { return toString(true); } /** * Returns a string representation of this aprational. * * @param pretty true to use a fixed-point notation, false to use an exponential notation. * * @return A string representing this object. */ @Override public String toString(boolean pretty) throws ApfloatRuntimeException { return numerator().toString(pretty) + (denominator().equals(ONE) ? "" : '/' + denominator().toString(pretty)); } /** * Write a string representation of this aprational to a Writer. * * @param out The output Writer. * * @exception IOException In case of I/O error writing to the stream. */ @Override public void writeTo(Writer out) throws IOException, ApfloatRuntimeException { writeTo(out, true); } /** * Write a string representation of this aprational to a Writer. * * @param out The output Writer. * @param pretty true to use a fixed-point notation, false to use an exponential notation. * * @exception IOException In case of I/O error writing to the stream. */ @Override public void writeTo(Writer out, boolean pretty) throws IOException, ApfloatRuntimeException { numerator().writeTo(out, pretty); if (!denominator().equals(ONE)) { out.write('/'); denominator().writeTo(out, pretty); } } /** * Formats the object using the provided formatter. * * @param formatter The formatter. * @param flags The flags to modify the output format. * @param width The minimum number of characters to be written to the output, or -1 for no minimum. * @param precision The maximum number of characters to be written to the output, or -1 for no maximum. * * @since 1.3 */ @Override public void formatTo(Formatter formatter, int flags, int width, int precision) { if (denominator().equals(ONE)) { numerator().formatTo(formatter, flags, width, precision); } else { if (width == -1) { numerator().formatTo(formatter, flags, width, precision); formatter.format("/"); denominator().formatTo(formatter, flags, width, precision); } else { try { Writer out = FormattingHelper.wrapAppendableWriter(formatter.out()); out = FormattingHelper.wrapPadWriter(out, (flags & LEFT_JUSTIFY) == LEFT_JUSTIFY); formatter = new Formatter(out, formatter.locale()); numerator().formatTo(formatter, flags, -1, precision); formatter.format("/"); denominator().formatTo(formatter, flags, -1, precision); FormattingHelper.finishPad(out, width); } catch (IOException ioe) { // Ignore as we can't propagate it; unfortunately we can't set it to the formattable either } } } } /** * Returns an ApfloatImpl representing the approximation of this * aprational up to the requested precision.

* * @param precision Precision of the ApfloatImpl that is needed. * * @return An ApfloatImpl representing this object to the requested precision. */ @Override protected ApfloatImpl getImpl(long precision) throws ApfloatRuntimeException { return ensureApprox(precision).getImpl(precision); } // Round away from zero i.e. opposite direction of rounding than in truncate() @Override Apint roundAway() throws ApfloatRuntimeException { Apint[] div = ApintMath.div(numerator(), denominator()); if (div[1].signum() == 0) { // No remainder from division; result is exact return div[0]; } else { // Remainder from division; round away from zero return div[0].add(new Apint(signum(), div[0].radix())); } } @Override Aprational scale(long scale) { return AprationalMath.scale(this, scale); } @Override Aprational abs() { return AprationalMath.abs(this); } @Override int compareToHalf() { return RoundingHelper.compareToHalf(this); } private void checkDenominator() throws IllegalArgumentException { if (this.denominator.signum() == 0) { throw new IllegalArgumentException("Denominator is zero"); } } // Reduce the numerator and denominator to smallest possible terms and set the signs properly // NOTE: the method mutates this object, so it must only be called for newly constructed aprationals // Returns this, for convenience private Aprational reduce() throws IllegalArgumentException, ApfloatRuntimeException { if (this.numerator.signum() == 0) { this.denominator = ONES[this.denominator.radix()]; } else { if (!this.numerator.equals(ONE) && !this.denominator.equals(ONE)) { if (this.numerator.radix() != this.denominator.radix()) { throw new IllegalArgumentException("Numerator and denominator must have the same radix"); } Apint gcd = ApintMath.gcd(this.numerator, this.denominator); this.numerator = this.numerator.divide(gcd); this.denominator = this.denominator.divide(gcd); } int sign = this.numerator.signum() * this.denominator.signum(); this.denominator = ApintMath.abs(this.denominator); if (sign != this.numerator.signum()) { this.numerator = this.numerator.negate(); } } return this; } private synchronized Apfloat ensureApprox(long precision) throws ApfloatRuntimeException { Apfloat approx = getApprox(precision); if (approx == null || approx.precision() < precision) { if (denominator().equals(ONE)) { approx = numerator(); } else { precision = Math.max(precision, 1); // In case the requested precision would be zero if (denominator().isShort()) { approx = numerator().precision(precision).divide(denominator()); setApprox(approx); } else { Apfloat inverseDen = getInverseDen(); inverseDen = ApfloatMath.inverseRoot(denominator(), 1, precision, inverseDen); approx = numerator().multiply(inverseDen); setApprox(approx); setInverseDen(inverseDen); } } } return approx; } private Apfloat getApprox(long precision) { return (this.approx == null ? null : this.approx.get()); } private void setApprox(Apfloat approx) { this.approx = new SoftReference<>(approx); } private Apfloat getInverseDen() { return (this.inverseDen == null ? null : this.inverseDen.get()); } private void setInverseDen(Apfloat inverseDen) { this.inverseDen = new SoftReference<>(inverseDen); } private static final long serialVersionUID = -224128535732558313L; private static final long UNDEFINED = 0x8000000000000000L; private Apint numerator; private Apint denominator; private volatile long scale = UNDEFINED; private volatile long size = 0; private transient SoftReference inverseDen = null; private transient SoftReference approx = null; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/AprationalMath.java000066400000000000000000000703501461767713300253150ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import org.apfloat.spi.Util; /** * Various mathematical functions for arbitrary precision rational numbers. * * @version 1.14.0 * @author Mikko Tommila */ public class AprationalMath { private AprationalMath() { } /** * Integer power. * * @param x Base of the power operator. * @param n Exponent of the power operator. * * @return x to the n:th power, that is xn. * * @exception ArithmeticException If both x and n are zero. */ public static Aprational pow(Aprational x, long n) throws ArithmeticException, ApfloatRuntimeException { if (n == 0) { if (x.signum() == 0) { throw new ArithmeticException("Zero to power zero"); } return new Apint(1, x.radix()); } else if (n < 0) { x = Aprational.ONE.divide(x); n = -n; } // Algorithm improvements by Bernd Kellner int b2pow = 0; while ((n & 1) == 0) { b2pow++; n >>>= 1; } Aprational r = x; while ((n >>>= 1) > 0) { x = x.multiply(x); if ((n & 1) != 0) { r = r.multiply(x); } } while (b2pow-- > 0) { r = r.multiply(r); } return r; } /** * Returns an aprational whose value is -x. * * @deprecated Use {@link Aprational#negate()}. * * @param x The argument. * * @return -x. */ @Deprecated public static Aprational negate(Aprational x) throws ApfloatRuntimeException { return x.negate(); } /** * Absolute value. * * @param x The argument. * * @return Absolute value of x. */ public static Aprational abs(Aprational x) throws ApfloatRuntimeException { if (x.signum() >= 0) { return x; } else { return x.negate(); } } /** * Copy sign from one argument to another. * * @param x The value whose sign is to be adjusted. * @param y The value whose sign is to be used. * * @return x with its sign changed to match the sign of y. * * @since 1.1 */ public static Aprational copySign(Aprational x, Aprational y) throws ApfloatRuntimeException { if (y.signum() == 0) { return y; } else if (x.signum() != y.signum()) { return x.negate(); } else { return x; } } /** * Multiply by a power of the radix. * Note that this method is prone to intermediate overflow errors. * Also, scaling by a very large negative number won't result in an * underflow and a zero result, but an overflow of the denominator * and an exception thrown. * * @param x The argument. * @param scale The scaling factor. * * @return x * x.radix()scale. */ public static Aprational scale(Aprational x, long scale) throws ApfloatRuntimeException { if (scale >= 0) { return new Aprational(ApintMath.scale(x.numerator(), scale), x.denominator()); } else if (scale == 0x8000000000000000L) { Apint scaler = ApintMath.pow(new Apint(x.radix(), x.radix()), 0x4000000000000000L); return new Aprational(x.numerator(), x.denominator().multiply(scaler)).divide(scaler); } else { return new Aprational(x.numerator(), ApintMath.scale(x.denominator(), -scale)); } } /** * Rounds the given number to the specified precision with the specified rounding mode. * * @deprecated Use {@link #roundToPrecision(Aprational,long,RoundingMode)}. * * @param x The number to round. * @param precision The precision to round to. * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception IllegalArgumentException If precision is less than zero or zero. * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.7.0 */ @Deprecated public static Apfloat round(Aprational x, long precision, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return roundToPrecision(x, precision, roundingMode); } /** * Rounds the given number to the specified precision with the specified rounding mode. * * @param x The number to round. * @param precision The precision to round to. * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception IllegalArgumentException If precision is less than zero or zero. * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public static Apfloat roundToPrecision(Aprational x, long precision, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return RoundingHelper.roundToPrecision(x, precision, roundingMode); } /** * Rounds x to integer using the specified rounding mode. * * @param x The number to round. * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public static Apint roundToInteger(Aprational x, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return RoundingHelper.roundToInteger(x, roundingMode); } /** * Rounds x to the specified number of places using the specified rounding mode. * * @param x The number to round. * @param places The number of places to round to (in base 10, the number of decimal places). * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public static Apfloat roundToPlaces(Aprational x, long places, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return RoundingHelper.roundToPlaces(x, places, roundingMode); } /** * Rounds x to the nearest multiple of y using the specified rounding mode. * * @param x The number to round. * @param y The integer multiple to round to. * @param roundingMode The rounding mode to use. * * @return The rounded number. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public static Aprational roundToMultiple(Aprational x, Aprational y, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { return RoundingHelper.roundToMultiple(x, y, roundingMode); } /** * Product of numbers. * This method may perform significantly better * than simply multiplying the numbers sequentially.

* * If there are no arguments, the return value is 1. * * @param x The argument(s). * * @return The product of the given numbers. * * @since 1.3 */ public static Aprational product(Aprational... x) throws ApfloatRuntimeException { if (x.length == 0) { return Aprational.ONE; } Apint[] n = new Apint[x.length], m = new Apint[x.length]; for (int i = 0; i < x.length; i++) { if (x[i].signum() == 0) { return Aprational.ZEROS[x[i].radix()]; } n[i] = x[i].numerator(); m[i] = x[i].denominator(); } return new Aprational(ApintMath.product(n), ApintMath.product(m)); } /** * Sum of numbers. * This method may perform significantly better * than simply adding the numbers sequentially.

* * If there are no arguments, the return value is 0. * * @param x The argument(s). * * @return The sum of the given numbers. * * @since 1.3 */ public static Aprational sum(Aprational... x) throws ApfloatRuntimeException { if (x.length == 0) { return Aprational.ZERO; } // Sort by size x = x.clone(); Arrays.sort(x, Comparator.comparing(ApfloatHelper::size)); // Recursively add return recursiveSum(x, 0, x.length - 1); } /** * Generates the first n terms in the continued fraction representation of x.

* * Note that the result length might be less than n, depending on the input value. * * @param x The number whose continued fraction terms should be generated. * @param n The maximum number of terms to generate. * * @return The continued fraction. * * @exception IllegalArgumentException If n is less than one. * * @since 1.12.0 */ public static Apint[] continuedFraction(Aprational x, int n) { if (n <= 0) { throw new IllegalArgumentException("Maximum number of terms is not positive"); } return Util.stream(ContinuedFractionHelper.continuedFraction(x)).limit(n).toArray(Apint[]::new); } /** * Generates the first n convergents corresponding to the continued fraction of x.

* * Note that the result length might be less than n, depending on the input value. * * @param x The number whose continued fraction convergents should be generated. * @param n The maximum number of convergents to generate. * * @return The convergents. * * @exception IllegalArgumentException If n is less than one. * * @since 1.12.0 */ public static Aprational[] convergents(Aprational x, int n) { if (n <= 0) { throw new IllegalArgumentException("Maximum number of convergents is not positive"); } Iterator continuedFraction = ContinuedFractionHelper.continuedFraction(x); return Util.stream(ContinuedFractionHelper.convergents(continuedFraction, x.radix())).limit(n).toArray(Aprational[]::new); } /** * Returns the greater of the two values. * * @param x An argument. * @param y Another argument. * * @return The greater of the two values. * * @since 1.9.0 */ public static Aprational max(Aprational x, Aprational y) throws ApfloatRuntimeException { return (x.compareTo(y) > 0 ? x : y); } /** * Returns the smaller of the two values. * * @param x An argument. * @param y Another argument. * * @return The smaller of the two values. * * @since 1.9.0 */ public static Aprational min(Aprational x, Aprational y) throws ApfloatRuntimeException { return (x.compareTo(y) < 0 ? x : y); } /** * Binomial coefficient. * * @param n The first argument. * @param k The second argument. * * @return * * ( * * n * k * * ) * * * * @throws ArithmeticException If the result is not finite or not a rational number. * * @since 1.11.0 */ public static Aprational binomial(Aprational n, Aprational k) throws ArithmeticException, ApfloatRuntimeException { if (n.isInteger() && k.isInteger()) { return ApintMath.binomial(n.numerator(), k.numerator()); } if (n.isInteger() && n.signum() < 0 && !k.isInteger()) { throw new ArithmeticException("Binomial coefficient is not finite"); } if (!k.isInteger()) { k = n.subtract(k); } if (!k.isInteger()) { throw new ArithmeticException("Binomial coefficient is not a rational number"); } int radix = n.radix(); if (k.signum() < 0) { return Apint.ZEROS[radix]; } Apint one = new Apint(1, radix), f = ApintMath.factorial(ApfloatHelper.longValueExact(k.truncate()), radix); return pochhammer(n.subtract(k).add(one), k.numerator()).divide(f); } /** * Pochhammer symbol.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * The asymptotic complexity is at least O(n2log n) and it is * impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the pochhammer symbol. * * @param x The first argument. * @param n The second argument. * * @return (x)n * * @since 1.13.0 */ public static Aprational pochhammer(Aprational x, Apint n) { Apint one = Apint.ONES[x.radix()]; if (n.signum() == 0) { return one; } if (n.equals(one)) { return x; } if (n.signum() < 0) { return one.divide(pochhammer(x.add(n), n.negate())); } Apint two = new Apint(2, x.radix()); Apint k = n.divide(two); return pochhammer(x, k).multiply(pochhammer(x.add(k), n.subtract(k))); } /** * Returns the specified Bernoulli number. The default radix is used. * * @param n The argument. * * @return The Bernoulli number Bn. * * @throws IllegalArgumentException If n < 0. * * @since 1.11.0 */ public static Aprational bernoulli(long n) throws IllegalArgumentException, ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); int radix = ctx.getDefaultRadix(); return bernoulli(n, radix); } /** * Returns the specified Bernoulli number in the given radix. * * @param n The argument. * @param radix The radix. * * @return The Bernoulli number Bn. * * @throws IllegalArgumentException If n < 0. * @throws NumberFormatException If the radix is not valid. * * @since 1.11.0 */ public static Aprational bernoulli(long n, int radix) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { if (n < 0) { throw new IllegalArgumentException("Negative Bernoulli number: " + n); } if (n == 0) { return Apint.ONES[radix]; } if (n == 1) { return new Aprational(new Apint(-1, radix), new Apint(2, radix)); } if ((n & 1) == 1) { return Apint.ZEROS[radix]; } return (n <= 2000 ? bernoulliSmall(n, radix) : bernoulliBig(n, radix)); } static Aprational bernoulliSmall(long n, int radix) { assert (n > 0); Aprational sum = Aprational.ZERO; for (long k = 1; k <= n; k++) { Apint binomial = new Apint(1, radix); Apint part = Apint.ZERO; for (long v = 1; v <= k; v++) { binomial = binomial.multiply(new Apint(k + 1 - v, radix)).divide(new Apint(v, radix)); Apint term = binomial.multiply(ApintMath.pow(new Apint(v, radix), n)); part = ((v & 1) == 0 ? part.add(term) : part.subtract(term)); } sum = sum.add(new Aprational(part, new Apint(k + 1, radix))); } return sum; // Alternative algorithm that uses more memory but isn't really much faster: // // factorial = factorial.multiply(new Apint(k, radix)); // sum = sum.multiply(new Apint(k + 1, radix)).add(part.multiply(factorial)); // } // return new Aprational(sum, ApintMath.factorial(n + 1, radix)); } static Aprational bernoulliBig(long n, int radix) { // See https://arxiv.org/abs/1108.0286 for the algorithm, Fast computation of Bernoulli, Tangent and Secant numbers by Richard P. Brent, David Harvey assert (n > 1); assert (n & 1) == 0; n >>= 1; Apint one = Apint.ONES[radix], two = new Apint(2, radix); long p = Math.max(1, (long) Math.ceil(n * Math.log(n) / Math.log(radix))), precision = ApfloatHelper.extendPrecision(Util.multiplyExact(Util.multiplyExact(2, n) + 1, p)); // 2 * n * p + 2 is not enough! Apint f2n1 = ApintMath.factorial(2 * n - 1, radix); Apfloat z = ApfloatMath.scale(new Apfloat(1, precision, radix), -p), v = ApfloatMath.scale(f2n1.multiply(ApfloatMath.tan(z)), -p); v = ApfloatMath.scale(v, 2 * p * (n - 1)); v = v.frac(); v = ApfloatMath.scale(v, 2 * p); Apint t = v.truncate(); Apint two2n1 = ApintMath.pow(two, 2 * n - 1), two2n = two2n1.multiply(two); Aprational b = new Aprational(new Apint((n & 1) == 1 ? n : -n, radix).multiply(t), two2n.subtract(one).multiply(two2n1)); return b; } static Iterator bernoullis(long n, int radix) { return (n <= 2000 ? bernoullisSmall(radix) : bernoullisBig(n, radix)); } // Returns the even bernoulli numbers B_2n, n > 0 static Iterator bernoullis2(long n, int radix) { return (n < 1000 ? bernoullis2Small(radix) : bernoullis2Big(n, radix)); } static Iterator bernoullisSmall(int radix) { return new Iterator() { @Override public boolean hasNext() { return true; } @Override public Aprational next() { Aprational b; if (this.n == 0) { b = Aprational.ONES[radix]; } else if (this.n > 1 && (this.n & 1) == 1) { b = Aprational.ZEROS[radix]; } else { b = Aprational.ZEROS[radix]; Iterator iterator = this.all.iterator(); Apint binomial = null; for (long k = 0; iterator.hasNext(); k++) { binomial = (k == 0 ? new Apint(1, radix) : binomial.multiply(new Apint(n + 1 - k, radix)).divide(new Apint(k, radix))); b = b.subtract(binomial.multiply(iterator.next()).divide(new Apint(n - k + 1, radix))); } } this.all.add(b); this.n++; return b; } private long n; private List all = new ArrayList<>(); }; } // Returns the even bernoulli numbers B_2n, n > 0 static Iterator bernoullis2Small(int radix) { return new Iterator() { @Override public boolean hasNext() { return true; } @Override public Aprational next() { this.i.next(); return this.i.next(); } private Iterator i = bernoullisSmall(radix); { this.i.next(); } }; } static Iterator bernoullisBig(long n, int radix) { return new Iterator() { @Override public boolean hasNext() { return this.k <= n; } @Override public Aprational next() { if (this.k > n) { throw new NoSuchElementException(); } Aprational b; if (this.k == 0) { b = Aprational.ONES[radix]; } else if (this.k == 1) { b = new Aprational(new Apint(-1, radix), new Apint(2, radix)); } else if ((this.k & 1) == 1) { b = Aprational.ZEROS[radix]; } else { b = this.i.next(); } this.k++; return b; } private long k; private Iterator i = bernoullis2Big(n >> 1, radix); }; } // Returns the even bernoulli numbers B_2n, n > 0 static Iterator bernoullis2Big(long n, int radix) { Apint one = Apint.ONES[radix], two = new Apint(2, radix); long p = (long) Math.ceil(n * Math.log(n) / Math.log(radix)), precision = ApfloatHelper.extendPrecision(Util.multiplyExact(Util.multiplyExact(2, n) + 1, p)); // 2 * n * p + 2 is not enough! Apint f2n1 = ApintMath.factorial(2 * n - 1, radix); Apfloat z = ApfloatMath.scale(new Apfloat(1, precision, radix), -p); return new Iterator() { @Override public boolean hasNext() { return this.k <= n; } @Override public Aprational next() { if (this.k > n) { throw new NoSuchElementException(); } long k = this.k; this.v = ApfloatMath.scale(this.v, 2 * p); Apint t1 = this.v.truncate(); this.f2k1 = (k == 1 ? this.f2k1 : this.f2k1.multiply(new Apint(2 * k - 1, radix)).multiply(new Apint(2 * k - 2, radix))); Apint t = t1.multiply(this.f2k1).divide(f2n1); this.v = this.v.frac(); this.two2k = this.two2k1.multiply(two); Aprational b = new Aprational(new Apint((k & 1) == 1 ? k : -k, radix).multiply(t), this.two2k.subtract(one).multiply(this.two2k1)); this.two2k1 = this.two2k.multiply(two); this.k++; return b; } private long k = 1; private Apfloat v = ApfloatMath.scale(f2n1.multiply(ApfloatMath.tan(z)), -p); private Apint f2k1 = one, two2k1 = two, two2k; }; } /** * Harmonic number.

* * @param n The argument. * * @return Hn * * @throws ArithmeticException If n is negative. * * @since 1.14.0 */ public static Aprational harmonicNumber(Apint n) throws ArithmeticException, ApfloatRuntimeException { return harmonicNumber(n, Apint.ONES[n.radix()]); } /** * Generalized harmonic number.

* * @param n The first argument. * @param r The second argument. * * @return Hn(r) * * @throws ArithmeticException If n is negative and r is positive. * * @since 1.14.0 */ public static Aprational harmonicNumber(Apint n, Apint r) throws ArithmeticException, ApfloatRuntimeException { if (n.signum() == 0 || r.signum() == 0) { return n; } Apint one = Apint.ONES[n.radix()]; if (n.signum() < 0) { if (r.signum() > 0) { throw new ArithmeticException("Negative harmonic number"); } return harmonicNumber(n.negate().subtract(one), r).negate(); } Apint[] h = harmonicNumber(one, n, ApfloatHelper.longValueExact(r)); return new Aprational(h[0], h[1]); } private static Apint[] harmonicNumber(Apint n, Apint m, long r) throws ArithmeticException, ApfloatRuntimeException { int radix = n.radix(); Apint one = Apint.ONES[radix]; if (n.equals(m)) { if (r >= 0) { Apint[] h = { one, ApintMath.pow(n, r) }; return h; } else { Apint[] h = { ApintMath.pow(n, -r), one }; return h; } } Apint k = n.add(m).divide(new Apint(2, radix)); Apint[] hl = harmonicNumber(n, k, r), hh = harmonicNumber(k.add(one), m, r), h = { hl[0].multiply(hh[1]).add(hl[1].multiply(hh[0])), hl[1].multiply(hh[1]) }; return h; } private static Aprational recursiveSum(Aprational[] x, int n, int m) throws ApfloatRuntimeException { if (n == m) { return x[n]; } else { int k = (n + m) >>> 1; return recursiveSum(x, n, k).add(recursiveSum(x, k + 1, m)); } } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/BesselHelper.java000066400000000000000000000211031461767713300247560ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import java.util.function.BiFunction; import org.apfloat.spi.Util; import static org.apfloat.ApcomplexMath.cos; import static org.apfloat.ApcomplexMath.exp; import static org.apfloat.ApcomplexMath.hypergeometric0F1Regularized; import static org.apfloat.ApcomplexMath.pow; import static org.apfloat.ApcomplexMath.sin; import static org.apfloat.ApfloatMath.pi; import static org.apfloat.ApfloatMath.scale; import static org.apfloat.ApfloatMath.sqrt; /** * Helper class for Bessel functions. * * @since 1.13.0 * @version 1.14.0 * @author Mikko Tommila */ class BesselHelper { /** * Helper for Bessel functions.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the functions. * * @param ν The first argument. * @param z The second argument. */ private BesselHelper(Apcomplex ν, Apcomplex z) { this.radix = z.radix(); this.targetPrecision = Math.min(ν.precision(), z.precision()); this.workingPrecision = ApfloatHelper.extendPrecision(targetPrecision, ApfloatHelper.getSmallExtraPrecision(radix)); this.ν = ensurePrecision(ν); this.z = ensurePrecision(z); this.two = new Apint(2, radix); } public static Apcomplex besselJ(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return new BesselHelper(ν, z).besselJ(); } public static Apcomplex besselI(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return new BesselHelper(ν, z).besselI(); } public static Apcomplex besselY(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return new BesselHelper(ν, z).besselY(); } public static Apcomplex besselK(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return new BesselHelper(ν, z).besselK(); } private Apcomplex besselJ() throws ArithmeticException, ApfloatRuntimeException { Apcomplex result = besselJ(ν); return ApfloatHelper.reducePrecision(result, ApfloatHelper.getSmallExtraPrecision(radix)); } private Apcomplex besselI() throws ArithmeticException, ApfloatRuntimeException { Apcomplex result = besselI(ν); return ApfloatHelper.reducePrecision(result, ApfloatHelper.getSmallExtraPrecision(radix)); } private Apcomplex besselJ(Apcomplex ν) throws ArithmeticException, ApfloatRuntimeException { return besselFirstKind(ν, true); } private Apcomplex besselI(Apcomplex ν) throws ArithmeticException, ApfloatRuntimeException { return besselFirstKind(ν, false); } private Apcomplex besselFirstKind(Apcomplex ν, boolean negate) throws ArithmeticException, ApfloatRuntimeException { if (ν.isInteger() && z.isZero()) { return (ν.real().signum() == 0 ? Apint.ONES[radix] : z); } Apfloat one = Apint.ONES[radix].precision(ApfloatHelper.extendPrecision(workingPrecision, 1)); Apcomplex z2 = z.divide(two), z24 = z2.multiply(z2); return pow(z2, ν).multiply(hypergeometric0F1Regularized(ensurePrecision(ν.add(one)), negate ? z24.negate() : z24)); } private Apcomplex besselY() throws ArithmeticException, ApfloatRuntimeException { if (z.isZero()) { throw new ArithmeticException("Bessel Y of zero"); } return besselSecondKind((ν, z) -> { Apcomplex piν = pi(workingPrecision, radix).multiply(ν); return besselJ(ν).multiply(cos(piν)).subtract(besselJ(ν.negate())).divide(sin(piν)); }); } private Apcomplex besselK() throws ArithmeticException, ApfloatRuntimeException { if (z.isZero()) { throw new ArithmeticException("Bessel K of zero"); } Apint one = Apint.ONES[radix]; Apfloat half = one.precision(workingPrecision).divide(two); Apcomplex ν12 = ensurePrecision(ν.add(half)), ν21 = ensurePrecision(two.multiply(ν).add(one)), z2 = two.multiply(z), u = HypergeometricHelper.hypergeometricU(ν12, ν21, z2, true); if (u != null) { Apfloat pi = pi(workingPrecision, radix); Apcomplex result = sqrt(pi).multiply(pow(z2, ν)).multiply(exp(z.negate())).multiply(u); return ApfloatHelper.limitPrecision(result, targetPrecision); } return besselSecondKind((ν, z) -> { Apfloat pi = pi(workingPrecision, radix); return besselI(ν.negate()).subtract(besselI(ν)).multiply(pi).divide(sin(pi.multiply(ν)).multiply(two)); }); } private Apcomplex besselSecondKind(BiFunction f) throws ArithmeticException, ApfloatRuntimeException { // First check if ν is an integer or near-integer and adjust if necessary if (ν.isInteger()) { long digitLoss = workingPrecision; workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); Apfloat offset = offset(-digitLoss); ν = new Apcomplex(ν.real().precision(Apfloat.INFINITE).add(offset), ν.imag()); } else { Apint νRounded = RoundingHelper.roundToInteger(ν.real(), RoundingMode.HALF_EVEN).truncate(); long digitLoss = Math.min(workingPrecision, -ν.subtract(νRounded).scale()); if (digitLoss > 0) { workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); } } // Evaluate two other Bessel functions, this often results in cancellation of significant digits so we may retry with higher precision Apcomplex result; long precisionLoss; do { ν = ensurePrecision(ν); z = ensurePrecision(z); result = f.apply(ν, z); if (result.isZero()) // The result shouldn't be exactly zero, it means full loss of significant digits { precisionLoss = workingPrecision; } else { precisionLoss = targetPrecision - result.precision(); } workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + precisionLoss); } while (precisionLoss > 0); return ApfloatHelper.limitPrecision(result, targetPrecision); } private Apfloat offset(long scale) { Apfloat offset = scale(new Apfloat("0.1", workingPrecision, radix), scale); return offset; } private Apcomplex ensurePrecision(Apcomplex z) { return ApfloatHelper.ensurePrecision(z, workingPrecision); } private long targetPrecision, workingPrecision; private int radix; private Apcomplex ν, z; private Apint two; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ConcurrentSoftHashMap.java000066400000000000000000000052101461767713300266220ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.lang.ref.SoftReference; import java.util.AbstractMap; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * Map with an underlying ConcurrentHashMap with softly referenced values. * The maximum map size is assumed to be limited so no effort is made to * expunge entries for stale values. * * @since 1.6 * @version 1.9.0 * @author Mikko Tommila */ class ConcurrentSoftHashMap extends AbstractMap { private ConcurrentHashMap> map; public ConcurrentSoftHashMap() { this.map = new ConcurrentHashMap<>(); } @Override public void clear() { this.map.clear(); } @Override public Set> entrySet() { throw new UnsupportedOperationException(); } @Override public V get(Object key) { return unwrap(this.map.get(key)); } @Override public V put(K key, V value) { return unwrap(this.map.put(key, wrap(value))); } @Override public V remove(Object key) { return unwrap(this.map.remove(key)); } @Override public int size() { return this.map.size(); } private SoftReference wrap(V value) { return new SoftReference<>(value); } private V unwrap(SoftReference value) { return (value == null ? null : value.get()); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ConcurrentWeakHashMap.java000066400000000000000000000100521461767713300265760ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.AbstractMap; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * Combination of WeakHashMap and ConcurrentHashMap, * providing weak keys and non-blocking access. * * @since 1.5 * @version 1.9.0 * @author Mikko Tommila */ class ConcurrentWeakHashMap extends AbstractMap { private static class Key extends WeakReference { private int hashCode; public Key(Object key, ReferenceQueue queue) { super(key, queue); this.hashCode = key.hashCode(); } @Override public int hashCode() { return this.hashCode; } @Override public boolean equals(Object obj) { if (this == obj) { // Always matches even if referenced object has been garbage collected, needed for expunging garbage collected keys return true; } if (obj instanceof Key) { Key that = (Key) obj; Object value = get(); return (value != null && value.equals(that.get())); } return false; } } private ConcurrentHashMap map; private ReferenceQueue queue; public ConcurrentWeakHashMap() { this.map = new ConcurrentHashMap<>(); this.queue = new ReferenceQueue<>(); } @Override public void clear() { expungeStaleEntries(); this.map.clear(); } @Override public Set> entrySet() { throw new UnsupportedOperationException(); } @Override public V get(Object key) { // Do not expunge stale entries here to improve performance return this.map.get(wrap(key)); } @Override public V put(K key, V value) { expungeStaleEntries(); return this.map.put(wrap(key), value); } @Override public V remove(Object key) { expungeStaleEntries(); return this.map.remove(wrap(key)); } @Override public boolean isEmpty() { // This is for the quick check, therefore we do not expunge stale entries here return this.map.isEmpty(); } @Override public int size() { expungeStaleEntries(); return this.map.size(); } private Key wrap(Object key) { return new Key(key, this.queue); } private void expungeStaleEntries() { // Should not cause (much) blocking Key key; while ((key = (Key) this.queue.poll()) != null) { this.map.remove(key); } } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ContinuedFractionHelper.java000066400000000000000000000107641461767713300271720ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.Iterator; import java.util.NoSuchElementException; /** * Helper class for continued fractions. * * @since 1.12.0 * @version 1.12.0 * @author Mikko Tommila */ class ContinuedFractionHelper { private static abstract class ContinuedFractionIterator implements Iterator { public ContinuedFractionIterator(T x) { this.i = x.truncate(); this.f = subtract(x, i); } @Override public boolean hasNext() { return this.i != null; } @Override public Apint next() { if (!hasNext()) { throw new NoSuchElementException(); } Apint next = this.i; if (this.f.signum() == 0) { this.i = null; } else { T x = inverse(this.f); this.i = x.truncate(); this.f = subtract(x, i); } return next; } protected abstract T subtract(T x, Apint y); protected abstract T inverse(T x); private Apint i; private T f; } private ContinuedFractionHelper() { } public static Iterator continuedFraction(Apfloat x) throws ApfloatRuntimeException { return new ContinuedFractionIterator(x) { @Override protected Apfloat subtract(Apfloat x, Apint y) { return x.subtract(y); } @Override protected Apfloat inverse(Apfloat x) { return ApfloatMath.inverseRoot(x, 1); } }; } public static Iterator continuedFraction(Aprational x) throws ApfloatRuntimeException { return new ContinuedFractionIterator(x) { @Override protected Aprational subtract(Aprational x, Apint y) { return x.subtract(y); } @Override protected Aprational inverse(Aprational x) { return Aprational.ONE.divide(x); } }; } public static Iterator convergents(Iterator continuedFraction, int radix) { return new Iterator() { @Override public boolean hasNext() { return continuedFraction.hasNext(); } @Override public Aprational next() { Apint a = continuedFraction.next(), numerator = a.multiply(h1).add(h2), denominator = a.multiply(k1).add(k2); this.h2 = this.h1; this.k2 = this.k1; this.h1 = numerator; this.k1 = denominator; return new Aprational(numerator, denominator); } private Apint h1 = Apint.ONES[radix], h2 = Apint.ZEROS[radix], k1 = Apint.ZEROS[radix], k2 = Apint.ONES[radix]; }; } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/EulerHelper.java000066400000000000000000000130301461767713300246150ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import org.apfloat.ApfloatMath.ApfloatHolder; /** * Helper class for computing the Euler gamma using binary splitting and the Brent-McMillan formula. * * @since 1.11.0 * @version 1.11.0 * @author Mikko Tommila */ class EulerHelper { // See http://www.numberworld.org/y-cruncher/internals/binary-splitting-library.html#eulergamma_bm_ab // See https://www.ginac.de/CLN/binsplit.pdf private EulerHelper(Apfloat n2, long precision, int radix) throws ApfloatRuntimeException { this.n2 = n2; this.precision = precision; this.radix = radix; } public static Apfloat euler(long precision, int radix) throws ApfloatRuntimeException { ApfloatHolder Q = new ApfloatHolder(), R = new ApfloatHolder(), S = new ApfloatHolder(), U = new ApfloatHolder(); long workingPrecision = ApfloatHelper.extendPrecision(precision), n = ApfloatHelper.extendPrecision((long) (precision * Math.log(radix) / 4)), terms = (long) (ALPHA * n); Apfloat nn = new Apfloat(n, workingPrecision, radix), n2 = nn.multiply(nn); new EulerHelper(n2, workingPrecision, radix).euler(0, terms, null, Q, R, S, null, U, null); return U.getApfloat().divide(Q.getApfloat().multiply(R.getApfloat().add(S.getApfloat()))).subtract(ApfloatMath.log(nn)).precision(precision); } private void euler(long a, long b, ApfloatHolder P, ApfloatHolder Q, ApfloatHolder R, ApfloatHolder S, ApfloatHolder T, ApfloatHolder U, ApfloatHolder V) throws ApfloatRuntimeException { assert (a < b); if (b - a == 1) { Apfloat bb = new Apfloat(b, this.precision, this.radix); Apfloat b2 = bb.multiply(bb); if (P != null) { P.setApfloat(new Apfloat(1, this.precision, this.radix)); } Q.setApfloat(bb); R.setApfloat(this.n2); S.setApfloat(b2); if (T != null) { T.setApfloat(this.n2); } U.setApfloat(this.n2); if (V != null) { V.setApfloat(b2.multiply(bb)); } } else { long m = a + b >>> 1; ApfloatHolder LP = new ApfloatHolder(), LQ = new ApfloatHolder(), LR = new ApfloatHolder(), LS = new ApfloatHolder(), LT = new ApfloatHolder(), LU = new ApfloatHolder(), LV = new ApfloatHolder(), RP = new ApfloatHolder(), RQ = new ApfloatHolder(), RR = new ApfloatHolder(), RS = new ApfloatHolder(), RT = new ApfloatHolder(), RU = new ApfloatHolder(), RV = new ApfloatHolder(); euler(a, m, LP, LQ, LR, LS, LT, LU, V != null ? LV : null); euler(m, b, P != null ? RP : null, RQ, RR, RS, T != null ? RT : null, RU, RV); if (P != null) { P.setApfloat(LP.getApfloat().multiply(RQ.getApfloat()).add(LQ.getApfloat().multiply(RP.getApfloat()))); } Q.setApfloat(LQ.getApfloat().multiply(RQ.getApfloat())); R.setApfloat(LR.getApfloat().multiply(RS.getApfloat()).add(LT.getApfloat().multiply(RR.getApfloat()))); S.setApfloat(LS.getApfloat().multiply(RS.getApfloat())); if (T != null) { T.setApfloat(LT.getApfloat().multiply(RT.getApfloat())); } U.setApfloat(LU.getApfloat().multiply(RV.getApfloat()).add(LP.getApfloat().multiply(LT.getApfloat()).multiply(RQ.getApfloat()).multiply(RR.getApfloat())).add(LQ.getApfloat().multiply(LT.getApfloat()).multiply(RU.getApfloat()))); if (V != null) { V.setApfloat(LV.getApfloat().multiply(RV.getApfloat())); } } } private static final double ALPHA = 3.5911214766686221; // 1 / W(1 / e) private final Apfloat n2; private final long precision; private final int radix; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/FixedPrecisionApcomplexHelper.java000066400000000000000000001700021461767713300303300ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import org.apfloat.spi.Util; /** * Fixed-precision mathematical functions for complex numbers.

* * All results of the mathematical operations are set to have the specified precision. * Also all input arguments are set to the specified precision before the operation. * If the specified precision is not infinite, this helper class also avoids * InfiniteExpansionException e.g. in case where it would happen with * ApcomplexMath.acos(Apcomplex.ZERO). * * @since 1.5 * @version 1.14.0 * @author Mikko Tommila */ public class FixedPrecisionApcomplexHelper { /** * Constructs an apcomplex fixed-precison helper with the specified precision. * The results of all mathematical operations are set to the specified precision. * * @param precision The precision of the results. * * @exception IllegalArgumentException In case the precision is invalid. */ public FixedPrecisionApcomplexHelper(long precision) throws IllegalArgumentException { ApfloatHelper.checkPrecision(precision); this.precision = precision; } /** * Returns the value with the specified precision. * * @param z The value. * * @return The value with to the specified precision. */ public Apcomplex valueOf(Apcomplex z) throws ApfloatRuntimeException { return z.precision(precision()); } /** * Negation. * * @param z The value to negate. * * @return -z. */ public Apcomplex negate(Apcomplex z) throws ApfloatRuntimeException { return valueOf(z).negate(); } /** * Complex conjugate. * * @param z The operand. * * @return x - i y where z is x + i y. */ public Apcomplex conj(Apcomplex z) throws ApfloatRuntimeException { return valueOf(z).conj(); } /** * Addition. * * @param z The first operand. * @param w The second operand. * * @return z + w. */ public Apcomplex add(Apcomplex z, Apcomplex w) throws ApfloatRuntimeException { return valueOf(setPrecision(z).add(setPrecision(w))); } /** * Subtraction. * * @param z The first operand. * @param w The second operand. * * @return z - w. */ public Apcomplex subtract(Apcomplex z, Apcomplex w) throws ApfloatRuntimeException { return valueOf(setPrecision(z).subtract(setPrecision(w))); } /** * Multiplication. * * @param z The first operand. * @param w The second operand. * * @return z * w. */ public Apcomplex multiply(Apcomplex z, Apcomplex w) throws ApfloatRuntimeException { return valueOf(setPrecision(z).multiply(setPrecision(w))); } /** * Division. * * @param z The first operand. * @param w The second operand. * * @return z / w. * * @exception ArithmeticException If w is zero. */ public Apcomplex divide(Apcomplex z, Apcomplex w) throws ArithmeticException, ApfloatRuntimeException { return valueOf(setPrecision(z).divide(setPrecision(w))); } /** * Power. * * @param z The first operand. * @param w The second operand. * * @return zw. * * @exception ArithmeticException If z and w are zero. */ public Apcomplex pow(Apcomplex z, Apcomplex w) throws ArithmeticException, ApfloatRuntimeException { Apcomplex result = ApfloatHelper.checkPow(z, w, precision()); if (result != null) { return valueOf(result); } return exp(multiply(log(z), w)); } /** * Integer power. * * @param z The first operand. * @param n The first operand. * * @return zn. * * @exception ArithmeticException If z and n are zero, or z is zero and n is negative. */ public Apcomplex pow(Apcomplex z, long n) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.pow(setPrecision(z), n)); } /** * Complex angle. * * @param z The operand. * * @return The angle of z on the complex plane. * * @exception ArithmeticException If z is zero. */ public Apfloat arg(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.arg(setPrecision(z))); } /** * Imaginary part. * * @param z The operand. * * @return The imaginary part of z. */ public Apfloat imag(Apcomplex z) { return valueOf(z.imag()); } /** * Real part. * * @param z The operand. * * @return The real part of z. */ public Apfloat real(Apcomplex z) { return valueOf(z.real()); } /** * Absolute value. * * @param z The operand. * * @return The absolute value of z. */ public Apfloat abs(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.abs(setPrecision(z))); } /** * Norm. * * @param z The operand. * * @return x2 + y2 where z is x + i y. */ public Apfloat norm(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.norm(setPrecision(z))); } /** * Arc cosine. * * @param z The operand. * * @return The arc cosine of z. */ public Apcomplex acos(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.acos(setPrecision(z), precision())); } /** * Hyperbolic arc cosine. * * @param z The operand. * * @return The hyperbolic arc cosine of z. */ public Apcomplex acosh(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.acosh(setPrecision(z), precision())); } /** * Arc sine. * * @param z The operand. * * @return The arc sine of z. */ public Apcomplex asin(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.asin(setPrecision(z))); } /** * Hyperbolic arc sine. * * @param z The operand. * * @return The hyperbolic arc sine of z. */ public Apcomplex asinh(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.asinh(setPrecision(z))); } /** * Arc tangent. * * @param z The operand. * * @return The arc tangent of z. * * @exception ArithmeticException If z is i. */ public Apcomplex atan(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.atan(setPrecision(z))); } /** * Hyperbolic arc tangent. * * @param z The operand. * * @return The hyperbolic arc tangent of z. * * @exception ArithmeticException If z is 1 or -1. */ public Apcomplex atanh(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.atanh(setPrecision(z))); } /** * Cube root. * * @param z The operand. * * @return The cube root of z. */ public Apcomplex cbrt(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.cbrt(setPrecision(z))); } /** * Cosine. * * @param z The operand. * * @return The cosine of z. */ public Apcomplex cos(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.cos(setTrigExpPrecision(z))); } /** * Hyperbolic cosine. * * @param z The operand. * * @return The hyperbolic cosine of z. */ public Apcomplex cosh(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.cosh(setExpTrigPrecision(z))); } /** * Exponential function. * * @param z The operand. * * @return ez. */ public Apcomplex exp(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.exp(setExpTrigPrecision(z))); } /** * Natural logarithm. * * @param z The operand. * * @return The natural logarithm of z. * * @exception ArithmeticException If z is zero. */ public Apcomplex log(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.log(setLogarithmicPrecision(z))); } /** * Logarithm in specified base. * * @param z The operand. * @param w The base. * * @return The base-w logarithm of z. * * @exception ArithmeticException If z or w is zero. * * @since 1.6 */ public Apcomplex log(Apcomplex z, Apcomplex w) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.log(setPrecision(z), setPrecision(w))); } /** * Sine. * * @param z The operand. * * @return The sine of z. */ public Apcomplex sin(Apcomplex z) throws ApfloatRuntimeException { Apcomplex result = checkSmallLinear(z); if (result != null) { return result; } return valueOf(ApcomplexMath.sin(setTrigExpPrecision(z))); } /** * Hyperbolic sine. * * @param z The operand. * * @return The hyperbolic sine of z. */ public Apcomplex sinh(Apcomplex z) throws ApfloatRuntimeException { Apcomplex result = checkSmallLinear(z); if (result != null) { return result; } return valueOf(ApcomplexMath.sinh(setExpTrigPrecision(z))); } /** * Square root. * * @param z The operand. * * @return The square root of z. */ public Apcomplex sqrt(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.sqrt(setPrecision(z))); } /** * Tangent. * * @param z The operand. * * @return The tangent of z. * * @exception ArithmeticException If z is π/2 + n π where n is an integer. */ public Apcomplex tan(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { Apcomplex result = checkSmallLinear(z); if (result != null) { return result; } return valueOf(ApcomplexMath.tanFixedPrecision(setTrigExpPrecision(z))); } /** * Hyperbolic tangent. * * @param z The operand. * * @return The hyperbolic tangent of z. * * @exception ArithmeticException If z is i (π/2 + n π) where n is an integer. */ public Apcomplex tanh(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { Apcomplex result = checkSmallLinear(z); if (result != null) { return result; } return valueOf(ApcomplexMath.tanhFixedPrecision(setExpTrigPrecision(z))); } /** * Sinc. * * @param z The argument. * * @return sinc(z) * * @since 1.14.0 */ public Apcomplex sinc(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.sinc(setTrigExpPrecision(z))); } /** * Arithmetic-geometric mean. * * @param a The first operand. * @param b The first operand. * * @return The arithmetic-geometric mean of a and b. */ public Apcomplex agm(Apcomplex a, Apcomplex b) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.agm(setPrecision(a), setPrecision(b))); } /** * Inverse root. * * @param z The operand. * @param n Which inverse root to take. * * @return z-1/n. * * @exception ArithmeticException If z or n is zero. */ public Apcomplex inverseRoot(Apcomplex z, long n) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.inverseRoot(setPrecision(z), n)); } /** * Inverse root with branch. * * @param z The operand. * @param n Which inverse root to take. * @param k Which branch to take. * * @return z-1/ne-i2πk/n. * * @exception ArithmeticException If z or n is zero. */ public Apcomplex inverseRoot(Apcomplex z, long n, long k) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.inverseRoot(setPrecision(z), n, k)); } /** * Root. * * @param z The operand. * @param n Which root to take. * * @return z1/n. * * @exception ArithmeticException If n is zero, or z is zero and n is negative. */ public Apcomplex root(Apcomplex z, long n) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.root(setPrecision(z), n)); } /** * Root with branch. * * @param z The operand. * @param n Which root to take. * @param k Which branch to take. * * @return z1/nei2πsk/n where s is the signum of the imaginary part of z. * * @exception ArithmeticException If n is zero, or z is zero and n is negative. */ public Apcomplex root(Apcomplex z, long n, long k) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.root(setPrecision(z), n, k)); } /** * All branches of a root. * * @param z The operand. * @param n Which root to take. * * @return z1/n. * * @exception ArithmeticException If n is zero, or z is zero and n is negative. */ public Apcomplex[] allRoots(Apcomplex z, int n) throws ArithmeticException, ApfloatRuntimeException { Apcomplex[] allRoots = ApcomplexMath.allRoots(setPrecision(z), n); for (int i = 0; i < allRoots.length; i++) { allRoots[i] = valueOf(allRoots[i]); } return allRoots; } /** * Move the radix point. * * @param z The operand. * @param scale The amount to move the radix point. * * @return z * z.radix()scale. */ public Apcomplex scale(Apcomplex z, long scale) throws ApfloatRuntimeException { return ApcomplexMath.scale(valueOf(z), scale); } /** * Lambert W function. * * @param z The operand. * * @return W0(z). * * @since 1.8.0 */ public Apcomplex w(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.w(setPrecision(z))); } /** * Lambert W function for the specified branch. * * @param z The operand. * @param k The branch. * * @return Wk(z). * * @since 1.8.0 */ public Apcomplex w(Apcomplex z, long k) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.w(setPrecision(z), k)); } /** * Product. * * @param z The operand(s). * * @return The product of the operands. */ public Apcomplex product(Apcomplex... z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.product(setPrecision(z))); } /** * Sum. * * @param z The operand(s). * * @return The sum of the operands. */ public Apcomplex sum(Apcomplex... z) throws ApfloatRuntimeException { // This is not entirely optimal as the real and imaginary parts might have different scales and one of them could have thus reduced precision return valueOf(ApcomplexMath.sum(setPrecision(z))); } /** * e. * * @return e. * * @since 1.11.0 */ public Apfloat e() throws ApfloatRuntimeException { return ApfloatMath.e(precision()); } /** * e. * * @param radix The radix of the result. * * @return e. * * @throws NumberFormatException If the radix is invalid. * * @since 1.11.0 */ public Apfloat e(int radix) throws NumberFormatException, ApfloatRuntimeException { return ApfloatMath.e(precision(), radix); } /** * γ, the Euler-Mascheroni constant. * * @return γ. * * @since 1.11.0 */ public Apfloat euler() throws ApfloatRuntimeException { return ApfloatMath.euler(precision()); } /** * γ, the Euler-Mascheroni constant. * * @param radix The radix of the result. * * @return γ. * * @throws NumberFormatException If the radix is invalid. * * @since 1.11.0 */ public Apfloat euler(int radix) throws NumberFormatException, ApfloatRuntimeException { return ApfloatMath.euler(precision(), radix); } /** * Catalan's constant G. * * @return G. * * @since 1.11.0 */ public Apfloat catalan() throws ApfloatRuntimeException { return ApfloatMath.catalan(precision()); } /** * Catalan's constant G. * * @param radix The radix of the result. * * @return G. * * @throws NumberFormatException If the radix is invalid. * * @since 1.11.0 */ public Apfloat catalan(int radix) throws NumberFormatException, ApfloatRuntimeException { return ApfloatMath.catalan(precision(), radix); } /** * The Glaisher-Kinkelin constant A. * * @return A. * * @since 1.11.0 */ public Apfloat glaisher() throws ApfloatRuntimeException { return ApfloatMath.glaisher(precision()); } /** * The Glaisher-Kinkelin constant A. * * @param radix The radix of the result. * * @return A. * * @throws NumberFormatException If the radix is invalid. * * @since 1.11.0 */ public Apfloat glaisher(int radix) throws NumberFormatException, ApfloatRuntimeException { return ApfloatMath.glaisher(precision(), radix); } /** * Khinchin's constant K. * * @return K. * * @since 1.11.0 */ public Apfloat khinchin() throws ApfloatRuntimeException { return ApfloatMath.khinchin(precision()); } /** * Khinchin's constant K. * * @param radix The radix of the result. * * @return K. * * @throws NumberFormatException If the radix is invalid. * * @since 1.11.0 */ public Apfloat khinchin(int radix) throws NumberFormatException, ApfloatRuntimeException { return ApfloatMath.khinchin(precision(), radix); } /** * Gamma function. * * @param z The operand. * * @return Γ(z). * * @throws ArithmeticException If z is a nonpositive integer. * * @since 1.9.0 */ public Apcomplex gamma(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.gamma(setGammaPrecision(z))); } /** * Incomplete gamma function. * * @param a The first operand. * @param z The second operand. * * @return Γ(a, z). * * @throws ArithmeticException If a is a nonpositive integer and z is zero. * * @since 1.10.0 */ public Apcomplex gamma(Apcomplex a, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.gamma(setGammaPrecision(a), setPrecision(z))); } /** * Generalized incomplete gamma function. * * @param a The first operand. * @param z0 The second operand. * @param z1 The third operand. * * @return Γ(a, z0) - Γ(a, z1). * * @throws ArithmeticException If a is a nonpositive integer and either z0 or z1 is zero. * * @since 1.10.0 */ public Apcomplex gamma(Apcomplex a, Apcomplex z0, Apcomplex z1) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.gamma(setGammaPrecision(a), setPrecision(z0), setPrecision(z1))); } /** * Logarithm of the gamma function. * * @param z The argument. * * @return logΓ(z) * * @throws ArithmeticException If z is a nonpositive integer. * * @since 1.11.0 */ public Apcomplex logGamma(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.logGamma(setPrecision(z))); } /** * Digamma function. * * @param z The argument. * * @return ψ(z) * * @throws ArithmeticException If z is a nonpositive integer. * * @since 1.11.0 */ public Apcomplex digamma(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.digamma(setPrecision(z))); } /** * Polygamma function. * * @param n The order. * @param z The argument. * * @return ψ(n)(z) * * @throws ArithmeticException If n is negative or z is a nonpositive integer. * * @since 1.13.0 */ public Apcomplex polygamma(long n, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.polygamma(n, setPrecision(z))); } /** * Beta function. * * @param a The first argument. * @param b The second argument. * * @return B(a, b) * * @throws ArithmeticException If a or b is a nonpositive integer but a + b is not. Also if both a and b are nonpositive integers. * * @since 1.13.0 */ public Apcomplex beta(Apcomplex a, Apcomplex b) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.beta(setPrecision(a), setPrecision(b))); } /** * Incomplete beta function. * * @param z The first argument. * @param a The second argument. * @param b The third argument. * * @return Bz(a, b) * * @throws ArithmeticException If a is a nonpositive integer or z is zero and a has nonpositive real part. * * @since 1.13.0 */ public Apcomplex beta(Apcomplex z, Apcomplex a, Apcomplex b) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.beta(setPrecision(z), setPrecision(a), setPrecision(b))); } /** * Generalized incomplete beta function. * * @param z1 The first argument. * @param z2 The second argument. * @param a The third argument. * @param b The fourth argument. * * @return B(z1, z2)(a, b) * * @throws ArithmeticException If a is a nonpositive integer or z1 or z2 is zero and a has nonpositive real part. * * @since 1.13.0 */ public Apcomplex beta(Apcomplex z1, Apcomplex z2, Apcomplex a, Apcomplex b) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.beta(setPrecision(z1), setPrecision(z2), setPrecision(a), setPrecision(b))); } /** * Pochhammer symbol. * * @param z The first argument. * @param n The second argument. * * @return (z)n * * @throws ArithmeticException If z + n is a nonpositive integer but z is not. * * @since 1.13.0 */ public Apcomplex pochhammer(Apcomplex z, Apcomplex n) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.pochhammer(setPrecision(z), setPrecision(n))); } /** * Binomial coefficient. * * @param n The argument. * @param k The argument. * * @return The binomial coefficient. * * @throws ArithmeticException If n or k is negative. * * @since 1.11.0 */ public Apfloat binomial(long n, long k) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApintMath.binomial(n, k)); } /** * Binomial coefficient. * * @param n The argument. * @param k The argument. * @param radix The radix. * * @return The binomial coefficient. * * @throws ArithmeticException If n or k is negative. * @throws NumberFormatException If the radix is not valid. * * @since 1.11.0 */ public Apfloat binomial(long n, long k, int radix) throws ArithmeticException, NumberFormatException, ApfloatRuntimeException { return valueOf(ApintMath.binomial(n, k, radix)); } /** * Binomial coefficient. * * @param n The argument. * @param k The argument. * * @return The binomial coefficient. * * @throws ArithmeticException If n, k or n - k is a nonpositive integer. * * @since 1.11.0 */ public Apcomplex binomial(Apcomplex n, Apcomplex k) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.binomial(setGammaPrecision(n), setGammaPrecision(k))); } /** * Bernoulli number. * * @param n The argument. * * @return Bn * * @throws IllegalArgumentException If n < 0. * * @since 1.11.0 */ public Apfloat bernoulli(long n) throws IllegalArgumentException, ApfloatRuntimeException { return valueOf(AprationalMath.bernoulli(n)); } /** * Bernoulli number. * * @param n The argument. * @param radix The radix. * * @return Bn * * @throws IllegalArgumentException If n < 0. * @throws NumberFormatException If the radix is not valid. * * @since 1.11.0 */ public Apfloat bernoulli(long n, int radix) throws IllegalArgumentException, NumberFormatException, ApfloatRuntimeException { return valueOf(AprationalMath.bernoulli(n, radix)); } /** * Riemann zeta function. * * @param s The argument. * * @return ζ(s) * * @throws ArithmeticException If s is 1. * * @since 1.11.0 */ public Apcomplex zeta(Apcomplex s) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.zeta(setZetaPrecision(s))); } /** * Hurwitz zeta function. * * @param s The first argument. * @param a The second argument. * * @return ζ(s, a) * * @throws ArithmeticException If s is 1 or if a is a nonpositive integer. * * @since 1.11.0 */ public Apcomplex zeta(Apcomplex s, Apcomplex a) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.zeta(setZetaPrecision(s), setPrecision(a))); } /** * Confluent hypergeometric function 0F1. * * @param a The first argument. * @param z The second argument. * * @return 0F1(; a; z) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public Apcomplex hypergeometric0F1(Apcomplex a, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.hypergeometric0F1(setPrecision(a), setPrecision(z))); } /** * Regularized confluent hypergeometric function 01. * * @param a The first argument. * @param z The second argument. * * @return 01(; a; z) * * @since 1.13.0 */ public Apcomplex hypergeometric0F1Regularized(Apcomplex a, Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.hypergeometric0F1Regularized(setPrecision(a), setPrecision(z))); } /** * Kummer confluent hypergeometric function 1F1. * * @param a The first argument. * @param b The second argument. * @param z The third argument. * * @return 1F1(a; b; z) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public Apcomplex hypergeometric1F1(Apcomplex a, Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.hypergeometric1F1(setPrecision(a), setPrecision(b), setPrecision(z))); } /** * Regularized Kummer confluent hypergeometric function 11. * * @param a The first argument. * @param b The second argument. * @param z The third argument. * * @return 11(a; b; z) * * @since 1.13.0 */ public Apcomplex hypergeometric1F1Regularized(Apcomplex a, Apcomplex b, Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.hypergeometric1F1Regularized(setPrecision(a), setPrecision(b), setPrecision(z))); } /** * Hypergeometric function 2F1. * * @param a The first argument. * @param b The second argument. * @param c The third argument. * @param z The fourth argument. * * @return 2F1(a, b; c; z) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public Apcomplex hypergeometric2F1(Apcomplex a, Apcomplex b, Apcomplex c, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.hypergeometric2F1(setPrecision(a), setPrecision(b), setPrecision(c), setPrecision(z))); } /** * Regularized hypergeometric function 21. * * @param a The first argument. * @param b The second argument. * @param c The third argument. * @param z The fourth argument. * * @return 21(a, b; c; z) * * @since 1.13.0 */ public Apcomplex hypergeometric2F1Regularized(Apcomplex a, Apcomplex b, Apcomplex c, Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.hypergeometric2F1Regularized(setPrecision(a), setPrecision(b), setPrecision(c), setPrecision(z))); } /** * Tricomi's confluent hypergeometric function U. * * @param a The first argument. * @param b The second argument. * @param z The third argument. * * @return U(a, b, z) * * @throws ArithmeticException If the result is not finite. * * @since 1.13.0 */ public Apcomplex hypergeometricU(Apcomplex a, Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.hypergeometricU(setPrecision(a), setPrecision(b), setPrecision(z))); } /** * Error function. * * @param z The argument. * * @return erf(z) * * @since 1.13.0 */ public Apcomplex erf(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.erfFixedPrecision(setErfPrecision(z))); } /** * Complementary error function. * * @param z The argument. * * @return erfc(z) * * @since 1.13.0 */ public Apcomplex erfc(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.erfcFixedPrecision(setErfPrecision(z))); } /** * Imaginary error function. * * @param z The argument. * * @return erfi(z) * * @since 1.13.0 */ public Apcomplex erfi(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.erfiFixedPrecision(setErfPrecision(z))); } /** * Fresnel integral S. * * @param z The argument. * * @return S(z) * * @since 1.13.0 */ public Apcomplex fresnelS(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.fresnelS(setPrecision(z))); } /** * Fresnel integral C. * * @param z The argument. * * @return C(z) * * @since 1.13.0 */ public Apcomplex fresnelC(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.fresnelC(setPrecision(z))); } /** * Exponential integral E. * * @param ν The first argument. * @param z The second argument. * * @return Eν(z) * * @throws ArithmeticException If real part of ν is < 0 and z is zero. * * @since 1.13.0 */ public Apcomplex expIntegralE(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.expIntegralE(setPrecision(ν), setPrecision(z))); } /** * Exponential integral Ei. * * @param z The argument. * * @return Ei(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public Apcomplex expIntegralEi(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.expIntegralEi(setPrecision(z))); } /** * Logarithmic integral. * * @param z The argument. * * @return li(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public Apcomplex logIntegral(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.logIntegral(setLogarithmicPrecision(z))); } /** * Sine integral. * * @param z The argument. * * @return Si(z) * * @since 1.13.0 */ public Apcomplex sinIntegral(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.sinIntegral(setPrecision(z))); } /** * Cosine integral. * * @param z The argument. * * @return Ci(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public Apcomplex cosIntegral(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.cosIntegral(setPrecision(z))); } /** * Hyperbolic sine integral. * * @param z The argument. * * @return Shi(z) * * @since 1.13.0 */ public Apcomplex sinhIntegral(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.sinhIntegral(setPrecision(z))); } /** * Hyperbolic cosine integral. * * @param z The argument. * * @return Chi(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public Apcomplex coshIntegral(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.coshIntegral(setPrecision(z))); } /** * Airy function Ai. * * @param z The argument. * * @return Ai(z) * * @since 1.13.0 */ public Apcomplex airyAi(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.airyAi(setPrecision(z), precision())); } /** * Derivative of the Airy function Ai. * * @param z The argument. * * @return Ai′(z) * * @since 1.13.0 */ public Apcomplex airyAiPrime(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.airyAiPrime(setPrecision(z), precision())); } /** * Airy function Bi. * * @param z The argument. * * @return Bi(z) * * @since 1.13.0 */ public Apcomplex airyBi(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.airyBi(setPrecision(z), precision())); } /** * Derivative of the Airy function Bi. * * @param z The argument. * * @return Bi′(z) * * @since 1.13.0 */ public Apcomplex airyBiPrime(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.airyBiPrime(setPrecision(z), precision())); } /** * Bessel function of the first kind. * * @param ν The order. * @param z The argument. * * @return Jν(z) * * @throws ArithmeticException If the real part of ν is < 0 and ν is not an integer and z is zero. Also if the real part of ν is zero but the imaginary part is not, and z is zero. * * @since 1.13.0 */ public Apcomplex besselJ(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.besselJ(setPrecision(ν), setPrecision(z))); } /** * Modified Bessel function of the first kind. * * @param ν The order. * @param z The argument. * * @return Iν(z) * * @throws ArithmeticException If the real part of ν is < 0 and ν is not an integer and z is zero. Also if the real part of ν is zero but the imaginary part is not, and z is zero. * * @since 1.13.0 */ public Apcomplex besselI(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.besselI(setPrecision(ν), setPrecision(z))); } /** * Bessel function of the second kind. * * @param ν The order. * @param z The argument. * * @return Yν(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public Apcomplex besselY(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.besselY(setPrecision(ν), setPrecision(z))); } /** * Modified Bessel function of the second kind. * * @param ν The order. * @param z The argument. * * @return Kν(z) * * @throws ArithmeticException If z is zero. * * @since 1.13.0 */ public Apcomplex besselK(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.besselK(setPrecision(ν), setPrecision(z))); } /** * Complete elliptic integral of the first kind. * * @param z The argument. * * @return K(z) * * @throws ArithmeticException If z is one. * * @since 1.13.0 */ public Apcomplex ellipticK(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.ellipticK(setPrecision(z), precision())); } /** * Complete elliptic integral of the second kind. * * @param z The argument. * * @return E(z) * * @since 1.13.0 */ public Apcomplex ellipticE(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.ellipticE(setPrecision(z), precision())); } /** * Hermite function. * * @param ν The first argument. * @param z The second argument. * * @return Hν(z) * * @since 1.14.0 */ public Apcomplex hermiteH(Apcomplex ν, Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.hermiteH(setPrecision(ν), setPrecision(z))); } /** * Laguerre function. * * @param ν The first argument. * @param z The second argument. * * @return Lν(z) * * @since 1.14.0 */ public Apcomplex laguerreL(Apcomplex ν, Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.laguerreL(setPrecision(ν), setPrecision(z))); } /** * Generalized Laguerre function. * * @param ν The first argument. * @param λ The second argument. * @param z The third argument. * * @return Lνλ(z) * * @since 1.14.0 */ public Apcomplex laguerreL(Apcomplex ν, Apcomplex λ, Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.laguerreL(setPrecision(ν), setPrecision(λ), setPrecision(z))); } /** * Legendre function. * * @param ν The first argument. * @param z The second argument. * * @return Pν(z) * * @throws ArithmeticException If ν is not an integer and z is -1. * * @since 1.14.0 */ public Apcomplex legendreP(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.legendreP(setPrecision(ν), setPrecision(z))); } /** * Associated Legendre function of the first kind. * * @param ν The first argument. * @param μ The second argument. * @param z The third argument. * * @return Pνμ(z) * * @throws ArithmeticException If ν is not an integer and z is -1. * * @since 1.14.0 */ public Apcomplex legendreP(Apcomplex ν, Apcomplex μ, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.legendreP(setPrecision(ν), setPrecision(μ), setPrecision(z))); } /** * Legendre function of the second kind. * * @param ν The first argument. * @param z The second argument. * * @return Qν(z) * * @throws ArithmeticException If z is 1 or -1. * * @since 1.14.0 */ public Apcomplex legendreQ(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.legendreQ(setPrecision(ν), setPrecision(z))); } /** * Associated Legendre function of the second kind. * * @param ν The first argument. * @param μ The second argument. * @param z The third argument. * * @return Qνμ(z) * * @throws ArithmeticException If z is 1 or -1. * * @since 1.14.0 */ public Apcomplex legendreQ(Apcomplex ν, Apcomplex μ, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.legendreQ(setPrecision(ν), setPrecision(μ), setPrecision(z))); } /** * Spherical harmonic function. * * @param λ The first argument. * @param μ The second argument. * @param ϑ The third argument. * @param ϕ The fourth argument. * * @return Yλμ(ϑ, φ) * * @throws ArithmeticException If ϑ is π plus a multiple of 2 π and μ is not an integer and has a negative real part, or if λ - μ is a negative integer. * * @since 1.14.0 */ public Apcomplex sphericalHarmonicY(Apcomplex λ, Apcomplex μ, Apcomplex ϑ, Apcomplex ϕ) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.sphericalHarmonicY(setPrecision(λ), setPrecision(μ), setPrecision(ϑ), setPrecision(ϕ))); } /** * Chebyshev function of the first kind. * * @param ν The first argument. * @param z The second argument. * * @return Tν(z) * * @since 1.14.0 */ public Apcomplex chebyshevT(Apcomplex ν, Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.chebyshevT(setPrecision(ν), setPrecision(z))); } /** * Chebyshev function of the second kind. * * @param ν The first argument. * @param z The second argument. * * @return Uν(z) * * @throws ArithmeticException If z is -1 and ν is not an integer. * * @since 1.14.0 */ public Apcomplex chebyshevU(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.chebyshevU(setPrecision(ν), setPrecision(z))); } /** * Renormalized Gegenbauer function. * * @param ν The first argument. * @param z The second argument. * * @return Cν(0)(z) * * @throws ArithmeticException If ν is zero. * * @since 1.14.0 */ public Apcomplex gegenbauerC(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.gegenbauerC(setPrecision(ν), setPrecision(z))); } /** * Gegenbauer function. * * @param ν The first argument. * @param λ The second argument. * @param z The third argument. * * @return Cνλ(z) * * @throws ArithmeticException If z is -1 and real part of λ is > 1/2. Also if z is -1 and λ is 1/2 and ν is not an integer. * * @since 1.14.0 */ public Apcomplex gegenbauerC(Apcomplex ν, Apcomplex λ, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.gegenbauerC(setPrecision(ν), setPrecision(λ), setPrecision(z))); } /** * Jacobi function. * * @param ν The first argument. * @param a The second argument. * @param b The third argument. * @param z The fourth argument. * * @return Pν(a,b)(z) * * @throws ArithmeticException If z is -1 and real part of b is > 0 and ν is not a positive integer. Also if ν + a is a negative integer and ν is not an integer. * * @since 1.14.0 */ public Apcomplex jacobiP(Apcomplex ν, Apcomplex a, Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.jacobiP(setPrecision(ν), setPrecision(a), setPrecision(b), setPrecision(z))); } /** * Fibonacci function. * * @param ν The first argument. * @param z The second argument. * * @return Fν(z) * * @throws ArithmeticException If z is -1 and ν is not an integer. * * @since 1.14.0 */ public Apcomplex fibonacci(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.fibonacci(new Apcomplex(setTrigonometricPrecision(ν.real()), setTrigonometricPrecision(ν.imag())), setPrecision(z))); } /** * Euler polynomial. * * @param n The first argument. * @param z The second argument. * * @return En(z) * * @throws IllegalArgumentException If n < 0. * * @since 1.14.0 */ public Apcomplex eulerE(long n, Apcomplex z) throws IllegalArgumentException, ApfloatRuntimeException { return valueOf(ApcomplexMath.eulerE(n, setPrecision(z), precision())); } /** * Bernoulli polynomial. * * @param n The first argument. * @param z The second argument. * * @return Bn(z) * * @throws IllegalArgumentException If n < 0. * * @since 1.14.0 */ public Apcomplex bernoulliB(long n, Apcomplex z) throws IllegalArgumentException, ApfloatRuntimeException { return valueOf(ApcomplexMath.bernoulliB(n, setPrecision(z), precision())); } /** * Harmonic number. * * @param z The argument. * * @return Hz * * @throws ArithmeticException If z is a negative integer. * * @since 1.14.0 */ public Apcomplex harmonicNumber(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.harmonicNumber(setPrecision(z))); } /** * Generalized harmonic number. * * @param z The first argument. * @param r The second argument. * * @return Hz(r) * * @throws ArithmeticException If z is a negative integer, unless r has a negative real part or is zero. * * @since 1.14.0 */ public Apcomplex harmonicNumber(Apcomplex z, Apcomplex r) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.harmonicNumber(setPrecision(z), setPrecision(r))); } /** * Polylogarithm. * * @param ν The first argument. * @param z The second argument. * * @return Liν(z) * * @throws ArithmeticException If the real part of ν is ≤ 1 and z is 1. * * @since 1.14.0 */ public Apcomplex polylog(Apcomplex ν, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.polylog(setPrecision(ν), setPrecision(z))); } /** * Logistic sigmoid. * * @param z The argument. * * @return σ(z) * * @throws ArithmeticException If z is an odd integer multiple of π i. * * @since 1.14.0 */ public Apcomplex logisticSigmoid(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApcomplexMath.logisticSigmoid(setExpTrigPrecision(z))); } /** * Unit in the last place. * * @param z The operand. * * @return The unit in the last place. * * @since 1.10.0 */ public Apfloat ulp(Apcomplex z) throws ApfloatRuntimeException { return valueOf(ApcomplexMath.ulp(setPrecision(z))); } /** * Returns the precision, which is used for the results. * * @return The precision of the results. */ public long precision() { return this.precision; } Apfloat valueOf(Apfloat x) throws ApfloatRuntimeException { return x.precision(precision()); } Apfloat pi() throws ApfloatRuntimeException { return ApfloatMath.pi(precision()); } Apfloat pi(int radix) throws NumberFormatException, ApfloatRuntimeException { return ApfloatMath.pi(precision(), radix); } Apfloat setTrigonometricPrecision(Apfloat x) throws ApfloatRuntimeException { long precision = ApfloatHelper.extendPrecision(precision(), Math.max(0, x.scale())); return x.precision(precision); } Apfloat setExponentialPrecision(Apfloat x) throws ApfloatRuntimeException { if (x.scale() <= -precision()) { // Result will be rounded to one so avoid heavy high-precision calculation x = new Apfloat(0, Apfloat.DEFAULT, x.radix()); } else if (x.scale() < 0) { // Taylor series would increase precision, thus reduce it long precision = Util.ifFinite(precision(), precision() + x.scale()); x = x.precision(precision); } else if (x.scale() > 1) { // Very large inputs have decreased precision, thus increase it long precision = Util.ifFinite(precision(), precision() + x.scale() - 1); x = x.precision(precision); } else { x = x.precision(precision()); } return x; } Apfloat setLogarithmicPrecision(Apfloat x) throws ApfloatRuntimeException { long precision = ApfloatHelper.extendPrecision(precision(), x.equalDigits(new Apfloat(1, Apfloat.INFINITE, x.radix()))); return x.precision(precision); } Apfloat setGammaPrecision(Apfloat x) { return setGammaPrecision((Apcomplex) x).real(); } Apfloat setZetaPrecision(Apfloat x) { return setTrigonometricPrecision(x); } Apfloat setErfPrecision(Apfloat x) { return setErfPrecision((Apcomplex) x).real(); } private Apcomplex setPrecision(Apcomplex z) throws ApfloatRuntimeException { return z.precision(precision()); } private Apcomplex[] setPrecision(Apcomplex[] z) throws ApfloatRuntimeException { Apcomplex[] tmp = new Apcomplex[z.length]; for (int i = 0; i < z.length; i++) { tmp[i] = setPrecision(z[i]); } return tmp; } private Apcomplex setExpTrigPrecision(Apcomplex z) { return new Apcomplex(setExponentialPrecision(z.real()), setTrigonometricPrecision(z.imag())); } private Apcomplex setTrigExpPrecision(Apcomplex z) { return new Apcomplex(setTrigonometricPrecision(z.real()), setExponentialPrecision(z.imag())); } private Apcomplex setLogarithmicPrecision(Apcomplex z) { long precision = ApfloatHelper.extendPrecision(precision(), abs(z).equalDigits(new Apfloat(1, Apfloat.INFINITE, z.radix()))); return z.precision(precision); } private Apcomplex setGammaPrecision(Apcomplex z) { long precision = ApfloatHelper.extendPrecision(precision(), Math.max(0, z.scale())); return ApfloatHelper.ensureGammaPrecision(z, precision); } private Apcomplex setZetaPrecision(Apcomplex z) { return new Apcomplex(setZetaPrecision(z.real()), setTrigonometricPrecision(z.imag())); } private Apcomplex setErfPrecision(Apcomplex z) { long precision = precision(), scale = z.scale(); if (scale > 0) { precision = ApfloatHelper.extendPrecision(precision, Util.ifFinite(scale, 2 * scale)); } return z.precision(precision); } private Apcomplex checkSmallLinear(Apcomplex z) { if (z.scale() <= -precision()) { return setPrecision(z); } return null; } private long precision; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/FixedPrecisionApfloatHelper.java000066400000000000000000002006631461767713300277750ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import java.util.Arrays; import org.apfloat.spi.Util; /** * Fixed-precision mathematical functions for floating-point numbers.

* * All results of the mathematical operations are set to have the specified precision. * Also all input arguments are set to the specified precision before the operation. * If the specified precision is not infinite, this helper class also avoids * InfiniteExpansionException e.g. in case where it would happen with * ApfloatMath.acos(Apfloat.ZERO). * * @since 1.5 * @version 1.14.0 * @author Mikko Tommila */ public class FixedPrecisionApfloatHelper extends FixedPrecisionApcomplexHelper { /** * Constructs an apfloat fixed-precison helper with the specified precision. * The results of all mathematical operations are set to the specified precision. * * @param precision The precision of the results. * * @exception IllegalArgumentException In case the precision is invalid. */ public FixedPrecisionApfloatHelper(long precision) throws IllegalArgumentException { super(precision); } /** * Returns the value with the specified precision. * * @param x The value. * * @return The value with to the specified precision. */ @Override public Apfloat valueOf(Apfloat x) { return super.valueOf(x); } /** * Negation. * * @param x The value to negate. * * @return -x. */ public Apfloat negate(Apfloat x) throws ApfloatRuntimeException { return valueOf(x).negate(); } /** * Addition. * * @param x The first operand. * @param y The second operand. * * @return x + y. */ public Apfloat add(Apfloat x, Apfloat y) throws ApfloatRuntimeException { return valueOf(setPrecision(x).add(valueOf(y))); } /** * Subtraction. * * @param x The first operand. * @param y The second operand. * * @return x - y. */ public Apfloat subtract(Apfloat x, Apfloat y) throws ApfloatRuntimeException { return valueOf(setPrecision(x).subtract(setPrecision(y))); } /** * Multiplication. * * @param x The first operand. * @param y The second operand. * * @return x * y. */ public Apfloat multiply(Apfloat x, Apfloat y) throws ApfloatRuntimeException { return valueOf(setPrecision(x).multiply(setPrecision(y))); } /** * Division. * * @param x The first operand. * @param y The second operand. * * @return x / y. * * @exception ArithmeticException If y is zero. */ public Apfloat divide(Apfloat x, Apfloat y) throws ArithmeticException, ApfloatRuntimeException { return valueOf(setPrecision(x).divide(setPrecision(y))); } /** * Power. * * @param x The first operand. * @param y The second operand. * * @return xy. * * @exception ArithmeticException If x and y are zero, or x is negative and y is not an integer. */ public Apfloat pow(Apfloat x, Apfloat y) throws ArithmeticException, ApfloatRuntimeException { Apfloat result = ApfloatHelper.checkPow(x, y, precision()); if (result != null) { return valueOf(result); } else if (x.signum() < 0 && y.isInteger()) { return valueOf(pow((Apcomplex) x, (Apcomplex) y).real()); } return exp(multiply(log(x), y)); } /** * Integer power. * * @param x The first operand. * @param n The second operand. * * @return xn. * * @exception ArithmeticException If x and n are zero, or x is zero and n is negative. */ public Apfloat pow(Apfloat x, long n) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.pow(setPrecision(x), n)); } /** * Absolute value. * * @param x The operand. * * @return The absolute value of x. */ public Apfloat abs(Apfloat x) throws ApfloatRuntimeException { return ApfloatMath.abs(valueOf(x)); } /** * Arc cosine. * * @param x The operand. * * @return The arc cosine of x. * * @exception ArithmeticException If the absolute value of x is more than one. */ public Apfloat acos(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.acos(setPrecision(x), precision())); } /** * Hyperbolic arc cosine. * * @param x The operand. * * @return The hyperbolic arc cosine of x. * * @exception ArithmeticException If the x is less than one. */ public Apfloat acosh(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.acosh(setPrecision(x))); } /** * Arc sine. * * @param x The operand. * * @return The arc sine of x. * * @exception ArithmeticException If the absolute value of x is more than one. */ public Apfloat asin(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.asin(setPrecision(x))); } /** * Hyperbolic arc sine. * * @param x The operand. * * @return The hyperbolic arc sine of x. */ public Apfloat asinh(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.asinh(setPrecision(x))); } /** * Arc tangent. * * @param x The operand. * * @return The arc tangent of x. */ public Apfloat atan(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.atan(setPrecision(x))); } /** * Hyperbolic arc tangent. * * @param x The operand. * * @return The hyperbolic arc tangent of x. * * @exception ArithmeticException If the absolute value of x is equal to or more than one. */ public Apfloat atanh(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.atanh(setPrecision(x))); } /** * Cube root. * * @param x The operand. * * @return The cube root of x. */ public Apfloat cbrt(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.cbrt(setPrecision(x))); } /** * Cosine. * * @param x The operand. * * @return The cosine of x. */ public Apfloat cos(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.cos(setTrigonometricPrecision(x))); } /** * Hyperbolic cosine. * * @param x The operand. * * @return The hyperbolic cosine of x. */ public Apfloat cosh(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.cosh(setExponentialPrecision(x))); } /** * Exponential function. * * @param x The operand. * * @return ex. */ public Apfloat exp(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.exp(setExponentialPrecision(x))); } /** * Natural logarithm. * * @param x The operand. * * @return The natural logarithm of x. * * @exception ArithmeticException If x is less than or equal to zero. */ public Apfloat log(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.log(setLogarithmicPrecision(x))); } /** * Logarithm in specified base. * * @param x The operand. * @param b The base. * * @return The base-b logarithm of x. * * @exception ArithmeticException If x or b is less than or equal to zero. * * @since 1.6 */ public Apfloat log(Apfloat x, Apfloat b) throws ArithmeticException, ApfloatRuntimeException { // If x or b is close to one then result will actually have limited accuracy // So, if the argument would have more precision, it could be used, however checking for // this as well as the computation itself could be very time-consuming so we don't do it return valueOf(ApfloatMath.log(setPrecision(x), setPrecision(b))); } /** * Sine. * * @param x The operand. * * @return The sine of x. */ public Apfloat sin(Apfloat x) throws ApfloatRuntimeException { Apfloat result = checkSmallLinear(x); if (result != null) { return result; } return valueOf(ApfloatMath.sin(setTrigonometricPrecision(x))); } /** * Hyperbolic sine. * * @param x The operand. * * @return The hyperbolic sine of x. */ public Apfloat sinh(Apfloat x) throws ApfloatRuntimeException { Apfloat result = checkSmallLinear(x); if (result != null) { return result; } return valueOf(ApfloatMath.sinh(setExponentialPrecision(x))); } /** * Square root. * * @param x The operand. * * @return The square root of x. * * @exception ArithmeticException If x is negative. */ public Apfloat sqrt(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.sqrt(setPrecision(x))); } /** * Tangent. * * @param x The operand. * * @return The tangent of x. * * @exception ArithmeticException If x is π/2 + n π where n is an integer. */ public Apfloat tan(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { Apfloat result = checkSmallLinear(x); if (result != null) { return result; } return valueOf(ApfloatMath.tan(setTrigonometricPrecision(x))); } /** * Hyperbolic tangent. * * @param x The operand. * * @return The hyperbolic tangent of x. */ public Apfloat tanh(Apfloat x) throws ApfloatRuntimeException { Apfloat result = checkSmallLinear(x); if (result != null) { return result; } return valueOf(ApfloatMath.tanhFixedPrecision(setExponentialPrecision(x))); } /** * Sinc. * * @param x The argument. * * @return sinc(x) * * @since 1.14.0 */ public Apfloat sinc(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.sinc(setTrigonometricPrecision(x))); } /** * Arithmetic-geometric mean. * * @param a The first operand. * @param b The first operand. * * @return The arithmetic-geometric mean of a and b. */ public Apfloat agm(Apfloat a, Apfloat b) throws ApfloatRuntimeException { return valueOf(ApfloatMath.agm(setPrecision(a), setPrecision(b))); } /** * Inverse root. * * @param x The operand. * @param n Which inverse root to take. * * @return x-1/n. * * @exception ArithmeticException If x or n is zero, or x is negative and n is even. */ public Apfloat inverseRoot(Apfloat x, long n) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.inverseRoot(setPrecision(x), n)); } /** * Root. * * @param x The operand. * @param n Which root to take. * * @return x1/n. * * @exception ArithmeticException If n is zero, or x is negative and n is even. */ public Apfloat root(Apfloat x, long n) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.root(setPrecision(x), n)); } /** * Move the radix point. * * @param x The operand. * @param scale The amount to move the radix point. * * @return x * x.radix()scale. */ public Apfloat scale(Apfloat x, long scale) throws ApfloatRuntimeException { return ApfloatMath.scale(valueOf(x), scale); } /** * Modulus. * * @param x The first operand. * @param y The second operand. * * @return x % y. */ public Apfloat mod(Apfloat x, Apfloat y) throws ApfloatRuntimeException { return fmod(x, y); } /** * Ceiling function. * * @param x The operand. * * @return The nearest integer greater than or equal to x. */ public Apfloat ceil(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.ceil(setPrecision(x))); } /** * Floor function. * * @param x The operand. * * @return The nearest integer less than or equal to x. */ public Apfloat floor(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.floor(setPrecision(x))); } /** * Truncate fractional part. * * @param x The operand. * * @return The nearest integer rounded towards zero from x. */ public Apfloat truncate(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.truncate(setPrecision(x))); } /** * Extract fractional part. * * @param x The operand. * * @return The fractional part of x. * * @since 1.7.0 */ public Apfloat frac(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.frac(x)); } /** * Round with specified rounding mode. * * @deprecated Use {@link #roundToPrecision(Apfloat,RoundingMode)}. * * @param x The operand. * @param roundingMode The rounding mode. * * @return x rounded with the specified rounding mode. * * @since 1.7.0 */ @Deprecated public Apfloat round(Apfloat x, RoundingMode roundingMode) throws ApfloatRuntimeException { return roundToPrecision(x, roundingMode); } /** * Round to precision with specified rounding mode. * * @param x The operand. * @param roundingMode The rounding mode. * * @return x rounded to the precision of this helper with the specified rounding mode. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public Apfloat roundToPrecision(Apfloat x, RoundingMode roundingMode) throws ApfloatRuntimeException { return ApfloatMath.roundToPrecision(x, precision(), roundingMode); } /** * Round to integer with specified rounding mode. * * @param x The operand. * @param roundingMode The rounding mode. * * @return x rounded to integer with the specified rounding mode. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public Apfloat roundToInteger(Apfloat x, RoundingMode roundingMode) throws ApfloatRuntimeException, ArithmeticException { return valueOf(ApfloatMath.roundToInteger(x, roundingMode)); } /** * Round to specified number of places with specified rounding mode. * * @param x The operand. * @param places The number of places. * @param roundingMode The rounding mode. * * @return x rounded to the specified number of places with the specified rounding mode. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @since 1.11.0 */ public Apfloat roundToPlaces(Apfloat x, long places, RoundingMode roundingMode) throws ApfloatRuntimeException, ArithmeticException { return valueOf(ApfloatMath.roundToPlaces(x, places, roundingMode)); } /** * Round to multiple with specified rounding mode. * * @param x The number to round. * @param y The integer multiple to round to. * @param roundingMode The rounding mode. * * @exception ArithmeticException If rounding is necessary (result is not exact) and rounding mode is {@link RoundingMode#UNNECESSARY}. * * @return x rounded to the nearest multiple of y with the specified rounding mode. * * @since 1.11.0 */ public Apfloat roundToMultiple(Apfloat x, Apfloat y, RoundingMode roundingMode) throws ApfloatRuntimeException, ArithmeticException { return valueOf(ApfloatMath.roundToMultiple(x, y, roundingMode)); } /** * Lambert W function. * * @param x The operand. * * @return W0(x). * * @since 1.8.0 */ public Apfloat w(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.w(setPrecision(x))); } /** * Convert radians to degrees. * * @param x The angle in radians. * * @return x converted to degrees. * * @since 1.8.0 */ public Apfloat toDegrees(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.toDegrees(setPrecision(x))); } /** * Convert degrees to radians. * * @param x The angle in degrees. * * @return x converted to radians. * * @since 1.8.0 */ public Apfloat toRadians(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.toRadians(setPrecision(x))); } /** * Angle of point. * * @param x The operand. * @param y The operand. * * @return The angle of the point (y, x). * * @exception ArithmeticException If x and y are zero. */ public Apfloat atan2(Apfloat x, Apfloat y) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.atan2(setPrecision(x), setPrecision(y))); } /** * Copies the sign from one number to another. * * @param x The number to copy the sign to. * @param y The number to copy the sign from. * * @return x with the sign of y. */ public Apfloat copySign(Apfloat x, Apfloat y) throws ApfloatRuntimeException { return ApfloatMath.copySign(valueOf(x), y); } /** * Modulus. * * @param x The first operand. * @param y The second operand. * * @return x % y. */ public Apfloat fmod(Apfloat x, Apfloat y) throws ApfloatRuntimeException { return valueOf(ApfloatMath.fmod(x, setPrecision(y))); // Since x might be much larger in scale we do not limit precision yet here } /** * Split to integer and fractional parts. * * @param x The operand. * * @return An array of two numbers [i, f] where i is floor(x) and f is x - floor(x). */ public Apfloat[] modf(Apfloat x) throws ApfloatRuntimeException { if (x.scale() > 0) { long precision = Util.ifFinite(precision(), precision() + x.scale()); x = x.precision(precision); } else { x = setPrecision(x); } Apfloat[] modfs = ApfloatMath.modf(x); modfs[0] = valueOf(modfs[0]); modfs[1] = valueOf(modfs[1]); return modfs; } /** * Factorial. * * @param n The operand. * * @return n!. */ public Apfloat factorial(long n) throws ApfloatRuntimeException { // For low precision and high n the result could be approximated faster with Stirling's formula return valueOf(ApfloatMath.factorial(n, precision())); } /** * Factorial. * * @param n The operand. * @param radix The radix of the result. * * @return n!. */ public Apfloat factorial(long n, int radix) throws ApfloatRuntimeException { // For low precision and high n the result could be approximated faster with Stirling's formula return valueOf(ApfloatMath.factorial(n, precision(), radix)); } /** * Double factorial. * * @param n The operand. * * @return n!!. * * @since 1.14.0 */ public Apfloat doubleFactorial(long n) throws ApfloatRuntimeException { return valueOf(ApfloatMath.doubleFactorial(n, precision())); } /** * Double factorial. * * @param n The operand. * @param radix The radix of the result. * * @return n!!. * * @since 1.14.0 */ public Apfloat doubleFactorial(long n, int radix) throws ApfloatRuntimeException { return valueOf(ApfloatMath.doubleFactorial(n, precision(), radix)); } /** * π. * * @return π. */ @Override public Apfloat pi() throws ApfloatRuntimeException { return super.pi(); } /** * π. * * @param radix The radix of the result. * * @return π. * * @exception NumberFormatException If the radix is invalid. */ @Override public Apfloat pi(int radix) throws NumberFormatException, ApfloatRuntimeException { return super.pi(radix); } /** * Logarithm. * * @param radix The radix of the result. * * @return log(radix). * * @exception NumberFormatException If the radix is invalid. */ public Apfloat logRadix(int radix) throws NumberFormatException, ApfloatRuntimeException { return ApfloatMath.logRadix(precision(), radix); } /** * Fused multiply-add. * * @param a The first operand. * @param b The second operand. * @param c The third operand. * @param d The fourth operand. * * @return a * b + c * d. */ public Apfloat multiplyAdd(Apfloat a, Apfloat b, Apfloat c, Apfloat d) throws ApfloatRuntimeException { return valueOf(ApfloatMath.multiplyAdd(setPrecision(a), setPrecision(b), setPrecision(c), setPrecision(d))); } /** * Fused multiply-subtract. * * @param a The first operand. * @param b The second operand. * @param c The third operand. * @param d The fourth operand. * * @return a * b - c * d. */ public Apfloat multiplySubtract(Apfloat a, Apfloat b, Apfloat c, Apfloat d) throws ApfloatRuntimeException { return valueOf(ApfloatMath.multiplySubtract(setPrecision(a), setPrecision(b), setPrecision(c), setPrecision(d))); } /** * Product. * * @param x The operand(s). * * @return The product of the operands. */ public Apfloat product(Apfloat... x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.product(setPrecision(x))); } /** * Sum. * * @param x The operand(s). * * @return The sum of the operands. */ public Apfloat sum(Apfloat... x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.sum(setPrecision(x))); } /** * Gamma function. * * @param x The operand. * * @return Γ(x). * * @throws ArithmeticException If x is a nonpositive integer. * * @since 1.9.0 */ public Apfloat gamma(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.gamma(setGammaPrecision(x))); } /** * Incomplete gamma function. * * @param a The first operand. * @param x The second operand. * * @return Γ(a, x). * * @throws ArithmeticException If a is not a positive integer and x is nonpositive. * * @since 1.10.0 */ public Apfloat gamma(Apfloat a, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.gamma(setGammaPrecision(a), setPrecision(x))); } /** * Generalized incomplete gamma function. * * @param a The first operand. * @param x0 The second operand. * @param x1 The third operand. * * @return Γ(a, x0) - Γ(a, x1). * * @throws ArithmeticException If a is not a positive integer and either x0 or x1 is nonpositive. * * @since 1.10.0 */ public Apfloat gamma(Apfloat a, Apfloat x0, Apfloat x1) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.gamma(setGammaPrecision(a), setPrecision(x0), setPrecision(x1))); } /** * Logarithm of the gamma function. * * @param x The argument. * * @return logΓ(x) * * @throws ArithmeticException If x is nonpositive. * * @since 1.11.0 */ public Apfloat logGamma(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.logGamma(setPrecision(x))); } /** * Digamma function. * * @param x The argument. * * @return ψ(x) * * @throws ArithmeticException If x is a nonpositive integer. * * @since 1.11.0 */ public Apfloat digamma(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.digamma(setPrecision(x))); } /** * Polygamma function. * * @param n The order. * @param x The argument. * * @return ψ(n)(x) * * @throws ArithmeticException If n is negative or x is a nonpositive integer. * * @since 1.13.0 */ public Apfloat polygamma(long n, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.polygamma(n, setPrecision(x))); } /** * Beta function. * * @param a The first argument. * @param b The second argument. * * @return B(a, b) * * @throws ArithmeticException If a or b is a nonpositive integer but a + b is not. Also if both a and b are nonpositive integers. * * @since 1.13.0 */ public Apfloat beta(Apfloat a, Apfloat b) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.beta(setPrecision(a), setPrecision(b))); } /** * Incomplete beta function. * * @param x The first argument. * @param a The second argument. * @param b The third argument. * * @return Bx(a, b) * * @throws ArithmeticException If a is a nonpositive integer or x is zero and a is nonpositive or x is negative and a is not an integer. Also if x > 1 and the result is not a polynomial. * * @since 1.13.0 */ public Apfloat beta(Apfloat x, Apfloat a, Apfloat b) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.beta(setPrecision(x), setPrecision(a), setPrecision(b))); } /** * Generalized incomplete beta function. * * @param x1 The first argument. * @param x2 The second argument. * @param a The third argument. * @param b The fourth argument. * * @return B(x1, x2)(a, b) * * @throws ArithmeticException If a is a nonpositive integer or x1 or x2 is zero and a is nonpositive or x1 or x2 is negative and a is not an integer. Also if x1 > 1 or x2 > 1 and the result is not a polynomial. * * @since 1.13.0 */ public Apfloat beta(Apfloat x1, Apfloat x2, Apfloat a, Apfloat b) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.beta(setPrecision(x1), setPrecision(x2), setPrecision(a), setPrecision(b))); } /** * Pochhammer symbol. * * @param x The first argument. * @param n The second argument. * * @return (x)n * * @throws ArithmeticException If x + n is a nonpositive integer but x is not. * * @since 1.13.0 */ public Apfloat pochhammer(Apfloat x, Apfloat n) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.pochhammer(setPrecision(x), setPrecision(n))); } /** * Binomial coefficient. * * @param n The argument. * @param k The argument. * * @return The binomial coefficient. * * @throws ArithmeticException If n, k or n - k is a nonpositive integer. * * @since 1.11.0 */ public Apfloat binomial(Apfloat n, Apfloat k) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.binomial(setGammaPrecision(n), setGammaPrecision(k))); } /** * Riemann zeta function. * * @param s The argument. * * @return ζ(s) * * @throws ArithmeticException If s is 1. * * @since 1.11.0 */ public Apfloat zeta(Apfloat s) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.zeta(setZetaPrecision(s))); } /** * Hurwitz zeta function. * * @param s The first argument. * @param a The second argument. * * @return ζ(s, a) * * @throws ArithmeticException If s is 1 or if a is a nonpositive integer or if s is not an integer and a is nonpositive. * * @since 1.11.0 */ public Apfloat zeta(Apfloat s, Apfloat a) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.zeta(setZetaPrecision(s), setPrecision(a))); } /** * Confluent hypergeometric function 0F1. * * @param a The first argument. * @param x The second argument. * * @return 0F1(; a; x) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public Apfloat hypergeometric0F1(Apfloat a, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.hypergeometric0F1(setPrecision(a), setPrecision(x))); } /** * Regularized confluent hypergeometric function 01. * * @param a The first argument. * @param x The second argument. * * @return 01(; a; x) * * @since 1.13.0 */ public Apfloat hypergeometric0F1Regularized(Apfloat a, Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.hypergeometric0F1Regularized(setPrecision(a), setPrecision(x))); } /** * Kummer confluent hypergeometric function 1F1. * * @param a The first argument. * @param b The second argument. * @param x The third argument. * * @return 1F1(a; b; x) * * @throws ArithmeticException If the function value is not finite. * * @since 1.11.0 */ public Apfloat hypergeometric1F1(Apfloat a, Apfloat b, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.hypergeometric1F1(setPrecision(a), setPrecision(b), setPrecision(x))); } /** * Regularized Kummer confluent hypergeometric function 11. * * @param a The first argument. * @param b The second argument. * @param x The third argument. * * @return 11(a; b; x) * * @since 1.13.0 */ public Apfloat hypergeometric1F1Regularized(Apfloat a, Apfloat b, Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.hypergeometric1F1Regularized(setPrecision(a), setPrecision(b), setPrecision(x))); } /** * Hypergeometric function 2F1. * * @param a The first argument. * @param b The second argument. * @param c The third argument. * @param x The fourth argument. * * @return 2F1(a, b; c; x) * * @throws ArithmeticException If the function value is not finite or real. * * @since 1.11.0 */ public Apfloat hypergeometric2F1(Apfloat a, Apfloat b, Apfloat c, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.hypergeometric2F1(setPrecision(a), setPrecision(b), setPrecision(c), setPrecision(x))); } /** * Regularized hypergeometric function 21. * * @param a The first argument. * @param b The second argument. * @param c The third argument. * @param x The fourth argument. * * @return 21(a, b; c; x) * * @since 1.13.0 */ public Apfloat hypergeometric2F1Regularized(Apfloat a, Apfloat b, Apfloat c, Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.hypergeometric2F1Regularized(setPrecision(a), setPrecision(b), setPrecision(c), setPrecision(x))); } /** * Tricomi's confluent hypergeometric function U. * * @param a The first argument. * @param b The second argument. * @param x The third argument. * * @return U(a, b, x) * * @throws ArithmeticException If the result would be complex or not finite. * * @since 1.13.0 */ public Apfloat hypergeometricU(Apfloat a, Apfloat b, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.hypergeometricU(setPrecision(a), setPrecision(b), setPrecision(x))); } /** * Error function. * * @param x The argument. * * @return erf(x) * * @since 1.13.0 */ public Apfloat erf(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.erfFixedPrecision(setErfPrecision(x))); } /** * Complementary error function. * * @param x The argument. * * @return erfc(x) * * @since 1.13.0 */ public Apfloat erfc(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.erfcFixedPrecision(setErfPrecision(x))); } /** * Imaginary error function. * * @param x The argument. * * @return erfi(x) * * @since 1.13.0 */ public Apfloat erfi(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.erfiFixedPrecision(setErfPrecision(x))); } /** * Inverse error function. * * @param x The argument. * * @return erf−1(x) * * @throws ArithmeticException If |x| is ≥ 1. * * @since 1.13.0 */ public Apfloat inverseErf(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { long precision = ApfloatHelper.extendPrecision(precision(), ApfloatMath.abs(x).equalDigits(Apfloat.ONES[x.radix()])); return valueOf(ApfloatMath.inverseErf(x.precision(precision))); } /** * Inverse complementary error function. * * @param x The argument. * * @return erfc−1(x) * * @throws ArithmeticException If x is ≤ 0 or ≥ 2. * * @since 1.13.0 */ public Apfloat inverseErfc(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { long precision = ApfloatHelper.extendPrecision(precision(), Math.max(-x.scale(), x.equalDigits(new Apfloat(2, Apfloat.INFINITE, x.radix())))); return valueOf(ApfloatMath.inverseErfc(x.precision(precision))); } /** * Fresnel integral S. * * @param x The argument. * * @return S(x) * * @since 1.13.0 */ public Apfloat fresnelS(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.fresnelS(setPrecision(x))); } /** * Fresnel integral C. * * @param x The argument. * * @return C(x) * * @since 1.13.0 */ public Apfloat fresnelC(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.fresnelC(setPrecision(x))); } /** * Exponential integral E. * * @param ν The first argument. * @param x The second argument. * * @return Eν(x) * * @throws ArithmeticException If ν is < 0 and x is zero or ν is nonzero and x is negative. * * @since 1.13.0 */ public Apfloat expIntegralE(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.expIntegralE(setPrecision(ν), setPrecision(x))); } /** * Exponential integral Ei. * * @param x The argument. * * @return Ei(x) * * @throws ArithmeticException If x is zero. * * @since 1.13.0 */ public Apfloat expIntegralEi(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.expIntegralEi(setPrecision(x))); } /** * Logarithmic integral. * * @param x The argument. * * @return li(x) * * @throws ArithmeticException If x is nonpositive or 1. * * @since 1.13.0 */ public Apfloat logIntegral(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.logIntegral(setLogarithmicPrecision(x))); } /** * Sine integral. * * @param x The argument. * * @return Si(x) * * @since 1.13.0 */ public Apfloat sinIntegral(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.sinIntegral(setPrecision(x))); } /** * Cosine integral. * * @param x The argument. * * @return Ci(x) * * @throws ArithmeticException If x is nonpositive. * * @since 1.13.0 */ public Apfloat cosIntegral(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.cosIntegral(setPrecision(x))); } /** * Hyperbolic sine integral. * * @param x The argument. * * @return Shi(x) * * @since 1.13.0 */ public Apfloat sinhIntegral(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.sinhIntegral(setPrecision(x))); } /** * Hyperbolic cosine integral. * * @param x The argument. * * @return Chi(x) * * @throws ArithmeticException If x is nonpositive. * * @since 1.13.0 */ public Apfloat coshIntegral(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.coshIntegral(setPrecision(x))); } /** * Airy function Ai. * * @param x The argument. * * @return Ai(x) * * @since 1.13.0 */ public Apfloat airyAi(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.airyAi(setPrecision(x), precision())); } /** * Derivative of the Airy function Ai. * * @param x The argument. * * @return Ai′(x) * * @since 1.13.0 */ public Apfloat airyAiPrime(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.airyAiPrime(setPrecision(x), precision())); } /** * Airy function Bi. * * @param x The argument. * * @return Bi(x) * * @since 1.13.0 */ public Apfloat airyBi(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.airyBi(setPrecision(x), precision())); } /** * Derivative of the Airy function Bi. * * @param x The argument. * * @return Bi′(x) * * @since 1.13.0 */ public Apfloat airyBiPrime(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.airyBiPrime(setPrecision(x), precision())); } /** * Bessel function of the first kind. * * @param ν The order. * @param x The argument. * * @return Jν(x) * * @throws ArithmeticException If ν is < 0 and ν is not an integer and x is zero. Also if ν is not an integer and x is < 0. * * @since 1.13.0 */ public Apfloat besselJ(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.besselJ(setPrecision(ν), setPrecision(x))); } /** * Modified Bessel function of the first kind. * * @param ν The order. * @param x The argument. * * @return Iν(x) * * @throws ArithmeticException If ν is < 0 and ν is not an integer and x is zero. Also if ν is not an integer and x is < 0. * * @since 1.13.0 */ public Apfloat besselI(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.besselI(setPrecision(ν), setPrecision(x))); } /** * Bessel function of the second kind. * * @param ν The order. * @param x The argument. * * @return Yν(x) * * @throws ArithmeticException If x is ≤ 0. * * @since 1.13.0 */ public Apfloat besselY(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.besselY(setPrecision(ν), setPrecision(x))); } /** * Modified Bessel function of the second kind. * * @param ν The order. * @param x The argument. * * @return Kν(x) * * @throws ArithmeticException If x is ≤ 0. * * @since 1.13.0 */ public Apfloat besselK(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.besselK(setPrecision(ν), setPrecision(x))); } /** * Complete elliptic integral of the first kind. * * @param x The argument. * * @return K(x) * * @throws ArithmeticException If x is ≥ 1. * * @since 1.13.0 */ public Apfloat ellipticK(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.ellipticK(setPrecision(x), precision())); } /** * Complete elliptic integral of the second kind. * * @param x The argument. * * @return E(x) * * @throws ArithmeticException If x is > 1. * * @since 1.13.0 */ public Apfloat ellipticE(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.ellipticE(setPrecision(x), precision())); } /** * Hermite function. * * @param ν The first argument. * @param x The second argument. * * @return Hν(x) * * @since 1.14.0 */ public Apfloat hermiteH(Apfloat ν, Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.hermiteH(setPrecision(ν), setPrecision(x))); } /** * Laguerre function. * * @param ν The first argument. * @param x The second argument. * * @return Lν(x) * * @since 1.14.0 */ public Apfloat laguerreL(Apfloat ν, Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.laguerreL(setPrecision(ν), setPrecision(x))); } /** * Generalized Laguerre function. * * @param ν The first argument. * @param λ The second argument. * @param x The third argument. * * @return Lνλ(x) * * @since 1.14.0 */ public Apfloat laguerreL(Apfloat ν, Apfloat λ, Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.laguerreL(setPrecision(ν), setPrecision(λ), setPrecision(x))); } /** * Legendre function. * * @param ν The first argument. * @param x The second argument. * * @return Pν(x) * * @throws ArithmeticException If ν is not an integer and x ≤ -1. * * @since 1.14.0 */ public Apfloat legendreP(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.legendreP(setPrecision(ν), setPrecision(x))); } /** * Associated Legendre function of the first kind. * * @param ν The first argument. * @param μ The second argument. * @param x The third argument. * * @return Pνμ(x) * * @throws ArithmeticException If x is ≤ -1 or ≥ 1 and ν or μ is not an integer or μ is not even or μ is not positive and ν < μ. * * @since 1.14.0 */ public Apfloat legendreP(Apfloat ν, Apfloat μ, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.legendreP(setPrecision(ν), setPrecision(μ), setPrecision(x))); } /** * Legendre function of the second kind. * * @param ν The first argument. * @param x The second argument. * * @return Qν(x) * * @throws ArithmeticException If x is ≥ 1 or ≤ -1. * * @since 1.14.0 */ public Apfloat legendreQ(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.legendreQ(setPrecision(ν), setPrecision(x))); } /** * Associated Legendre function of the second kind. * * @param ν The first argument. * @param μ The second argument. * @param x The third argument. * * @return Qνμ(x) * * @throws ArithmeticException If x is ≥ 1 or ≤ -1. * * @since 1.14.0 */ public Apfloat legendreQ(Apfloat ν, Apfloat μ, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.legendreQ(setPrecision(ν), setPrecision(μ), setPrecision(x))); } /** * Chebyshev function of the first kind. * * @param ν The first argument. * @param x The second argument. * * @return Tν(x) * * @throws ArithmeticException If x is < -1 and ν is not an integer. * * @since 1.14.0 */ public Apfloat chebyshevT(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.chebyshevT(setPrecision(ν), setPrecision(x))); } /** * Chebyshev function of the second kind. * * @param ν The first argument. * @param x The second argument. * * @return Uν(x) * * @throws ArithmeticException If x is ≤ -1 and ν is not an integer. * * @since 1.14.0 */ public Apfloat chebyshevU(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.chebyshevU(setPrecision(ν), setPrecision(x))); } /** * Renormalized Gegenbauer function. * * @param ν The first argument. * @param x The second argument. * * @return Cν(0)(x) * * @throws ArithmeticException If ν is zero. Also if x is < -1 and ν is not an integer. * * @since 1.14.0 */ public Apfloat gegenbauerC(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.gegenbauerC(setPrecision(ν), setPrecision(x))); } /** * Gegenbauer function. * * @param ν The first argument. * @param λ The second argument. * @param x The third argument. * * @return Cνλ(x) * * @throws ArithmeticException If x is < -1 and ν is not an integer. Also if x is -1 and λ is > 1/2. Also if x is -1 and λ is 1/2 and ν is not an integer. * * @since 1.14.0 */ public Apfloat gegenbauerC(Apfloat ν, Apfloat λ, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.gegenbauerC(setPrecision(ν), setPrecision(λ), setPrecision(x))); } /** * Jacobi function. * * @param ν The first argument. * @param a The second argument. * @param b The third argument. * @param x The fourth argument. * * @return Pν(a,b)(x) * * @throws ArithmeticException If ν is not a positive integer and either x is -1 and b is > 0 or x is < -1. Also if ν + a is a negative integer and ν is not an integer. * * @since 1.14.0 */ public Apfloat jacobiP(Apfloat ν, Apfloat a, Apfloat b, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.jacobiP(setPrecision(ν), setPrecision(a), setPrecision(b), setPrecision(x))); } /** * Fibonacci function. * * @param ν The first argument. * @param x The second argument. * * @return Fν(x) * * @since 1.14.0 */ public Apfloat fibonacci(Apfloat ν, Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.fibonacci(setPrecision(ν), setPrecision(x))); } /** * Euler polynomial. * * @param n The first argument. * @param x The second argument. * * @return En(x) * * @throws IllegalArgumentException If n < 0. * * @since 1.14.0 */ public Apfloat eulerE(long n, Apfloat x) throws IllegalArgumentException, ApfloatRuntimeException { return valueOf(ApfloatMath.eulerE(n, setPrecision(x), precision())); } /** * Bernoulli polynomial. * * @param n The first argument. * @param x The second argument. * * @return Bn(x) * * @throws IllegalArgumentException If n < 0. * * @since 1.14.0 */ public Apfloat bernoulliB(long n, Apfloat x) throws IllegalArgumentException, ApfloatRuntimeException { return valueOf(ApfloatMath.bernoulliB(n, setPrecision(x), precision())); } /** * Harmonic number. * * @param x The argument. * * @return Hx * * @throws ArithmeticException If x is a negative integer. * * @since 1.14.0 */ public Apfloat harmonicNumber(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.harmonicNumber(setPrecision(x))); } /** * Generalized harmonic number. * * @param x The first argument. * @param r The second argument. * * @return Hx(r) * * @throws ArithmeticException If x is a negative integer, unless r is a nonpositive integer. Also if x is < -1 and r is not an integer. * * @since 1.14.0 */ public Apfloat harmonicNumber(Apfloat x, Apfloat r) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.harmonicNumber(setPrecision(x), setPrecision(r))); } /** * Polylogarithm. * * @param ν The first argument. * @param x The second argument. * * @return Liν(x) * * @throws ArithmeticException If ν is ≤ 1 and x is 1 or if x is > 1. * * @since 1.14.0 */ public Apfloat polylog(Apfloat ν, Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return valueOf(ApfloatMath.polylog(setPrecision(ν), setPrecision(x))); } /** * Logistic sigmoid. * * @param x The argument. * * @return σ(x) * * @since 1.14.0 */ public Apfloat logisticSigmoid(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.logisticSigmoid(setExponentialPrecision(x))); } /** * Return a uniformly distributed random number 0 ≤ x < 1. * * @return A random number. * * @since 1.9.0 */ public Apfloat random() throws ApfloatRuntimeException { return valueOf(ApfloatMath.random(precision())); } /** * Return a uniformly distributed random number 0 ≤ x < 1. * * @param radix The radix of the number. * * @return A random number. * * @exception NumberFormatException If the radix is invalid. * * @since 1.9.0 */ public Apfloat random(int radix) throws NumberFormatException, ApfloatRuntimeException { return valueOf(ApfloatMath.random(precision(), radix)); } /** * Return a normally distributed random number with mean 0 and standard deviation 1. * * @return A random number. * * @since 1.9.0 */ public Apfloat randomGaussian() throws ApfloatRuntimeException { return valueOf(ApfloatMath.randomGaussian(precision())); } /** * Return a normally distributed random number with mean 0 and standard deviation 1. * * @param radix The radix of the number. * * @return A random number. * * @exception NumberFormatException If the radix is invalid. * * @since 1.9.0 */ public Apfloat randomGaussian(int radix) throws NumberFormatException, ApfloatRuntimeException { return valueOf(ApfloatMath.randomGaussian(precision(), radix)); } /** * Continued fraction. * * @param x The value. * @param n Maximum number of terms. * * @return The continued fraction. * * @exception IllegalArgumentException If n is less than one. * * @since 1.12.0 */ public Apfloat[] continuedFraction(Apfloat x, int n) throws ApfloatRuntimeException { Apfloat[] continuedFraction = ApfloatMath.continuedFraction(setPrecision(x), n); continuedFraction = Arrays.copyOf(continuedFraction, continuedFraction.length, Apfloat[].class); for (int i = 0; i < continuedFraction.length; i++) { continuedFraction[i] = valueOf(continuedFraction[i]); } return continuedFraction; } /** * Convergents. * * @param x The value. * @param n Maximum number of convergents. * * @return The convergents. * * @exception IllegalArgumentException If n is less than one. * * @since 1.12.0 */ public Apfloat[] convergents(Apfloat x, int n) throws ApfloatRuntimeException { Apfloat[] convergents = ApfloatMath.convergents(setPrecision(x), n); convergents = Arrays.copyOf(convergents, convergents.length, Apfloat[].class); for (int i = 0; i < convergents.length; i++) { convergents[i] = valueOf(convergents[i]); } return convergents; } /** * Maximum value. * * @param x The first operand. * @param y The second operand. * * @return The maximum of x and y. * * @since 1.9.0 */ public Apfloat max(Apfloat x, Apfloat y) throws ApfloatRuntimeException { return valueOf(ApfloatMath.max(setPrecision(x), setPrecision(y))); } /** * Minimum value. * * @param x The first operand. * @param y The second operand. * * @return The minimum of x and y. * * @since 1.9.0 */ public Apfloat min(Apfloat x, Apfloat y) throws ApfloatRuntimeException { return valueOf(ApfloatMath.min(setPrecision(x), setPrecision(y))); } /** * The number adjacent to the first argument in the direction of the second argument. * * @param x The first operand. * @param y The second operand. * * @return The number adjacent to the first argument in the direction of the second argument. * * @since 1.10.0 */ public Apfloat nextAfter(Apfloat x, Apfloat y) throws ApfloatRuntimeException { return valueOf(ApfloatMath.nextAfter(setPrecision(x), setPrecision(y))); } /** * The adjacent value closer to negative infinity. * * @param x The operand. * * @return The adjacent value closer to negative infinity. * * @since 1.10.0 */ public Apfloat nextDown(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.nextDown(setPrecision(x))); } /** * The adjacent value closer to positive infinity. * * @param x The operand. * * @return The adjacent value closer to positive infinity. * * @since 1.10.0 */ public Apfloat nextUp(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.nextUp(setPrecision(x))); } /** * Unit in the last place. * * @param x The operand. * * @return The unit in the last place. * * @since 1.10.0 */ public Apfloat ulp(Apfloat x) throws ApfloatRuntimeException { return valueOf(ApfloatMath.ulp(setPrecision(x))); } private Apfloat setPrecision(Apfloat x) throws ApfloatRuntimeException { return x.precision(precision()); } private Apfloat[] setPrecision(Apfloat[] x) throws ApfloatRuntimeException { Apfloat[] tmp = new Apfloat[x.length]; for (int i = 0; i < x.length; i++) { tmp[i] = setPrecision(x[i]); } return tmp; } private Apfloat checkSmallLinear(Apfloat x) { if (x.scale() <= -precision()) { return setPrecision(x); } return null; } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/FormattingHelper.java000066400000000000000000000207131461767713300256610ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.io.Flushable; import java.io.Writer; import java.io.FilterWriter; import java.io.StringWriter; import java.io.IOException; import java.text.DecimalFormatSymbols; import java.util.Formatter; import java.util.Locale; /** * Helper class for formatting. * * @version 1.8.3 * @author Mikko Tommila */ class FormattingHelper { private static class AppendableWriter extends Writer { public AppendableWriter(Appendable out) { this.out = out; } @Override public void write(int c) throws IOException { this.out.append((char) c); } @Override public void write(char[] buffer, int offset, int length) throws IOException { for (int i = 0; i < length; i++) { this.out.append(buffer[i + offset]); } } @Override public void write(String text, int offset, int length) throws IOException { this.out.append(text, offset, length); } @Override public Writer append(CharSequence sequence) throws IOException { this.out.append(sequence); return this; } @Override public Writer append(CharSequence sequence, int start, int end) throws IOException { this.out.append(sequence, start, end); return this; } @Override public void flush() throws IOException { if (this.out instanceof Flushable) { ((Flushable) this.out).flush(); } } @Override public void close() throws IOException { if (this.out instanceof AutoCloseable) { try { ((AutoCloseable) this.out).close(); } catch (IOException ioe) { throw ioe; } catch (Exception e) { throw new IOException(e); } } } private Appendable out; } private static class LocalizeWriter extends FilterWriter { public LocalizeWriter(Writer out, Locale locale, boolean localizeDigits, boolean isUpperCase) { super(out); this.locale = locale; this.localizeDigits = localizeDigits; this.isUpperCase = isUpperCase; if (locale != null) { DecimalFormatSymbols decimalFormatSymbols = new DecimalFormatSymbols(locale); this.zero = decimalFormatSymbols.getZeroDigit(); this.decimalSeparator = decimalFormatSymbols.getDecimalSeparator(); } else { this.zero = '0'; this.decimalSeparator = '.'; } } @Override public void write(int c) throws IOException { if (c == '.') { c = this.decimalSeparator; } else if (this.localizeDigits && c >= '0' && c <= '9') { c += this.zero - '0'; } if (this.isUpperCase) { String s; if (this.locale == null) { s = String.valueOf((char) c).toUpperCase(); } else { s = String.valueOf((char) c).toUpperCase(this.locale); } for (int i = 0; i < s.length(); i++) { super.write(s.charAt(i)); } } else { super.write(c); } } @Override public void write(char[] buffer, int offset, int length) throws IOException { for (int i = 0; i < length; i++) { write(buffer[i + offset]); } } @Override public void write(String text, int offset, int length) throws IOException { for (int i = 0; i < length; i++) { write(text.charAt(i + offset)); } } private Locale locale; private boolean localizeDigits; private boolean isUpperCase; private char zero; private char decimalSeparator; } private static class CountWriter extends FilterWriter { public CountWriter(Writer out) { super(out); } @Override public void write(int c) throws IOException { super.write(c); this.count++; } @Override public void write(char[] buffer, int offset, int length) throws IOException { super.write(buffer, offset, length); this.count += length; } @Override public void write(String text, int offset, int length) throws IOException { super.write(text, offset, length); this.count += length; } public long count() { return this.count; } private long count; } private static class BufferWriter extends StringWriter { public BufferWriter(Writer out) { this.out = out; } public Writer out() { return this.out; } private Writer out; } private FormattingHelper() { } public static Writer wrapAppendableWriter(Appendable out) { return (out instanceof Writer ? (Writer) out : new AppendableWriter(out)); } public static Writer wrapLocalizeWriter(Writer out, Formatter formatter, int radix, boolean isUpperCase) { return new LocalizeWriter(out, formatter.locale(), radix <= 10, isUpperCase); } public static Writer wrapPadWriter(Writer out, boolean isLeftJustify) { if (isLeftJustify) { out = new CountWriter(out); } else { out = new BufferWriter(out); } return out; } public static void finishPad(Writer out, long width) throws IOException { if (out instanceof CountWriter) { CountWriter counter = (CountWriter) out; long count = width - counter.count(); pad(out, count); } else { BufferWriter buffer = (BufferWriter) out; long count = width - buffer.getBuffer().length(); pad(buffer.out(), count); buffer.out().append(buffer.getBuffer()); } } private static void pad(Appendable out, long count) throws IOException { for (long i = 0; i < count; i++) { out.append(' '); } } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/GCDHelper.java000066400000000000000000000240431461767713300241440ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import org.apfloat.spi.Util; import static org.apfloat.ApintMath.abs; import static org.apfloat.ApintMath.scale; /** * Binary recursive GCD algorithm implementation. * * @since 1.6 * @version 1.10.0 * @author Mikko Tommila */ class GCDHelper { // Simple 2x2 matrix class private static class Matrix { public Matrix(Apint r11, Apint r12, Apint r21, Apint r22) { this.r11 = r11; this.r12 = r12; this.r21 = r21; this.r22 = r22; } public Matrix multiply(Matrix a) throws ApfloatRuntimeException { return new Matrix(multiplyAdd(this.r11, a.r11, this.r12, a.r21), multiplyAdd(this.r11, a.r12, this.r12, a.r22), multiplyAdd(this.r21, a.r11, this.r22, a.r21), multiplyAdd(this.r21, a.r12, this.r22, a.r22)); } private static Apint multiplyAdd(Apint a, Apint b, Apint c, Apint d) throws ApfloatRuntimeException { return a.multiply(b).add(c.multiply(d)); } public final Apint r11; public final Apint r12; public final Apint r21; public final Apint r22; } // Return type for the half-gcd method private static class HalfGcdType { public HalfGcdType(long j, Matrix r) { this.j = j; this.r = r; } public final long j; public final Matrix r; } private GCDHelper() { } public static Apint gcd(Apint a, Apint b) throws ApfloatRuntimeException { if (a.signum() == 0) { return abs(b); // Thanks to Marko Gaspersic for finding the bug in issue #11 } if (b.signum() == 0) { return abs(a); // Thanks to Marko Gaspersic for finding the bug in issue #11 } // First reduce the numbers so that they have roughly the same size, regardless of algorithm used if (a.scale() > b.scale()) { a = a.mod(b); } else if (b.scale() > a.scale()) { b = b.mod(a); } Apint gcd; if (Math.max(a.scale(), b.scale()) * Math.log(Math.max(a.radix(), b.radix())) < 80000) { // Small number, use the O(n^2) simple algorithm gcd = elementaryGcd(a, b); } else { // Big number, use the O(n log n) divide-and-conquer algorithm gcd = recursiveGcd(a, b); } return gcd; } private static Apint elementaryGcd(Apint a, Apint b) throws ApfloatRuntimeException { while (b.signum() != 0) { Apint r = a.mod(b); a = b; b = r; } return abs(a); } private static Apint recursiveGcd(Apint a, Apint b) throws ApfloatRuntimeException { if (a.radix() != 2 || b.radix() != 2) { // This algorithm only works with binary numbers; convert to radix 2 and then back to original radix return recursiveGcd(a.toRadix(2), b.toRadix(2)).toRadix(a.radix()); } // First count the trailing zero bits of each number - the power of two factor in the gcd long zeros = Math.min(v(a), v(b)); // Then remove the trailing zeros (it doesn't matter if one number has more zeros than the other), and add one zero to b // The algorithm only works if a has no trailing zeros, and b has at least one a = scale(a, -v(a)); b = scale(b, 1 - v(b)); // Call the recursive algorithm to compute the odd part of the gcd; initial k is the bit length of the numbers long k = Math.max(a.scale(), b.scale()); HalfGcdType t = halfBinaryGcd(a, b, k); long j = t.j; Matrix result = t.r; // As the output of the recursive algorithm, we get two terms of the remainder sequence (like in the elementary algorithm) Apint c = scale(result.r11.multiply(a).add(result.r12.multiply(b)), -2 * j), d = scale(result.r21.multiply(a).add(result.r22.multiply(b)), -2 * j); // We have to check if these terms are the *last* terms of the remainder sequence Apint gcd; if (d.signum() == 0) { // If d = 0 then c is the odd part of the gcd: c and d are the last terms of the remainder sequence. gcd = c; } else { // However, with large numbers, the initial k argument for the recursive algorithm isn't many times sufficient, // and c and d are not actually the last terms of the remainder sequence. So we continue computing the remainder // sequence, until we reach the last terms, to find the gcd (odd part). // The numbers remaining in the sequence are small, O(log n), compared to the original input numbers, so the elementary // algorithm is sufficient for all practical purposes. gcd = elementaryGcd(c, d); } // Finally scale the odd part of the gcd by the number of trailing zeros in the original numbers return abs(scale(gcd, zeros)); } // Based on the "Recursive Binary GCD Algorithm" by Damien Stehlé and Paul Zimmermann. // Adapted from the algorithm presented in "Modern Computer Arithmetic" v. 0.5.9 by Richard P. Brent and Paul Zimmermann. private static HalfGcdType halfBinaryGcd(Apint a, Apint b, long k) throws ApfloatRuntimeException { assert (v(a) < v(b)); Apint one = new Apint(1, 2); if (v(b) > k) { return new HalfGcdType(0, new Matrix(one, Apint.ZERO, Apint.ZERO, one)); } long k1 = k >> 1; Apint a1 = a.mod(powerOfTwo(2 * k1 + 1)), b1 = b.mod(powerOfTwo(2 * k1 + 1)); HalfGcdType t1 = halfBinaryGcd(a1, b1, k1); long j1 = t1.j; Apint ac = scale(t1.r.r11.multiply(a).add(t1.r.r12.multiply(b)), -2 * j1), bc = scale(t1.r.r21.multiply(a).add(t1.r.r22.multiply(b)), -2 * j1); long j0 = v(bc); if (Util.ifFinite(j0, j0 + j1) > k) { return t1; } Apint[] qr = binaryDivide(ac, bc); Apint q = qr[0], r = qr[1]; long k2 = k - (j0 + j1); Apint a2 = scale(bc, -j0).mod(powerOfTwo(2 * k2 + 1)), b2 = scale(r, -j0).mod(powerOfTwo(2 * k2 + 1)); HalfGcdType t2 = halfBinaryGcd(a2, b2, k2); long j2 = t2.j; Matrix qm = new Matrix(Apint.ZERO, powerOfTwo(j0), powerOfTwo(j0), q), result = t2.r.multiply(qm).multiply(t1.r); long j = j1 + j0 + j2; return new HalfGcdType(j, result); } // The fast "generalized binary division" algorithm. // This is another quite strange algorithm, producing a "quotient" and "remainder" // but not like in a normal division algorithm. Instead of removing the high-order // bits (like in normal division) this algorithm removes the lowest-order bits. // It kind of makes sense if you consider the numbers as p-adic numbers. private static Apint[] binaryDivide(Apint a, Apint b) throws ApfloatRuntimeException { assert (a.signum() != 0); assert (b.signum() != 0); assert (v(a) < v(b)); Apint A = scale(a, -v(a)).negate(), B = scale(b, -v(b)), one = new Apint(1, 2), q = one; long n = v(b) - v(a) + 1; int maxN = Util.log2up(n); for (int i = 1; i <= maxN; i++) { q = q.add(q.multiply(one.subtract(B.multiply(q)))).mod(powerOfTwo(1L << i)); } q = cmod(A.multiply(q), powerOfTwo(n)); Apint r = q.multiply(b).divide(powerOfTwo(n - 1)).add(a); return new Apint[] { q, r }; } // The p-adic valuation of the number i.e. the number of trailing zero bits (for 2-adic numbers) private static long v(Apint a) throws ApfloatRuntimeException { if (a.signum() == 0) { return Apfloat.INFINITE; } return a.scale() - a.size(); } // Returns 2^n private static Apint powerOfTwo(long n) throws ApfloatRuntimeException { assert (n >= 0); return scale(new Apint(1, 2), n); } // Centered modulus i.e. modulus but scaled so that the result is -2/m < r <= 2/m private static Apint cmod(Apint a, Apint m) throws ApfloatRuntimeException { a = a.mod(m); Apint halfM = scale(m, -1); a = (a.compareTo(halfM) > 0 ? a.subtract(m) : a); a = (a.compareTo(halfM.negate()) <= 0 ? a.add(m) : a); return a; } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/HurwitzZetaHelper.java000066400000000000000000000303761461767713300260550ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.Iterator; import org.apfloat.spi.Util; import static org.apfloat.ApcomplexMath.isNonPositiveInteger; /** * Helper class for the Hurwitz zeta function. * * @since 1.11.0 * @version 1.14.0 * @author Mikko Tommila */ class HurwitzZetaHelper { // See https://arxiv.org/pdf/1309.2877.pdf // Rigorous high-precision computation of the Hurwitz zeta function and its derivatives, Fredrik Johansson public static Apcomplex zeta(Apcomplex s, Apcomplex a) { int radix = a.radix(); Apint one = new Apint(1, radix); if (s.equals(one)) { throw new ArithmeticException("Zeta of first argument one"); } if (s.isZero() && a.isZero()) { Apint two = new Apint(2, radix); return new Aprational(one, two); } Apcomplex sOrig = s; long targetPrecision = Math.min(s.precision(), a.precision()), precision = ApfloatHelper.extendPrecision(targetPrecision); s = ApfloatHelper.ensurePrecision(s, precision); a = ApfloatHelper.ensurePrecision(a, precision); if (isNonPositiveInteger(s)) { // Handle cases where the result might be genuinely zero long n1 = ApfloatHelper.longValueExact(one.subtract(s.real().truncate())); return bernoulliB(n1, a).divide(new Apfloat(n1, targetPrecision, radix)).negate(); } if (isNonPositiveInteger(a)) { if (s.real().signum() < 0 || s.isZero()) { // Use recurrence formula: zeta(s, a) = a^-s + zeta(s, a + 1) Apcomplex t = Apcomplex.ZERO, sn = s.negate(); long i = ApfloatHelper.longValueExact(a.real().truncate()); while (i++ <= 0) { t = t.add(ApcomplexMath.pow(a, sn)); a = a.add(one); } t = ApfloatHelper.reducePrecision(t); s = sOrig; a = a.precision(targetPrecision); Apcomplex z = zeta(s, a); if (t.isZero()) { return z; } return t.add(ApfloatHelper.ensurePrecision(z, precision)); } throw new ArithmeticException("Zeta of second argument nonpositive integer"); } if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate zeta function to infinite precision"); } long doublePrecision = ApfloatHelper.getDoublePrecision(radix); // Must be: ℜ(a) + N > 1 and ℜ(s) + 2M > 1 // We can set N = M for a basic case // Far in the critical strip N should be larger than M for better efficiency // Note that the search is for the absolute size of the error term, not the relative error (relative to the value of the zeta function being evaluated) // Thus we would first need some guess for the scale of the value of the Hurwitz zeta function, to have a goal for the size of the error term long zetaScale = Math.min(0, zetaScale(s.precision(doublePrecision), a.precision(doublePrecision))), targetScale = -Util.ifFinite(-zetaScale, targetPrecision - zetaScale), precisionLoss; Apcomplex result; do { Apint N = binarySearch(s, a, targetPrecision, targetScale), // s could be a nonpositive near-integer so easier not to round it to avoid getting a zero from the Pochammer symbol M = N; Apcomplex I = I(s, a, N), S = S(s, a, N.longValueExact()), T = T(s, a, N, M.longValueExact()); result = S.add(I).add(T); precisionLoss = (result.isZero() ? precision : targetPrecision - result.precision()); // Assumed that the result can't be exactly zero because those are handled by the polynomial case above (the real zeros) if (precisionLoss > 0) { precision = Util.ifFinite(precision, precision + precisionLoss); targetScale = -Util.ifFinite(-targetScale, -targetScale + precisionLoss); s = ApfloatHelper.ensurePrecision(s, precision); a = ApfloatHelper.ensurePrecision(a, precision); } } while (precisionLoss > 0); return ApfloatHelper.limitPrecision(result, targetPrecision); } private static long zetaScale(Apcomplex s, Apcomplex a) { // Increase the precision to avoid loss of precision exception long extraPrecision = Math.max(0, Math.max(s.scale(), a.scale())); Apint one = Apint.ONES[a.radix()]; s = ApfloatHelper.extendPrecision(s, extraPrecision); a = ApfloatHelper.extendPrecision(a, extraPrecision); return ApcomplexMath.pow(a, one.subtract(s)).divide(s.subtract(one)).scale(); // Is not actually valid if re(s) <= 1 or re(a) <= 0 } private static Apint binarySearch(Apcomplex s, Apcomplex a, long precision, long targetScale) { int radix = a.radix(); Apint one = Apint.ONES[radix], two = new Apint(2, radix), min = ApintMath.max(two.subtract(a.real().truncate()), one.subtract(s.real()).divide(two).truncate().add(one)), N = ApintMath.max(new Apint(precision, radix), min); long M = ApfloatHelper.longValueExact(N), low = M, high = M; Apfloat R = R(s, a, N, M); // Initial search to find another point on the other side // double or halve the current point to find it while (R.scale() >= targetScale) { low = M; // R is too large, M is too small M = Util.multiplyExact(2, M); N = new Apint(M, radix); R = R(s, a, N, M); high = M; } if (low == high) { long lowLimit = Math.max(0, min.longValueExact()); while (R.scale() < targetScale && M > lowLimit) { high = M; // R is too small, M is too large M = Math.max(M >> 1, lowLimit); N = new Apint(M, radix); R = R(s, a, N, M); low = M; } } // Now that we have a range [low, high] find the point where R.scale() is just less than targetScale while (high - low > 1) { // Test mid point of range M = high + low >>> 1; N = new Apint(M, radix); R = R(s, a, N, M); if (R.scale() >= targetScale) { // Mid point R is too large, M is too small low = M; } else { // Mid point R is too small, M is too large high = M; } } return new Apint(high, radix); } private static Apfloat R(Apcomplex s, Apcomplex a, Apint N, long M) { int radix = a.radix(); Apint two = new Apint(2, radix), four = new Apint(4, radix), M2 = new Apint(2 * M, radix); Apfloat σ = s.real(), τ = s.imag(), α = a.real(), β = a.imag(), pi = ApfloatMath.pi(ApfloatHelper.getDoublePrecision(radix), radix); Apfloat K = ApfloatMath.exp(ApfloatMath.max(Apfloat.ZEROS[radix], expPrecision(τ.multiply(ApfloatMath.atan(β.divide(α.add(N))))))), R = K.multiply(J(N.add(α), σ.add(M2))); return four.multiply(ApcomplexMath.abs(pochhammer(s, 2 * M))).divide(ApfloatMath.pow(two.multiply(pi), 2 * M)).multiply(ApfloatMath.abs(R)); } private static Apfloat J(Apfloat A, Apfloat B) { Apint one = Apint.ONES[A.radix()]; Apfloat B1 = B.subtract(one); return one.divide(B1.multiply(ApfloatMath.pow(A, B1))); } private static Apcomplex pochhammer(Apcomplex s, long n) { return ApcomplexMath.pochhammer(s, new Apfloat(n, s.precision(), s.radix())); } private static Apcomplex S(Apcomplex s, Apcomplex a, long N) { int radix = a.radix(); Apcomplex sum = Apcomplex.ZEROS[radix]; for (long k = 0; k < N; k++) { sum = sum.add(ApcomplexMath.pow(a.add(new Apint(k, radix)), s.negate())); } return sum; } private static Apcomplex I(Apcomplex s, Apcomplex a, Apint N) { int radix = a.radix(); Apint one = Apint.ONES[radix]; return ApcomplexMath.pow(a.add(N), one.subtract(s)).divide(s.subtract(one)); } private static Apcomplex T(Apcomplex s, Apcomplex a, Apint N, long M) { int radix = a.radix(); Apint one = Apint.ONES[radix]; Apcomplex sum = new Aprational(one, new Apint(2, radix)), aN = a.add(N), aN2 = ApcomplexMath.pow(aN, -2), pochhammer = s, factor = pochhammer.divide(aN); Iterator bernoullis = AprationalMath.bernoullis2(M, radix); for (long k = 1; k <= M; k++) { factor = factor.divide(new Apint(2 * k - 1, radix).multiply(new Apint(2 * k, radix))); sum = sum.add(bernoullis.next().multiply(factor)); if (k < M) { pochhammer = pochhammer.add(one); factor = factor.multiply(pochhammer); pochhammer = pochhammer.add(one); factor = factor.multiply(pochhammer).multiply(aN2); } } return sum.multiply(ApcomplexMath.pow(aN, s.negate())); } private static Apfloat expPrecision(Apfloat x) { // Increase the precision to avoid loss of precision exception return ApfloatHelper.extendPrecision(x, Math.max(0, x.scale())); } // Bernoulli polynomial, calculated as a polynomial // z assumed to be of extended precision already private static Apcomplex bernoulliB(long n, Apcomplex z) { assert (n > 0); long precision = z.precision(); int radix = z.radix(); if (z.isZero()) { return AprationalMath.bernoulli(n, radix); } Apcomplex sum = Apcomplex.ZEROS[radix], numerator = new Apfloat(1, precision, radix), denominator = numerator; Iterator bernoullis = AprationalMath.bernoullis(n, radix); for (long k = 0; k <= n; k++) { Aprational b = bernoullis.next(); sum = sum.add(b.multiply(numerator).divide(denominator)); if (k < n) { numerator = numerator.multiply(new Apint(n - k, radix)); denominator = denominator.multiply(new Apint(k + 1, radix)).multiply(z); } } sum = sum.multiply(ApcomplexMath.pow(z, n)); return ApfloatHelper.reducePrecision(sum); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/HypergeometricHelper.java000066400000000000000000001332421461767713300265370ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.stream.Stream; import org.apfloat.spi.Util; import static java.util.Comparator.comparing; import static org.apfloat.ApcomplexMath.abs; import static org.apfloat.ApcomplexMath.exp; import static org.apfloat.ApcomplexMath.gamma; import static org.apfloat.ApcomplexMath.isNonPositiveInteger; import static org.apfloat.ApcomplexMath.pow; import static org.apfloat.ApcomplexMath.sin; import static org.apfloat.ApcomplexMath.sqrt; import static org.apfloat.ApfloatMath.pi; import static org.apfloat.ApfloatMath.scale; /** * Helper class for hypergeometric functions. * * @since 1.11.0 * @version 1.14.0 * @author Mikko Tommila */ class HypergeometricHelper { // See: Computing hypergeometric functions rigorously by Fredrik Johansson, https://arxiv.org/pdf/1606.06977.pdf private static class RetryException extends RuntimeException { public RetryException(long precisionLoss) { this.precisionLoss = precisionLoss; } public long getPrecisionLoss() { return precisionLoss; } private static final long serialVersionUID = 1L; private long precisionLoss; } private static class NotConvergingException extends RuntimeException { private static final long serialVersionUID = 1L; } private class Hypergeometric2F1Helper { public Hypergeometric2F1Helper(boolean retry) { this.a = HypergeometricHelper.this.a[0]; this.b = HypergeometricHelper.this.a[1]; this.c = HypergeometricHelper.this.b[0]; this.z = HypergeometricHelper.this.z; this.one = HypergeometricHelper.this.one; this.retry = retry; } public void ensurePrecisions() { a = ensurePrecision(a); b = ensurePrecision(b); c = ensurePrecision(c); z = ensurePrecision(z); } public void adjustIntegerAB() { // Transforms T2 and T3 are of the form factor * (term1 - term2) where term1 and term2 can be very close to each other, so overall precision needs to be increased to get the actual result, instead of just zero Apcomplex ab = a.subtract(b); long digitLoss; if (ab.isInteger()) { // Adjust the one which has larger magnitude in real part swapLargerAB(); digitLoss = workingPrecision; workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); Apfloat offset = offset(-digitLoss); if (!b.equals(offset)) // It might be that b is exactly the same as the offset so a - b is not integer after all (but would be if we did add the offset), we just need to increase the precisions { a = new Apcomplex(a.real().precision(Apfloat.INFINITE).add(offset), a.imag()); } b = new Apcomplex(adjustOffset(b.real(), offset), b.imag()); ensurePrecisions(); } else { Apint abRounded = RoundingHelper.roundToInteger(ab.real(), RoundingMode.HALF_EVEN).truncate(); digitLoss = Math.min(workingPrecision, -ab.subtract(abRounded).scale()); if (digitLoss > 0) { workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); // Set precision of a and b so that after computing a - b the difference still has the required precision Apfloat offset = offset(-digitLoss); a = new Apcomplex(adjustOffset(a.real(), offset), a.imag()); b = new Apcomplex(adjustOffset(b.real(), offset), b.imag()); ensurePrecisions(); } } } public void adjustIntegerCAB() { // Transforms T4 and T5 are of the form factor * (term1 - term2) where term1 and term2 can be very close to each other, so overall precision needs to be increased to get the actual result, instead of just zero Apcomplex cab = c.subtract(a).subtract(b); long digitLoss; if (cab.isInteger()) { Apcomplex aOrig = a, bOrig = b, cOrig = c; // Adjust the one which has largest magnitude in real part swapLargerAB(); digitLoss = workingPrecision; workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); Apfloat offset = offset(-digitLoss); if (c.real().scale() > a.real().scale()) { c = new Apcomplex(c.real().precision(Apfloat.INFINITE).add(offset), c.imag()); a = new Apcomplex(adjustOffset(a.real(), offset), a.imag()); } else { c = new Apcomplex(adjustOffset(c.real(), offset), c.imag()); a = new Apcomplex(a.real().precision(Apfloat.INFINITE).add(offset), a.imag()); } b = new Apcomplex(adjustOffset(b.real(), offset), b.imag()); ensurePrecisions(); if (c.subtract(a).subtract(b).isInteger()) { // It could be that a+b happened to be equal to the offset, to suitable precision, so we don't need to adjust by offset after all, we just need to increase the precision a = aOrig; b = bOrig; c = cOrig; ensurePrecisions(); assert (!c.subtract(a).subtract(b).isInteger()); } } else { Apint cabRounded = RoundingHelper.roundToInteger(cab.real(), RoundingMode.HALF_EVEN).truncate(); digitLoss = Math.min(workingPrecision, -cab.subtract(cabRounded).scale()); if (digitLoss > 0) { workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); Apfloat offset = offset(-digitLoss); a = new Apcomplex(adjustOffset(a.real(), offset), a.imag()); b = new Apcomplex(adjustOffset(b.real(), offset), b.imag()); c = new Apcomplex(adjustOffset(c.real(), offset), c.imag()); ensurePrecisions(); } } } private void swapLargerAB() { if (a.real().scale() < b.real().scale()) { // a is always the one that has larger magnitude in real part Apcomplex tmp = a; a = b; b = tmp; } } public Apcomplex transform(Apcomplex s, Apcomplex c, Apcomplex base1, Apcomplex exp1, Apcomplex g1, Apcomplex g2, Apcomplex a1, Apcomplex b1, Apcomplex c1, Apcomplex base2, Apcomplex exp2, Apcomplex base3, Apcomplex exp3, Apcomplex g3, Apcomplex g4, Apcomplex a2, Apcomplex b2, Apcomplex c2, Apcomplex z) { Apcomplex term1, term2; if (isNonPositiveInteger(g1) || isNonPositiveInteger(g2)) { term1 = zero; // Division by infinity } else { term1 = pow(base1, exp1).divide(gamma(g1).multiply(gamma(g2)).multiply(gamma(c1))).multiply(evaluate(a1, b1, c1, z)); } if (isNonPositiveInteger(g3) || isNonPositiveInteger(g4)) { term2 = zero; // Division by infinity } else { term2 = pow(base2, exp2).multiply(pow(base3, exp3)).divide(gamma(g3).multiply(gamma(g4)).multiply(gamma(c2))).multiply(evaluate(a2, b2, c2, z)); } Apcomplex d = term1.subtract(term2); long precisionLoss = (d.isZero() ? workingPrecision : targetPrecision - d.precision()); if (retry && precisionLoss > 1) // Allow a precision loss of 1 (which happens often), otherwise retry with increased precision { throw new RetryException(precisionLoss); } Apfloat pi = pi(workingPrecision, radix); return gamma(c).multiply(pi).divide(sin(pi.multiply(s))).multiply(d); } private Apcomplex evaluate(Apcomplex a, Apcomplex b, Apcomplex c, Apcomplex z) { return HypergeometricHelper.this.evaluate(new Apcomplex[] { a, b }, new Apcomplex[] { c }, z); } public Apcomplex a, b, c, z; public Apint one; private boolean retry; } // T0 is the direct evaluation of the series without transformation, T1 - T5 are as per DLMF 15.8.1 - 15.8.5 private static enum Transformation { T0 { @Override public boolean isApplicable(Apcomplex z) { return true; } @Override public Apcomplex z(Apcomplex z) { return z; } @Override public Apcomplex value(Hypergeometric2F1Helper helper) { Apcomplex a = helper.a, b = helper.b, c = helper.c, z = helper.z; return helper.evaluate(a, b, c, z); } }, T1 { @Override public boolean isApplicable(Apcomplex z) { return !z.equals(Apint.ONES[z.radix()]); } @Override public Apcomplex z(Apcomplex z) { Apint one = Apint.ONES[z.radix()]; return z.divide(z.subtract(one)); } @Override public Apcomplex value(Hypergeometric2F1Helper helper) { Apint one = helper.one; Apcomplex a = helper.a, b = helper.b, c = helper.c, z = helper.z, z1 = one.subtract(z), s = c.subtract(a), t = c.subtract(b); if (isNonPositiveInteger(s) && (!isNonPositiveInteger(t) || s.real().compareTo(t.real()) >= 0)) { return ApcomplexMath.pow(z1, b.negate()).multiply(helper.evaluate(s, b, c, z(z))); } return ApcomplexMath.pow(z1, a.negate()).multiply(helper.evaluate(a, t, c, z(z))); } }, T2 { @Override public boolean isApplicable(Apcomplex z) { return !z.isZero(); } @Override public Apcomplex z(Apcomplex z) { Apint one = Apint.ONES[z.radix()]; return one.divide(z); } @Override public Apcomplex value(Hypergeometric2F1Helper helper) { helper.adjustIntegerAB(); Apint one = helper.one; Apcomplex a = helper.a, b = helper.b, c = helper.c, z = helper.z; return helper.transform(b.subtract(a), c, z.negate(), a.negate(), b, c.subtract(a), a, a.subtract(c).add(one), a.subtract(b).add(one), z.negate(), b.negate(), one, one, a, c.subtract(b), b, b.subtract(c).add(one), b.subtract(a).add(one), z(z)); } }, T3 { @Override public boolean isApplicable(Apcomplex z) { return !z.equals(Apint.ONES[z.radix()]); } @Override public Apcomplex z(Apcomplex z) { Apint one = Apint.ONES[z.radix()]; return one.divide(one.subtract(z)); } @Override public Apcomplex value(Hypergeometric2F1Helper helper) { helper.adjustIntegerAB(); Apint one = helper.one; Apcomplex a = helper.a, b = helper.b, c = helper.c, z = helper.z; return helper.transform(b.subtract(a), c, one.subtract(z), a.negate(), b, c.subtract(a), a, c.subtract(b), a.subtract(b).add(one), one.subtract(z), b.negate(), one, one, a, c.subtract(b), b, c.subtract(a), b.subtract(a).add(one), z(z)); } }, T4 { @Override public boolean isApplicable(Apcomplex z) { return true; } @Override public Apcomplex z(Apcomplex z) { Apint one = Apint.ONES[z.radix()]; return one.subtract(z); } @Override public Apcomplex value(Hypergeometric2F1Helper helper) { helper.adjustIntegerCAB(); Apint one = helper.one; Apcomplex a = helper.a, b = helper.b, c = helper.c, z = helper.z; return helper.transform(c.subtract(b).subtract(a), c, one, one, c.subtract(a), c.subtract(b), a, b, a.add(b).subtract(c).add(one), one.subtract(z), c.subtract(a).subtract(b), one, one, a, b, c.subtract(a), c.subtract(b), c.subtract(a).subtract(b).add(one), z(z)); } }, T5 { @Override public boolean isApplicable(Apcomplex z) { return !z.isZero(); } @Override public Apcomplex z(Apcomplex z) { Apint one = Apint.ONES[z.radix()]; return one.subtract(one.divide(z)); } @Override public Apcomplex value(Hypergeometric2F1Helper helper) { helper.adjustIntegerCAB(); Apint one = helper.one; Apcomplex a = helper.a, b = helper.b, c = helper.c, z = helper.z; return helper.transform(c.subtract(b).subtract(a), c, z, a.negate(), c.subtract(a), c.subtract(b), a, a.subtract(c).add(one), a.add(b).subtract(c).add(one), one.subtract(z), c.subtract(a).subtract(b), z, a.subtract(c), a, b, c.subtract(a), one.subtract(a), c.subtract(a).subtract(b).add(one), z(z)); } }; public abstract boolean isApplicable(Apcomplex z); public abstract Apcomplex z(Apcomplex z); public abstract Apcomplex value(Hypergeometric2F1Helper helper); } /** * Helper for the generalized hypergeometric function pFq.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param z The third argument. */ private HypergeometricHelper(Apcomplex[] a, Apcomplex[] b, Apcomplex z) { this.radix = z.radix(); this.extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix); this.targetPrecision = ApfloatHelper.extendPrecision(precision(a, b, z), extraPrecision); this.workingPrecision = targetPrecision; this.a = Arrays.stream(a).map(c -> ApfloatHelper.extendPrecision(c, extraPrecision)).toArray(Apcomplex[]::new); this.b = Arrays.stream(b).map(c -> ApfloatHelper.extendPrecision(c, extraPrecision)).toArray(Apcomplex[]::new); this.z = ensurePrecision(z); this.one = Apint.ONES[radix]; this.zero = Apint.ZEROS[radix]; } /** * Generalized hypergeometric function pFq.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param z The third argument. * * @return pFq(a1, …, ap; b1, …, bq; z) * * @throws ArithmeticException If the series does not converge. */ public static Apcomplex hypergeometricPFQ(Apcomplex[] a, Apcomplex[] b, Apcomplex z) { HypergeometricHelper helper = new HypergeometricHelper(a, b, z); return helper.result(helper.hypergeometricPFQ()); } /** * Regularized generalized hypergeometric function pq.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param z The third argument. * * @return pq(a1, …, ap; b1, …, bq; z) * * @throws ArithmeticException If the series does not converge. * * @since 1.13.0 */ public static Apcomplex hypergeometricPFQRegularized(Apcomplex[] a, Apcomplex[] b, Apcomplex z) { HypergeometricHelper helper = new HypergeometricHelper(a, b, z); return helper.result(helper.hypergeometricPFQRegularized()); } private Apcomplex hypergeometricPFQRegularized() { Apcomplex result; Apfloat n = null; int j = -1; // Find smallest integer from b that is <= 0, if any for (int i = 0; i < b.length; i++) { Apfloat br = b[i].real().negate(); if (isNonPositiveInteger(b[i])) { if (n == null) { j = i; n = br; } else if (br.compareTo(n) > 0) { j = i; n = br; } } } if (n == null) { // None of the b is a nonpositive integer, regularization is trivial Apcomplex[] gamma = Arrays.stream(b).map(this::ensureGammaPrecision).map(ApcomplexMath::gamma).toArray(Apcomplex[]::new); result = hypergeometricPFQ().divide(ApcomplexMath.product(gamma)); } else { // At least one of the b is a nonpositive integer, regularization needs to be done by omitting the terms where the divisor is infinite int radix = z.radix(); Apfloat n1 = n.add(Apint.ONES[radix]); Apcomplex[] pochhammer = Arrays.stream(a).map(ai -> ApcomplexMath.pochhammer(ai, n1)).toArray(Apcomplex[]::new); result = ApcomplexMath.product(pochhammer); if (!result.isZero()) { Apfloat n2 = n.add(new Apint(2, radix)); Apcomplex[] gamma = Arrays.stream(b).map(n1::add).map(this::ensureGammaPrecision).map(ApcomplexMath::gamma).toArray(Apcomplex[]::new); result = result.multiply(ApcomplexMath.pow(z, n1)).divide(ApcomplexMath.gamma(n2).multiply(ApcomplexMath.product(gamma))); a = Arrays.stream(a).map(n1::add).toArray(Apcomplex[]::new); b = Arrays.stream(b).map(n1::add).toArray(Apcomplex[]::new); b[j] = n2; result = result.multiply(hypergeometricPFQ()); } } return result; } /** * Tricomi's confluent hypergeometric function U. * Also known as the confluent hypergeometric function of the second kind.

* * @implNote * This implementation is slow, meaning that it isn't a fast algorithm. * It is impractically slow beyond a precision of a few thousand digits. At the time of * implementation no generic fast algorithm is known for the function. * * @param a The first argument. * @param b The second argument. * @param z The third argument. * @param fastOnly Only attempt relatively fast algorithms and return null if not applicable * * @return U(a, b, z) * * @since 1.13.0 */ public static Apcomplex hypergeometricU(Apcomplex a, Apcomplex b, Apcomplex z, boolean fastOnly) { HypergeometricHelper helper = new HypergeometricHelper(new Apcomplex[] { a }, new Apcomplex[] { b }, z); return helper.result(helper.hypergeometricU(fastOnly)); } // In the general case (p = q + 1) this works only for |z| < 1, and in general, may converge slowly for very large |z| private Apcomplex hypergeometricPFQ() throws ArithmeticException, ApfloatRuntimeException { Apcomplex result = checkResult(); if (result != null) { return result; } // After checking for polynomial case, if any a and b are equal, they can be removed List bList = new ArrayList<>(Arrays.asList(b)); a = Arrays.stream(a).filter(z -> !bList.remove(z)).toArray(Apcomplex[]::new); b = bList.toArray(new Apcomplex[0]); if (a.length == 2 && b.length == 1) { return hypergeometric2F1(a[0], a[1], b[0], z); } if (a.length > b.length + 1L) { if (z.isZero()) { return new Apfloat(1, targetPrecision, radix); } throw new ArithmeticException("Series does not converge"); } if (a.length == 0 && b.length == 0) { return ApcomplexMath.exp(z); } if (a.length == 1 && b.length == 0) { return ApcomplexMath.pow(one.subtract(z), a[0].negate()); } if (a.length == 0 && b.length == 1) { return hypergeometric0F1(b[0], z); } if (a.length == 1 && b.length == 1) { return hypergeometric1F1(a[0], b[0], z); } assert (b.length > 0); result = evaluate(a, b, z); return ApfloatHelper.limitPrecision(result, targetPrecision); } private Apcomplex hypergeometric0F1(Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (abs(z).doubleValue() > targetPrecision * Math.log(radix)) { // Evaluate with 1F1 // https://functions.wolfram.com/HypergeometricFunctions/Hypergeometric0F1/27/01/ Apint two = new Apint(2, radix), four = new Apint(4, radix); Aprational half = new Aprational(one, two); Apcomplex b12 = ensurePrecision(b.subtract(half)); if (isNonPositiveInteger(b12)) { // This transformation wouldn't work correctly if 0F1 is not polynomial, but 1F1 becomes polynomial (b12 is nonpositive integer) // Note that if b is not a nonpositive integer (in which case 0F1 would also throw exception) then 2b-1 is not a nonpositive integer either so b21 is not a problem like b12 long digitLoss = workingPrecision; workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); Apfloat offset = offset(-digitLoss); b = new Apcomplex(b.real().precision(Apfloat.INFINITE).add(offset), b.imag()); b = ensurePrecision(b); z = ensurePrecision(z); b12 = ensurePrecision(b.subtract(half)); } Apcomplex b21 = ensurePrecision(two.multiply(b).subtract(one)), result; if (z.real().signum() >= 0) { // Use the formula for Bessel I and Bessel I as 1F1 Apcomplex sqrtZ = sqrt(z); result = exp(two.negate().multiply(sqrtZ)).multiply(hypergeometric1F1(b12, b21, four.multiply(sqrtZ))); } else { // Use the formula for Bessel J and Bessel J as 1F1 Apcomplex i = new Apcomplex(zero, one), sqrtZ = sqrt(z.negate()); result = exp(two.negate().multiply(i).multiply(sqrtZ)).multiply(hypergeometric1F1(b12, b21, four.multiply(i).multiply(sqrtZ))); } return ApfloatHelper.limitPrecision(result, targetPrecision); } Apcomplex result = evaluate(new Apcomplex[0], new Apcomplex[] { b }, z); return ApfloatHelper.limitPrecision(result, targetPrecision); } private Apcomplex hypergeometric1F1(Apcomplex a, Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { if (abs(z).doubleValue() > targetPrecision * Math.log(radix)) { try { // Evaluate with U* // Note: this transformation works correctly if 1F1 is not polynomial but U* becomes polynomial (a or a-b+1 is nonpositive integer, or b-a or 1-a is nonpositive integer) Apcomplex ba = ensurePrecision(b.subtract(a)); Apcomplex result = zero; if (!isNonPositiveInteger(ba)) { result = pow(z.negate(), a.negate()).divide(gamma(ensureGammaPrecision(ba))).multiply(hypergeometricUStar(a, b, z)); } result = result.add(pow(z, ba.negate()).multiply(exp(z)).divide(gamma(ensureGammaPrecision(a))).multiply(hypergeometricUStar(ba, b, z.negate()))).multiply(gamma(ensureGammaPrecision(b))); return ApfloatHelper.limitPrecision(result, targetPrecision); } catch (NotConvergingException nce) { // Ignore and retry with the (possibly very slow) direct evaluation of the series } } Apcomplex result = hypergeometric1F1series(a, b, z); return ApfloatHelper.limitPrecision(result, targetPrecision); } private Apcomplex hypergeometric1F1series(Apcomplex a, Apcomplex b, Apcomplex z) { if (a.equals(b) && !isNonPositiveInteger(a)) { return ApcomplexMath.exp(z); } Apcomplex factor = one; if (z.real().signum() < 0) { // Kummer transformation factor = ApcomplexMath.exp(z); a = ensurePrecision(b.subtract(a)); z = z.negate(); } Apcomplex result = evaluate(new Apcomplex[] { a }, new Apcomplex[] { b }, z).multiply(factor); return result; } private Apcomplex hypergeometricUStar(Apcomplex a, Apcomplex b, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { Apcomplex ab1 = ensurePrecision(a.subtract(b).add(one)); Apcomplex result = evaluate(new Apcomplex[] { a, ab1 }, new Apcomplex[0], one.divide(z).negate()); return result; } private Apcomplex hypergeometricU(boolean fastOnly) throws ArithmeticException, ApfloatRuntimeException { if (abs(z).doubleValue() > targetPrecision * Math.log(radix)) { try { // Evaluate with U* Apcomplex result = pow(z, a[0].negate()).multiply(hypergeometricUStar(a[0], b[0], z)); return ApfloatHelper.limitPrecision(result, targetPrecision); } catch (NotConvergingException nce) { // Ignore and retry with the (possibly very slow) direct evaluation of the series if (fastOnly) { // Too slow, try another algorithm return null; } } } if (fastOnly && (Stream.concat(Arrays.stream(a), Arrays.stream(b)).map(Apcomplex::real).reduce(ApfloatMath::min).get().doubleValue() < -100.0 * targetPrecision || // Check minimum number of evaluation terms z.scale() > 5.0 / Math.log(radix))) // Check convergence speed { // Too slow, try another algorithm return null; } // Evaluate two 1F1 functions, this often results in cancellation of significant digits so we may retry with higher precision Apcomplex result; long precisionLoss; do { Apcomplex a = this.a[0], b = this.b[0]; a = ensurePrecision(a); b = ensurePrecision(b); z = ensurePrecision(z); // First check if b is an integer or near-integer and adjust if necessary if (b.isInteger()) { long digitLoss = workingPrecision; workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); Apfloat offset = offset(-digitLoss); b = new Apcomplex(b.real().precision(Apfloat.INFINITE).add(offset), b.imag()); a = ensurePrecision(a); b = ensurePrecision(b); z = ensurePrecision(z); } else { Apint bRounded = RoundingHelper.roundToInteger(b.real(), RoundingMode.HALF_EVEN).truncate(); long digitLoss = Math.min(workingPrecision, -b.subtract(bRounded).scale()); if (digitLoss > 0) { workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); a = ensurePrecision(a); b = ensurePrecision(b); z = ensurePrecision(z); } } Apcomplex ab1 = ensureGammaPrecision(a.subtract(b).add(one)); result = zero; if (!isNonPositiveInteger(ab1)) { Apcomplex b1n = ensureGammaPrecision(one.subtract(b)); result = gamma(b1n).divide(gamma(ab1)).multiply(hypergeometric1F1series(a, b, z)); } if (!isNonPositiveInteger(a)) { Apint two = new Apint(2, radix); Apcomplex b1 = ensureGammaPrecision(b.subtract(one)), b1n = ensurePrecision(one.subtract(b)), b2 = ensurePrecision(two.subtract(b)); a = ensureGammaPrecision(a); result = result.add(gamma(b1).divide(gamma(a)).multiply(pow(z, b1n)).multiply(hypergeometric1F1series(ab1, b2, z))); } precisionLoss = (result.isZero() ? workingPrecision : targetPrecision - result.precision()); workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + precisionLoss); } while (precisionLoss > 0); return ApfloatHelper.limitPrecision(result, targetPrecision); } private Apcomplex hypergeometric2F1(Apcomplex a, Apcomplex b, Apcomplex c, Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { // Rules (in order!): // If a or b is a nonpositive integer, result is a polynomial (unless c is a nonpositive integer > a and b) // If c is a nonpositive integer, result is infinity (unless a or b is a nonpositive integer >= c) // If c and (a or b) is same nonpositive integer -> result is still a polynomial // If z is 1, result is infinity if re(a+b-c) >= 0 // Could also check if c-a or c-b is a nonpositive integer, then use transformation formula and function value is a polynomial // If c = a or c = b (and not a nonpositive integer) then it's 1F0 // Then perform transformation so that transformed z is as small as possible (in absolute value) // If transformed z is too big (i.e. near exp(±i pi / 3)) then use alternative algorithm // If transformation requires division by possible zero (e.g. b - a), then alter the parameters slightly to be nonzero, e.g. by largest ulp of a or b, ensure the required working precision (nb. probably no point to calculate average of two calls with +-ulp due to shape of function) // Real version is real if z <= 1 (may be infinite if z = 1 depending on a, b and c as said above) or in case of polynomial always if (z.equals(one)) { if (a.real().add(b.real()).subtract(c.real()).signum() >= 0) { throw new ArithmeticException("Does not converge"); } Apcomplex s = c.subtract(a), t = c.subtract(b); if (isNonPositiveInteger(s) || isNonPositiveInteger(t)) { return zero; } Apcomplex cab = s.subtract(b); s = ApfloatHelper.ensureGammaPrecision(s, workingPrecision); t = ApfloatHelper.ensureGammaPrecision(t, workingPrecision); cab = ApfloatHelper.ensureGammaPrecision(cab, workingPrecision); c = ApfloatHelper.ensureGammaPrecision(c, workingPrecision); return ApcomplexMath.gamma(c).multiply(ApcomplexMath.gamma(cab)).divide(ApcomplexMath.gamma(s).multiply(ApcomplexMath.gamma(t))); } Apcomplex zDoublePrecision = z.precision(ApfloatHelper.getDoublePrecision(radix)); // Does it make any sense to check first if the transform results in a polynomial? The polynomial could potentially be of huge degree anyways Transformation transformation = Arrays.stream(Transformation.values()).filter(t -> t.isApplicable(z)).min(comparing(t -> abs(t.z(zDoublePrecision)))).get(); Apcomplex result; if (abs(transformation.z(zDoublePrecision)).doubleValue() > 0.8) { // Use alternative algorithm as none of the transforms is very good result = alternative(a, b, c, z); } else { result = null; try { result = transformation.value(new Hypergeometric2F1Helper(true)); } catch (RetryException re) { workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + re.getPrecisionLoss()); result = transformation.value(new Hypergeometric2F1Helper(false)); // Retry once if there is unexpected precision loss } } return ApfloatHelper.limitPrecision(result, targetPrecision); } private static long precision(Apcomplex[] z0, Apcomplex[] z1, Apcomplex z2) { Apcomplex[] z = Stream.concat(Stream.concat(Arrays.stream(z0), Arrays.stream(z1)), Stream.of(z2)).toArray(Apcomplex[]::new); return precision(z); } private static long precision(Apcomplex... z) { return Arrays.stream(z).mapToLong(Apcomplex::precision).min().getAsLong(); } private Apcomplex checkResult() { Apfloat minNonPositiveIntegerA = maxNonPositiveInteger(a), minNonPositiveIntegerB = maxNonPositiveInteger(b); if (minNonPositiveIntegerB != null && (minNonPositiveIntegerA == null || minNonPositiveIntegerA.compareTo(minNonPositiveIntegerB) < 0)) { throw new ArithmeticException("Division by zero"); } if (z.isZero()) { return new Apfloat(1, targetPrecision, radix); } if (targetPrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate hypergeometric function to infinite precision"); } if (minNonPositiveIntegerA != null) { // Result is a polynomial, we should evaluate here as e.g. a transformation of 2F1 won't work if c is a non-positive integer Apcomplex result = evaluate(a, b, z); return ApfloatHelper.limitPrecision(result, targetPrecision); } return null; } public static Apfloat maxNonPositiveInteger(Apcomplex... a) { return Arrays.stream(a).filter(Apcomplex::isInteger).map(Apcomplex::real).filter(x -> x.signum() <= 0).reduce(ApfloatMath::max).orElse(null); } // It could be that the terms initially grow for a long time, until they start getting smaller // Also it could be that the sum similarly grows first, but then starts also getting significantly smaller (by many orders of magnitude) -> this causes a precision loss, which needs to be detected, and handled by retrying with increased precision private Apcomplex evaluate(Apcomplex[] a, Apcomplex[] b, Apcomplex z) { Apcomplex[] aOrig = a.clone(), bOrig = b.clone(); Apcomplex s; Apint minN = ApintMath.max(one, Stream.concat(Arrays.stream(a), Arrays.stream(b)).map(Apcomplex::real).reduce(ApfloatMath::min).get().truncate().negate()).add(one); long precisionLoss = 0, extraPrecision, extendedPrecision = ApfloatHelper.extendPrecision(workingPrecision, minN.scale()); // Estimate for accumulated round-off error precision due to repeated multiplication only (not scale based digit loss, see below) boolean divergentSeries = a.length - b.length > 1; ensurePrecision(a, a, extendedPrecision); ensurePrecision(b, b, extendedPrecision); z = ApfloatHelper.ensurePrecision(z, extendedPrecision); do { long maxSScale = 1; // Scale of 1, the initial s Apint i = zero; Apcomplex numerator = one, denominator = one, o = null, t = null; boolean minIterations; extraPrecision = precisionLoss; s = one; do { minIterations = i.compareTo(minN) <= 0; if (divergentSeries && !minIterations) { checkDivergence(o, t); } i = i.add(one); for (int j = 0; j < a.length; j++) { numerator = numerator.multiply(a[j]); a[j] = a[j].add(one); } if (numerator.isZero()) { return s; // It was a polynomial } numerator = numerator.multiply(z); for (int j = 0; j < b.length; j++) { denominator = denominator.multiply(b[j]); b[j] = b[j].add(one); } denominator = denominator.multiply(i); o = t; t = numerator.divide(denominator); s = s.add(t); maxSScale = Math.max(maxSScale, s.scale()); } while (minIterations || s.isZero() || s.scale() - t.scale() <= workingPrecision); // Subtraction might overflow precisionLoss = (s.isZero() ? extendedPrecision : maxSScale - s.scale()); // Loss due to scale of s reduced from its peak (loss off most significant digits) if (workingPrecision - s.precision() > 1) // Often the precision is reduced by 1 { precisionLoss = Util.ifFinite(precisionLoss, precisionLoss + workingPrecision - s.precision()); // Loss due to accumulation (loss off least significant digits) } if (precisionLoss > extraPrecision) { extendedPrecision = Util.ifFinite(workingPrecision, workingPrecision + precisionLoss); ensurePrecision(aOrig, a, extendedPrecision); ensurePrecision(bOrig, b, extendedPrecision); z = ApfloatHelper.ensurePrecision(z, extendedPrecision); } } while (precisionLoss > extraPrecision); return s; } private void checkDivergence(Apcomplex old, Apcomplex term) { // Check if the divergent series reached the smallest term already, even though the required precision was not reached if (old != null && abs(old).compareTo(abs(term)) < 0) { throw new NotConvergingException(); } } // See: https://def.fe.up.pt/pipermail/maxima-discuss/2006.txt "Methods for numerically difficult cases of 2F1(a,b;c|z)", alternative algorithm by Bill Gosper private Apcomplex alternative(Apcomplex a, Apcomplex b, Apcomplex c, Apcomplex z) { if (c.real().signum() <= 0) { Apint cRounded = RoundingHelper.roundToInteger(c.real(), RoundingMode.HALF_EVEN).truncate(); long digitLoss = -c.subtract(cRounded).scale(); if (digitLoss > 0) { workingPrecision = Util.ifFinite(workingPrecision, workingPrecision + digitLoss); a = ensurePrecision(a); b = ensurePrecision(b); c = ensurePrecision(c); z = ensurePrecision(z); } } Apint two = new Apint(2, radix), four = new Apint(4, radix), k = zero; Apcomplex d = zero, e = one, f = zero, z1 = ensurePrecision(one.subtract(z)), z12 = two.multiply(z1), z2 = ensurePrecision(z.subtract(two)), abz = a.multiply(b).multiply(z), c2 = c.divide(two), c12 = ensurePrecision(c.add(one)).divide(two), cba = ensurePrecision(c.subtract(b).subtract(a)); assert (c2.real().signum() > 0 || c2.imag().signum() != 0 || !c2.isInteger()); // c2 should not be rounded to negative integer do { Apcomplex kc2 = k.add(c2), kakbz = k.add(a).multiply(k.add(b)).multiply(z), divisor = one.divide(four.multiply(k.add(one)).multiply(kc2).multiply(k.add(c12))), d1 = kakbz.multiply(e.subtract(k.add(cba).multiply(d).multiply(z).divide(z1))).multiply(divisor), e1 = kakbz.multiply(abz.multiply(d).divide(z1).add(k.add(c).multiply(e))).multiply(divisor), f1 = f.subtract(d.multiply(k.multiply(cba.multiply(z).add(k.multiply(z2)).subtract(c)).subtract(abz)).divide(kc2.multiply(z12))).add(e); d = ensurePrecision(d1); e = ensurePrecision(e1); f = ensurePrecision(f1); k = k.add(one); } while (d.scale() >= -workingPrecision || e.scale() >= -workingPrecision); return f; } private Apfloat offset(long scale) { Apfloat offset = scale(new Apfloat("0.1", workingPrecision, radix), scale); return offset; } private Apfloat adjustOffset(Apfloat x, Apfloat offset) { if (x.scale() <= offset.scale()) { return x; } return x.precision(Apfloat.INFINITE).add(offset).subtract(offset); } private Apcomplex ensurePrecision(Apcomplex z) { return ApfloatHelper.ensurePrecision(z, workingPrecision); } private void ensurePrecision(Apcomplex[] src, Apcomplex[] dest, long extendedPrecision) { for (int i = 0; i < dest.length; i++) { dest[i] = ApfloatHelper.ensurePrecision(src[i], extendedPrecision); } } private Apcomplex ensureGammaPrecision(Apcomplex z) { return ApfloatHelper.ensureGammaPrecision(z, workingPrecision); } private Apcomplex result(Apcomplex z) { return (z == null ? z : ApfloatHelper.reducePrecision(z, extraPrecision)); } private long targetPrecision, extraPrecision, workingPrecision; private int radix; private Apcomplex[] a, b; private Apcomplex z; private Apint one, zero; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/IncompleteGammaHelper.java000066400000000000000000000705401461767713300266140ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.Arrays; import java.util.function.BiFunction; import java.util.function.LongFunction; import org.apfloat.spi.Util; import static org.apfloat.ApcomplexMath.isNonPositiveInteger; /** * Helper class for the incomplete gamma function. * * @since 1.10.0 * @version 1.14.0 * @author Mikko Tommila */ class IncompleteGammaHelper { // See https://hal.archives-ouvertes.fr/hal-01329669/document // Fast and accurate evaluation of a generalized incomplete gamma function Rémy Abergel, Lionel Moisan private static class Sequence { public Sequence(LongFunction a, LongFunction b) { this.a = a; this.b = b; } public Apcomplex a(long n) { return this.a.apply(n); } public Apcomplex b(long n) { return this.b.apply(n); } private LongFunction a; private LongFunction b; } private static class ContinuedFractionResult { private Apcomplex result; private Apcomplex delta; private long iterations; public ContinuedFractionResult(Apcomplex result, Apcomplex delta, long iterations) { this.result = result; this.delta = delta; this.iterations = iterations; } public Apcomplex getResult() { return result; } public Apcomplex getDelta() { return delta; } public long getIterations() { return iterations; } } private static enum ContinuedFractionType { LOWER, UPPER; } private static enum ContinuedFraction { LOWER1(ContinuedFractionType.LOWER, IncompleteGammaHelper::lowerGammaSequence) { @Override public long getMinIterations(Apcomplex a, Apcomplex z) { return (a.real().signum() >= 0 ? 0 : Util.subtractExact(4, Util.multiplyExact(2, ApfloatHelper.longValueExact(a.real().truncate())))); } }, LOWER2(ContinuedFractionType.LOWER, IncompleteGammaHelper::lowerGammaSequenceAlternative) { @Override public long getMinIterations(Apcomplex a, Apcomplex z) { return Math.max(a.real().signum() >= 0 ? 0 : Util.subtractExact(3, ApfloatHelper.longValueExact(a.real().truncate())), Util.subtractExact(2, Util.addExact(a.real().truncate().longValueExact(), ApfloatHelper.longValueExact(z.real().truncate())))); } }, UPPER1(ContinuedFractionType.UPPER, IncompleteGammaHelper::upperGammaSequence) { @Override public long getMinIterations(Apcomplex a, Apcomplex z) { return Math.max(a.real().signum() <= 0 ? 0 : Util.addExact(2, ApfloatHelper.longValueExact(a.real().truncate())), Util.addExact(1, Util.subtractExact(ApfloatHelper.longValueExact(a.real().truncate()), ApfloatHelper.longValueExact(z.real().truncate())) / 2)); } }, UPPER2(ContinuedFractionType.UPPER, IncompleteGammaHelper::upperGammaSequenceAlternative) { @Override public long getMinIterations(Apcomplex a, Apcomplex z) { return (a.real().signum() <= 0 ? 0 : Util.addExact(Util.multiplyExact(2, ApfloatHelper.longValueExact(a.real().truncate())), 2)); } }; private ContinuedFraction(ContinuedFractionType type, BiFunction sequence) { this.type = type; this.sequence = sequence; } public ContinuedFractionType getType() { return this.type; } public BiFunction getSequence() { return this.sequence; } public abstract long getMinIterations(Apcomplex a, Apcomplex z); public static ContinuedFraction[] upperValues() { ContinuedFraction[] upperValues = { UPPER1 }; return upperValues; } public static ContinuedFraction[] lowerValues() { ContinuedFraction[] lowerValues = { LOWER1 }; return lowerValues; } public static ContinuedFraction[] bothValues() { ContinuedFraction[] bothValues = { LOWER1, UPPER1 }; return bothValues; } private ContinuedFractionType type; private BiFunction sequence; } private static class GammaValue { public GammaValue(Apcomplex a, Apcomplex result, boolean inverted) { this.a = a; this.result = result; this.inverted = inverted; } public GammaValue invert() { return new GammaValue(this.a, this.result, !this.inverted); } public Apcomplex subtract(GammaValue that) { if (this.inverted == that.inverted) { Apcomplex result = this.result.subtract(that.result); return this.inverted ? result.negate() : result; } else { Apcomplex result = this.result.add(that.result).subtract(ApcomplexMath.gamma(this.a)); return this.inverted ? result.negate() : result; } } public Apcomplex getValue() { return (this.inverted ? ApcomplexMath.gamma(this.a).subtract(this.result) : this.result); } private Apcomplex a; private Apcomplex result; private boolean inverted; } private static class RetryException extends RuntimeException { private static final long serialVersionUID = 1L; } public static Apcomplex gamma(Apcomplex a, Apcomplex z) { if (z.isZero()) { if (a.real().signum() <= 0) { throw new ArithmeticException("Upper gamma with first argument real part nonpositive and second argment zero"); } return ApcomplexMath.gamma(a); } checkPrecision(a, z); return upperGamma(a, z).getValue(); } public static Apcomplex gamma(Apcomplex a, Apcomplex z0, Apcomplex z1) { if (a.isZero() && z0.isZero() && z1.isZero()) { throw new ArithmeticException("Gamma of zero"); } if (z0.equals(z1)) { return Apcomplex.ZEROS[z0.radix()]; } checkPrecision(a, z0, z1); if (z0.isZero()) { return lowerGamma(a, z1, null).getValue(); } if (z1.isZero()) { return lowerGamma(a, z0, null).getValue().negate(); } if (useSum(z0) && useSum(z1)) { return sum(a, z1).subtract(sum(a, z0)); } return upperGamma(a, z0).subtract(upperGamma(a, z1)); } private static void checkPrecision(Apcomplex... z) { long precision = Arrays.stream(z).mapToLong(Apcomplex::precision).min().getAsLong(); if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate incomplete gamma function to infinite precision"); } } private static GammaValue upperGamma(Apcomplex a, Apcomplex z) { if (useAsymptoticLarge(a, z) && !isNonPositiveInteger(a)) { return asymptoticLargeA(a, z); } if (useAsymptoticLarge(z, a)) { return asymptoticLargeZ(a, z); } GammaValue result = attemptUStar(a, z); if (result != null) { return result; } ContinuedFraction[] algorithms = null; if (isNonPositiveInteger(a)) { if (isCloseToNegativeRealAxis(z)) { // Note that this transformation may be extremely slow if n is large // gamma(-n,z) = (-1)^n/n! gamma(0,z) - e^-z sum[z^(k-n-1)/(-n)_k,{k,1,n}] // See https://functions.wolfram.com/GammaBetaErf/Gamma2/17/02/01/ long n = ApfloatHelper.longValueExact(a.real().truncate()); // If this overflows then the value would overflow anyways return new GammaValue(a, upperGamma(n, z), false); } algorithms = ContinuedFraction.upperValues(); } if (algorithms == null) { if (useLowerGamma(a, z)) { return lowerGamma(a, z, ContinuedFraction.lowerValues()).invert(); } algorithms = (isMaybeUnstable(a, z) ? ContinuedFraction.bothValues() : ContinuedFraction.upperValues()); } ContinuedFraction fastest = fastestG(a, z, algorithms); return gammaG(a, z, fastest, ContinuedFractionType.UPPER); } private static boolean useAsymptoticLarge(Apcomplex larger, Apcomplex smaller) { if (larger.scale() > 1 && larger.scale() > smaller.scale()) { long precision = Math.min(larger.precision(), smaller.precision()); double digitsPerTerm = larger.scale() - Math.max(1.0, smaller.scale()), maxTerms = 2; return digitsPerTerm * maxTerms > precision; } return false; } private static GammaValue lowerGamma(Apcomplex a, Apcomplex z, ContinuedFraction[] algorithms) { if (isNonPositiveInteger(a)) { throw new ArithmeticException("Lower gamma with first argument nonpositive integer"); } if (useSum(z)) { // The series is fastest for small z return new GammaValue(a, sum(a, z), false); } if (algorithms == null) { if (isMaybeUnstable(a, z)) { algorithms = ContinuedFraction.bothValues(); } else if (useUpperGamma(a, z)) { algorithms = ContinuedFraction.upperValues(); } else { algorithms = ContinuedFraction.lowerValues(); } } ContinuedFraction fastest = fastestG(a, z, algorithms); return gammaG(a, z, fastest, ContinuedFractionType.LOWER); } private static boolean useSum(Apcomplex z) { // The series converges fast for small z return z.scale() <= 0; } private static boolean useLowerGamma(Apcomplex a, Apcomplex z) { // The continued fraction for upper gamma would not converge well return z.scale() < a.scale() || isCloseToNegativeRealAxis(z) || useSum(z); } private static boolean isCloseToNegativeRealAxis(Apcomplex z) { // If z is too close to the negative real axis, the upper gamma continued fraction converges poorly return (z.real().signum() <= 0 || z.real().scale() < 0) && z.imag().scale() < 0; } private static boolean useUpperGamma(Apcomplex a, Apcomplex z) { // The continued fraction for upper gamma converges better return a.scale() < z.scale(); } private static boolean isMaybeUnstable(Apcomplex a, Apcomplex z) { // Borderline cases where upper gamma continued fraction might not converge well if (a.scale() > 0 && z.scale() > 0) { double ratio = abs(a).divide(abs(z)).doubleValue(); return 0.1 <= ratio && ratio <= 10.0; } return false; } private static Apfloat abs(Apcomplex z) { return ApcomplexMath.abs(z.precision(ApfloatHelper.getDoublePrecision(z.radix()))); } private static GammaValue gammaG(Apcomplex a, Apcomplex z, ContinuedFraction algorithm, ContinuedFractionType type) { Apcomplex g = g(algorithm.getSequence(), a, z, algorithm.getMinIterations(a, z)); return new GammaValue(a, g, algorithm.getType() != type); } // Converges well only when |z| > |a|, a can be zero but z cannot private static Sequence upperGammaSequence(Apcomplex a, Apcomplex z) { int radix = z.radix(); Apfloat one = new Apint(1, radix); Apcomplex za = z.subtract(a); Sequence s = new Sequence(n -> { if (n == 1) { return one; } else { Apint n1 = new Apint(n - 1, radix); return n1.multiply(a.subtract(n1)); } }, n -> new Apint(2 * n - 1, radix).add(za)); return s; } // Converges best when |z| <= |a|, both a and z must be nonzero and a must not be a negative integer private static Sequence lowerGammaSequence(Apcomplex a, Apcomplex z) { int radix = z.radix(); Apfloat one = new Apint(1, radix); Sequence s = new Sequence(n -> { if (n == 1) { return one; } else if (n % 2 == 0) { return new Apint(1 - n / 2, radix).subtract(a).multiply(z); } else { return new Apint(n / 2, radix).multiply(z); } }, n -> new Apint(n - 1, radix).add(a)); return s; } // Inferior alternative to the upper gamma sequence, converges well only when z is not close to the negative real axis private static Sequence upperGammaSequenceAlternative(Apcomplex a, Apcomplex z) { int radix = z.radix(); Apfloat one = new Apint(1, radix); Sequence s = new Sequence(n -> { if (n == 1) { return one; } else if (n % 2 == 0) { return new Apint(n / 2, radix).subtract(a); } else { return new Apint(n / 2, radix); } }, n -> (n % 2 == 0 ? one : z)); return s; } // Inferior alternative to the lower gamma sequence, converges well only when z is not close to the negative real axis private static Sequence lowerGammaSequenceAlternative(Apcomplex a, Apcomplex z) { int radix = z.radix(); Apfloat one = new Apint(1, radix); Apcomplex az = a.add(z); Sequence s = new Sequence(n -> { if (n == 1) { return one; } else { return new Apint(2 - n, radix).subtract(a).multiply(z); } }, n -> { if (n == 1) { return a; } else { return az.add(new Apint(n - 1, radix)); } }); return s; } private static ContinuedFraction fastestG(Apcomplex a, Apcomplex z, ContinuedFraction[] algorithms) { // There are some input values for which the upper continued fraction behaves in a very pathological way e.g. a=-1e-2+4e2i and z=1e-2+1e2i if (algorithms.length == 1) { return algorithms[0]; } int radix = z.radix(); long precision = (long) (50 / Math.log10(radix)); a = a.precision(precision); z = z.precision(precision); ContinuedFraction fastest = null; ContinuedFractionResult fastestResult = null; for (ContinuedFraction continuedFraction : algorithms) { ContinuedFractionResult result = continuedFraction(continuedFraction.sequence.apply(a, z), radix, precision, 0, 50); if (fastest == null) { fastest = continuedFraction; fastestResult = result; } else { long resultIterations = result.getIterations(); long fastestIterations = fastestResult.getIterations(); if (resultIterations < fastestIterations) { // Whichever continued fraction reached the precision goal earlier is faster fastest = continuedFraction; fastestResult = result; } else if (resultIterations == fastestIterations) { // If neither continued fraction reached the precision goal within the max iterations, see which one got better precision Apint one = new Apint(1, radix); long resultPrecision = result.getDelta().equalDigits(one); long fastestPrecision = fastestResult.getDelta().equalDigits(one); if (resultPrecision > fastestPrecision) { fastest = continuedFraction; fastestResult = result; } } } } return fastest; } private static Apcomplex g(BiFunction s, Apcomplex a, Apcomplex z, long minIterations) { int radix = z.radix(); long extraPrecision = extraPrecision(radix); // More extra precision because the incomplete gamma behaves so erratically, the more the bigger the numbers a = ApfloatHelper.extendPrecision(a, extraPrecision); z = ApfloatHelper.extendPrecision(z, extraPrecision); long reducePrecision = extraPrecision; Apcomplex f = null; do { try { f = continuedFraction(s.apply(a, z), radix, Math.min(a.precision(), z.precision()), minIterations, Long.MAX_VALUE).getResult(); } catch (RetryException re) { // If the continued fraction initially converges to a wrong value and we don't calculate it accurately enough then keep increasing the precision // See: // Walter Gautschi, "Anomalous convergence of a continued fraction for ratios of Kummer functions", Mathematics of Computation, volume 31, number 140, October 1977, pages 994-999 // https://www.ams.org/journals/mcom/1977-31-140/S0025-5718-1977-0442204-3/S0025-5718-1977-0442204-3.pdf a = ApfloatHelper.extendPrecision(a, extraPrecision); z = ApfloatHelper.extendPrecision(z, extraPrecision); reducePrecision += extraPrecision; extraPrecision += extraPrecision; } } while (f == null); Apcomplex g = f.multiply(ApcomplexMath.exp(a.multiply(ApcomplexMath.log(z)).subtract(z))); return ApfloatHelper.reducePrecision(g, reducePrecision); } private static long extraPrecision(int radix) { return (long) (Apfloat.EXTRA_PRECISION * 2 / Math.log10(radix)); } // Modified Lentz's method private static ContinuedFractionResult continuedFraction(Sequence s, int radix, long workingPrecision, long minIterations, long maxIterations) { Apint one = new Apint(1, radix); long n = 0; Apcomplex an; Apcomplex bn; Apcomplex f = tiny(new Apint(0, radix), workingPrecision); Apcomplex c = f; Apcomplex d = Apcomplex.ZERO; Apcomplex delta; long precision; long precisionLoss = extraPrecision(radix) / 4; long targetPrecision = workingPrecision - precisionLoss; // Due to round-off errors we cannot always reach workingPrecision but slightly less is sufficient long maxPrecision = 0; do { n = Util.addExact(n, 1); an = s.a(n).precision(workingPrecision); bn = s.b(n).precision(workingPrecision); d = d.multiply(an).add(bn); d = ApfloatHelper.ensurePrecision(d, workingPrecision); if (d.isZero()) { d = tiny(bn, workingPrecision); } c = bn.add(an.divide(c)); c = ApfloatHelper.ensurePrecision(c, workingPrecision); if (c.isZero()) { c = tiny(bn, workingPrecision); } d = one.divide(d); delta = c.multiply(d); f = f.multiply(delta); precision = delta.equalDigits(one); maxPrecision = Math.max(maxPrecision, precision); if (precision < precisionLoss && maxPrecision >= targetPrecision - precisionLoss) // Check if the continued fraction initially converges to a wrong value and we don't calculate it accurately enough { throw new RetryException(); } } while (n < minIterations || n <= maxIterations && precision < targetPrecision); return new ContinuedFractionResult(f, delta, n); } private static Apcomplex tiny(Apcomplex z, long workingPrecision) { if (z.isZero()) { z = new Apfloat(1, workingPrecision, z.radix()); } return ApcomplexMath.scale(ApcomplexMath.ulp(z), -workingPrecision).precision(workingPrecision); } // Asymptotic algorithm for |a| -> infinity private static GammaValue asymptoticLargeA(Apcomplex a, Apcomplex z) { // https://functions.wolfram.com/GammaBetaErf/Gamma2/06/02/01/ long precision = Math.min(a.precision(), z.precision()); Apint one = Apcomplex.ONES[a.radix()]; Apcomplex z1 = ApfloatHelper.ensurePrecision(z.subtract(one), precision), sum = one.add(z.divide(a)).add(z.multiply(z1).divide(a.multiply(a))), zz = ApfloatHelper.extendPrecision(z, a.scale()), aa = ApfloatHelper.extendPrecision(a, a.scale()), result = ApcomplexMath.exp(z.negate()).multiply(ApcomplexMath.pow(zz, aa)).divide(a).multiply(sum); return new GammaValue(a, result, true); } // Asymptotic algorithm for |z| -> infinity private static GammaValue asymptoticLargeZ(Apcomplex a, Apcomplex z) { // https://functions.wolfram.com/GammaBetaErf/Gamma2/06/02/02/ long precision = Math.min(a.precision(), z.precision()); int radix = a.radix(); Apint one = Apcomplex.ONES[radix], two = new Apint(2, radix); Apcomplex a1 = ApfloatHelper.ensurePrecision(one.subtract(a), precision), a2 = ApfloatHelper.ensurePrecision(two.subtract(a), precision), sum = one.subtract(a1.divide(z)).add(a2.multiply(a1).divide(z.multiply(z))), result = ApcomplexMath.exp(z.negate()).multiply(ApcomplexMath.pow(z, a1.negate())).multiply(sum); return new GammaValue(a, result, false); } // Algorithm for using hypergeometric U private static GammaValue attemptUStar(Apcomplex a, Apcomplex z) { long precision = Math.min(a.precision(), z.precision()); Apcomplex a1 = ApfloatHelper.ensurePrecision(Apcomplex.ONES[a.radix()].subtract(a), precision); try { Apcomplex result = HypergeometricHelper.hypergeometricU(a1, a1, z, true); if (result != null) { return new GammaValue(a, result.multiply(ApcomplexMath.exp(z.negate())), false); } } catch (LossOfPrecisionException lope) { // Attempt another algorithm } return null; } // Upper gamma of nonpositive integer private static Apcomplex upperGamma(long mn, Apcomplex z) { Apcomplex result = e1(z); // Same as upperGamma(0, z) assert (mn <= 0); long n = -mn; if (n > 0) { long workingPrecision = ApfloatHelper.extendPrecision(z.precision()); int radix = z.radix(); result = result.divide(ApfloatMath.factorial(n, workingPrecision, radix)); if ((n & 1) == 1) { result = result.negate(); } z = ApfloatHelper.extendPrecision(z); Apcomplex ez = ApcomplexMath.exp(z.negate()); Apcomplex s = ApcomplexMath.pow(z, mn).divide(new Apint(mn, radix)), sum = s; for (long k = 2; k <= n; k++) { mn++; s = s.multiply(z).divide(new Apint(mn, radix)); sum = sum.add(s); } result = result.subtract(ez.multiply(sum)); } return result; } private static Apcomplex sum(Apcomplex a, Apcomplex z) { a = ApfloatHelper.extendPrecision(a); z = ApfloatHelper.extendPrecision(z); boolean useAlternatingSum = (z.real().signum() >= 0); Apcomplex za = ApcomplexMath.pow(z, a); if (!useAlternatingSum) { za = za.multiply(ApcomplexMath.exp(z.negate())); } long targetPrecision = Math.min(a.precision(), z.precision()); int radix = z.radix(); Apcomplex sum = Apcomplex.ZERO; Apint one = Apint.ONES[radix]; Apcomplex f = (useAlternatingSum ? one.precision(targetPrecision) : a); long n = 0; Apcomplex t; do { if (useAlternatingSum) { Apint nn = new Apint(n, radix); Apcomplex an = a.add(nn); if (n > 0) { za = za.multiply(z); f = f.multiply(nn); } t = za.divide(f.multiply(an)); sum = (n & 1) == 0 ? sum.add(t) : sum.subtract(t); } else { if (n > 0) { a = a.add(one); za = za.multiply(z); f = f.multiply(a); } t = za.divide(f); sum = sum.add(t); } n++; } while (sum.scale() - t.scale() < targetPrecision && !t.isZero()); // Also check for underflow of t return ApfloatHelper.reducePrecision(sum); } // Exponential integral for upperGamma(0, z) private static Apcomplex e1(Apcomplex z) { assert (isCloseToNegativeRealAxis(z)); int radix = z.radix(); long targetPrecision = z.precision(); Apcomplex mz = ApfloatHelper.extendPrecision(z).negate(); Apcomplex s = mz, sum = s, t; long k = 1; do { k++; Apint kk = new Apint(k, radix); s = s.multiply(mz).divide(kk); t = s.divide(kk); sum = sum.add(t); } while (sum.scale() - t.scale() < targetPrecision && !t.isZero()); // Also check for underflow of t Apcomplex result = ApfloatMath.euler(targetPrecision, radix).negate().subtract(ApcomplexMath.log(z)).subtract(ApfloatHelper.reducePrecision(sum)); return result; } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/InfiniteExpansionException.java000066400000000000000000000045261461767713300277240ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; /** * Exception indicating that the result of an operation * would have infinite size.

* * For example, new Apfloat(2).divide(new Apfloat(3)), in radix 10. * * @since 1.5 * @version 1.14.0 * @author Mikko Tommila */ public class InfiniteExpansionException extends NumericComputationException { /** * Constructs a new apfloat infinite expansion exception with an empty detail message. */ public InfiniteExpansionException() { } /** * Constructs a new apfloat infinite expansion exception with the specified detail message. * * @param message The detail message. */ public InfiniteExpansionException(String message) { super(message); } /** * Constructs a new apfloat infinite expansion exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public InfiniteExpansionException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/LambertWHelper.java000066400000000000000000000553511461767713300252720ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import static org.apfloat.spi.RadixConstants.*; import org.apfloat.spi.Util; /** * Helper class for Lambert W function. * * @since 1.8.0 * @version 1.10.0 * @author Mikko Tommila */ class LambertWHelper { private static class ComplexException extends Exception { public ComplexException(ArithmeticException cause) { super(cause); } @Override public ArithmeticException getCause() { return (ArithmeticException) super.getCause(); } private static final long serialVersionUID = 1; } private static final double BRANCH_POINT_BEYOND = -0.3678794411714460; // Behind branch point on real axis (-1/e = -0.36787944117144233) private LambertWHelper(Apcomplex z, long k) { this.targetPrecision = z.precision(); // The final precision; might be less, but the intermediate steps must still be done to the full precision this.precision = ApfloatHelper.extendPrecision(this.targetPrecision); // The working precision; must be extended because of accumulated loss of precision this.radix = z.radix(); this.z = ApfloatHelper.ensurePrecision(z, this.precision); if (z.imag().signum() == 0) { this.x = z.real(); } this.k = k; this.minusOne = new Apint(-1, this.radix); this.one = new Apint(1, this.radix); this.two = new Apint(2, this.radix); this.three = new Apint(3, this.radix); this.minusOnePerE = new Apfloat(BRANCH_POINT_BEYOND, Apfloat.DEFAULT, this.radix); // Slightly beyond the limit to cater for round-off errors Apfloat distSquare = new Apfloat(1e-8, Apfloat.DEFAULT, this.radix); // How close is "close" to the branch point, squared; one fourth of double precision this.close = ApcomplexMath.norm(z.subtract(this.minusOnePerE)).compareTo(distSquare) <= 0; // In case of large k, the precision (of the imaginary part) is extended if (k != 0) { // If 2 k pi is 10 or more, then increase precision by how many extra digits 2 k pi has double precisionIncrease = Math.log(Math.abs((double) k) * 2 * Math.PI) / Math.log((double) this.radix); this.precision = ApfloatHelper.extendPrecision(this.precision, (long) precisionIncrease); this.targetPrecision = ApfloatHelper.extendPrecision(this.targetPrecision, (long) precisionIncrease); } if ((this.z.real().signum() != 0 || this.z.imag().signum() != 0) && this.precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate W to infinite precision"); } } public static Apfloat w(Apfloat x) throws ArithmeticException, ApfloatRuntimeException { return new LambertWHelper(x, 0).real(); } public static Apcomplex w(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { return w(z, 0); } public static Apcomplex w(Apcomplex z, long k) throws ArithmeticException, ApfloatRuntimeException { return new LambertWHelper(z, k).complex(); } public Apfloat real() throws ArithmeticException, ApfloatRuntimeException { try { return doReal(); } catch (ComplexException ce) { throw ce.getCause(); } } private Apfloat doReal() throws ComplexException, ApfloatRuntimeException { assert (this.k == 0 || this.x.signum() < 0); if (this.x.signum() == 0) { return this.x; } // Initial value Apfloat w; long initialPrecision = DOUBLE_PRECISION[this.x.radix()]; Apfloat initialX = this.x.precision(initialPrecision); long digits = 0; long oldAccuracy = 0; if (this.x.compareTo(this.minusOnePerE) < 0) { // We know for sure here, but it could still be, even if we don't notice it here throw new ComplexException(new ArithmeticException("Result would be complex")); } else if (this.k == -1 && !this.close) { // Real valued W_-1: log(-x) - log(-log(-x)), -1/e <= x < 0 (not very close to the branch point) Apfloat logx = ApfloatMath.log(initialX.negate()); w = logx.subtract(ApfloatMath.log(logx.negate())); } else if (this.k == -1) { // W_-1 close to the branch point -1/e w = negativeRealSeries(); digits = oldAccuracy = w.precision(); w = w.precision(shiftLeftPrecision(digits, 2)); } else if (this.x.scale() > 1) { // Large values Apfloat logx = ApfloatMath.log(initialX); w = logx.subtract(ApfloatMath.log(logx)); } else if (this.x.signum() > 0 && this.x.scale() >= 0) { // Moderate values w = ApfloatMath.log(initialX.add(this.one)); } else if (!this.close) { // Small but not very close to the branch point; possibly close to zero w = initialX; } else { // Close to the branch point -1/e w = positiveRealSeries(); digits = oldAccuracy = w.precision(); w = w.precision(shiftLeftPrecision(digits, 2)); } if (!this.close) { // If x is slightly close to -1/e, but not very close, precision of the result is still reduced this.targetPrecision -= (this.x.equalDigits(this.minusOnePerE) + 1 ) / 2; } this.targetPrecision = Math.max(this.targetPrecision, 1); // In case input is -0.3 with precision 1 boolean done = (digits >= this.targetPrecision); if (!done) { // Precalculate the needed values once to the required precision ApfloatMath.logRadix(this.targetPrecision, this.radix); } // Fritsch's iteration (quartic) // For values close to -1/e the convergence is initially worse but eventually becomes quartic Apfloat oldW; boolean converges = false; // If there are at least a few correct digits in the result for (int i = 0; i < 50 && !done; i++) // Should be enough iterations { oldW = w; // Calculate one Fritsch's iteration Apfloat z = ApfloatMath.log(this.x.divide(w)).subtract(w); Apfloat w1 = this.one.add(w); Apfloat q = z.multiply(this.two).divide(this.three).add(w1).multiply(w1).multiply(this.two); Apfloat e = z.divide(w1).multiply(q.subtract(z)).divide(q.subtract(this.two.multiply(z))); // Check the accuracy of the result, initially convergence can be slow but becomes quartic eventually long accuracy = (converges ? -e.scale() : digits); double rate = Math.min(Math.max(accuracy / Math.max(1.0, oldAccuracy), 1.0), 4.0); if (accuracy >= this.targetPrecision / rate) { done = true; } oldAccuracy = accuracy; w = w.multiply(this.one.add(e)); // If x was close to the limit and we did not notice it earlier, w may now have diverged if (this.k == 0 && w.compareTo(this.minusOne) < 0 || this.k == -1 && w.compareTo(this.minusOne) > 0) { throw new ComplexException(new ArithmeticException("Result would be complex")); } // Check the convergence if (!converges) { digits = w.equalDigits(oldW); accuracy = digits; converges = (digits >= initialPrecision / 4); } if (converges) { w = w.precision(shiftLeftPrecision(accuracy, 4, Apcomplex.EXTRA_PRECISION)); } } return w.precision(this.targetPrecision); } public Apcomplex complex() throws ArithmeticException, ApfloatRuntimeException { if (this.z.real().signum() == 0 && this.z.imag().signum() == 0) { if (this.k == 0) { return this.z; } else { throw new ArithmeticException("W_" + this.k + " of zero"); } } // To compute the initial value, we use the algorithms from // "On the Lambert W Function" (https://cs.uwaterloo.ca/research/tr/1993/03/W.pdf) by R. M. Corless et al.: // - (4.20): near zero and near infinity (i.e. all cases not specifically mentioned below): // W_k(z) = log(z) + 2*pi*k*i-log(log(z) + 2*pi*k*i) // - (4.22): anywhere near the branch point -1/e (very close) for W_0: // p = sqrt(2*(e*z+1)) // W_0(z) = -1 + p - 1/3 p^2 + 11/72 p^3 ... // - Similarly near the branch point, for W_-1, when imag(z) >= 0, and also for W_1 when imag(z) < 0: // p = -sqrt(2*(e*z+1)) // - (Remark after 4.20): for real-valued W_-1(x): // W_-1(x) = log(-x) - log(-log(-x)) // Note that we don't necessarily need a very accurate initial guess; the iteration only needs to converge (to the correct branch). // Also note that precision is greatly reduced for k = 0, 1, -1 near the branch point -1/e (only on one side for k = +-1) Apcomplex w; long initialPrecision = DOUBLE_PRECISION[this.radix]; // If there is an imaginary part, we must keep it and not set it to zero, to get correct log() result later Apcomplex initialZ = ApfloatHelper.limitPrecision(this.z, initialPrecision); long digits = 0; long oldAccuracy = 0; try { // Check if it's a real valued argument, or at least very close to the branch point if it's beyond it if (this.k == 0 && this.z.imag().signum() == 0 && this.z.real().compareTo(this.minusOnePerE) > 0) { // Real valued W_0, x >= -1/e return doReal(); } else if (this.k == -1 && this.z.imag().signum() == 0 && this.z.real().signum() < 0 && this.z.real().compareTo(this.minusOnePerE) > 0) { // Real valued W_-1, -1/e <= x < 0 return doReal(); } } catch (ComplexException ce) { // Value was actually slightly beyond the branch point, retry as complex valued function } if (this.k == 0 && this.z.scale() < 0) { // Small and close to zero w = initialZ; } else if (this.k == 0 && this.z.scale() < 1 && !this.close) { // Moderate values close to zero but not close to branch point w = ApcomplexMath.log(initialZ.add(this.one)); } else if (this.k > 1 || this.k < -1 || !this.close) { // Close to zero, or close to infinity, or complex branches (i.e. not close to the branch point) w = logApprox(initialZ); } else if (this.k == 0) { // Close to the branch point -1/e w = positiveComplexSeries(); digits = oldAccuracy = w.precision(); w = w.precision(shiftLeftPrecision(digits, 2)); } else if (this.k == -1 && this.z.imag().signum() >= 0 || this.k == 1 && this.z.imag().signum() < 0) { // Close to the branch point -1/e w = negativeComplexSeries(); digits = oldAccuracy = w.precision(); w = w.precision(shiftLeftPrecision(digits, 2)); } else { // Close to the branch point on W_1 or W_-1 but on the the side where the default approximation works w = logApprox(initialZ); } if (!this.close && (this.k == 0 || this.k == -1 && this.z.imag().signum() >= 0 || this.k == 1 && this.z.imag().signum() < 0)) { // If x is slightly close to the branch point (from the correct side), but not very close, precision is still reduced this.targetPrecision -= (this.z.equalDigits(this.minusOnePerE) + 1) / 2; } this.targetPrecision = Math.max(this.targetPrecision, 1); // In case input is -0.3 with precision 1 boolean done = (digits >= this.targetPrecision); if (!done) { // Precalculate the needed values once to the required precision ApfloatMath.logRadix(this.targetPrecision, this.radix); } // Fritsch's iteration (quartic) // For values close to -1/e the convergence is initially worse but eventually becomes quartic Apcomplex oldW; boolean converges = false; // If there are at least a few correct digits in the result for (int j = 0; j < 50 && !done; j++) // Should be enough iterations { oldW = w; // Calculate one Fritsch's iteration // In order to pick the correct branch of the logarithm, we have to look at the expanded format of the formula // See: F. N. Fritsch, R. E. Shafer, and W. P. Crowley, "Algorithm 443: Solution of the transcendental equation we^w = x", Communications of the ACM, 16 (1973), p. 123-124 Apcomplex z = fixLogBranch(log(this.z.divide(w)), w).subtract(w); Apcomplex w1 = this.one.add(w); Apcomplex q = z.multiply(this.two).divide(this.three).add(w1).multiply(w1).multiply(this.two); Apcomplex e = z.divide(w1).multiply(q.subtract(z)).divide(q.subtract(this.two.multiply(z))); // Check the accuracy of the result, initially convergence can be slow but becomes quartic eventually long accuracy = (converges ? -e.scale() : digits); double rate = Math.min(Math.max(accuracy / Math.max(1.0, oldAccuracy), 1.0), 4.0); if (accuracy >= this.targetPrecision / rate) { done = true; } oldAccuracy = accuracy; w = w.multiply(this.one.add(e)); // Check the convergence if (!converges) { digits = w.equalDigits(oldW); accuracy = digits; converges = (digits >= initialPrecision / 4); } if (converges) { w = w.precision(shiftLeftPrecision(accuracy, 4, Apcomplex.EXTRA_PRECISION)); } } return w.precision(this.targetPrecision); } private Apcomplex log(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { Apcomplex logz = ApcomplexMath.log(z); logz = ApfloatHelper.ensurePrecision(logz, z.precision()); // Issue #10: precision might be very low if z is close to 1, thanks to Axel Kramer for finding this bug if (this.k != 0) { // log(z) + 2*pi*k*i Apcomplex offset = new Apcomplex(Apfloat.ZERO, twoPiK()); logz = logz.add(offset); } return logz; } private Apcomplex logApprox(Apcomplex z) throws ArithmeticException, ApfloatRuntimeException { // W_k(z) = log(z) + 2*pi*k*i - log(log(z) + 2*pi*k*i) Apcomplex logz = log(z); Apcomplex w = logz.subtract(ApcomplexMath.log(logz)); return w; } private Apcomplex p() throws ApfloatRuntimeException { // p = sqrt(2 (e z + 1)) if (this.p == null) { Apfloat e = new Apfloat(Math.E, Apfloat.DEFAULT, this.radix); this.p = ApcomplexMath.sqrt(this.two.multiply(e.multiply(this.z).add(this.one))); long precision = e.precision(); while (this.p.precision() <= -this.p.scale() && precision < this.precision) { // Very close to the branch point; need to get a better approximation precision = shiftLeftPrecision(precision, 1); this.p = ApcomplexMath.sqrt(this.two.multiply(e(precision).multiply(this.z).add(this.one))); } // Target precision is reduced very near the branch point if (this.p.real().signum() == 0 && this.p.imag().signum() == 0) { this.targetPrecision /= 2; } else { this.targetPrecision += this.p.scale() - 1; } } return this.p; } private Apfloat positiveRealSeries() throws ComplexException, ApfloatRuntimeException { return realSeries(p()); } private Apfloat negativeRealSeries() throws ComplexException, ApfloatRuntimeException { return realSeries(p().negate()); } private Apcomplex positiveComplexSeries() throws ApfloatRuntimeException { return complexSeries(p()); } private Apcomplex negativeComplexSeries() throws ApfloatRuntimeException { return complexSeries(p().negate()); } private Apfloat realSeries(Apcomplex p) throws ComplexException, ApfloatRuntimeException { if (p.imag().signum() != 0) { throw new ComplexException(new ArithmeticException("Result would be complex")); } return complexSeries(p).real(); } private Apcomplex complexSeries(Apcomplex p) throws ApfloatRuntimeException { // -1 + p - 1/3 p^2 + 11/72 p^3 + ... Aprational factor2 = new Aprational(this.one, this.three); Aprational factor3 = new Aprational(new Apint(11, this.radix), new Apint(72, this.radix)); Apcomplex p2 = p.multiply(p); Apcomplex p3 = p2.multiply(p); Apcomplex w = this.minusOne.add(p).subtract(factor2.multiply(p2)).add(factor3.multiply(p3)); // Error term is O(p^4) so the maximum precision from the above is -4 * p.scale(), but could be less if p is less accurate long seriesPrecision = Util.ifFinite(-p3.scale(), -p3.scale() - p.scale()); w = w.precision(Math.min(w.precision(), seriesPrecision)); return w; } // Multiply the precision and check for overflow, as ifFinite() only works reliably if the result is at most twice the original number private long shiftLeftPrecision(long precision, int i) { return shiftLeftPrecision(precision, i, 0); } private long shiftLeftPrecision(long precision, int i, long add) { while (--i >= 0) { precision = ApfloatHelper.extendPrecision(precision, precision); } return ApfloatHelper.extendPrecision(precision, add); } // Usually we get the correct branch of W by adding 2 k pi i to the logarithm taken previously, // however sometimes the result just is off by either 2 pi i or -2 pi i and we have to adjust. // Assuming that our initial guess is close enough to the correct branch value, if the // next value differs by more than pi i, then we adjust by +-2 pi i, and can get the result to // converge to the correct branch of W. // Because we use log(z / w) instead of log(z) - log(w) the branch of the logarithm behaves // quite in a nontrivial way, so this is a heuristic algorithm. // This problem seems to apply only to the Fritsch algorithm as it uses log(); other algorithms // using exp() don't seem to suffer from this issue (like Halley's method). private Apcomplex fixLogBranch(Apcomplex next, Apcomplex previous) throws ApfloatRuntimeException { if (this.k != 0) { int comparePrecision = DOUBLE_PRECISION[next.radix()]; double diff = next.imag().precision(comparePrecision).subtract(previous.imag()).doubleValue(); if (diff < -Math.PI) { Apcomplex twoPiI = new Apcomplex(Apfloat.ZERO, twoPi()); next = next.add(twoPiI); } else if (diff > Math.PI) { Apcomplex twoPiI = new Apcomplex(Apfloat.ZERO, twoPi()); next = next.subtract(twoPiI); } } return next; } private Apfloat twoPi() throws ApfloatRuntimeException { if (this.twoPi == null) { this.twoPi = this.two.multiply(ApfloatMath.pi(this.precision, this.radix)); } return this.twoPi; } private Apfloat twoPiK() throws ApfloatRuntimeException { if (this.twoPiK == null) { this.twoPiK = twoPi().multiply(new Apint(this.k, this.radix)); } return this.twoPiK; } private Apfloat e(long precision) throws ApfloatRuntimeException { if (this.e == null || this.e.precision() < precision) { this.e = ApfloatMath.exp(new Apfloat(1, precision, this.radix)); } return this.e; } private Apfloat x; private Apcomplex z; private int radix; private long precision; private long targetPrecision; private long k; private boolean close; private Apint minusOne; private Apint one; private Apint two; private Apint three; private Apfloat twoPi; private Apfloat twoPiK; private Apfloat e; private Apfloat minusOnePerE; private Apcomplex p; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/LossOfPrecisionException.java000066400000000000000000000050201461767713300273410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; /** * Exception indicating a result that would have no significant digits.

* * An example would be ApfloatMath.sin(new Apfloat(1e100)). * Rather than returning an arbitrary result, this exception should be thrown.

* * Note that a subtraction where a complete loss of digits occurs does not throw * this exception but instead just returns zero. * * @since 1.5 * @version 1.14.0 * @author Mikko Tommila */ public class LossOfPrecisionException extends NumericComputationException { /** * Constructs a new apfloat loss of precision exception with an empty detail message. */ public LossOfPrecisionException() { } /** * Constructs a new apfloat loss of precision exception with the specified detail message. * * @param message The detail message. */ public LossOfPrecisionException(String message) { super(message); } /** * Constructs a new apfloat loss of precision exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public LossOfPrecisionException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/NumericComputationException.java000066400000000000000000000045311461767713300301130ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; /** * Exception indicating that something went wrong in a numeric computation.

* * EU Artificial Intelligence Act note: the name of this class was generated with artificial intelligence. * * @since 1.14.0 * @version 1.14.0 * @author Mikko Tommila */ public class NumericComputationException extends ApfloatRuntimeException { /** * Constructs a new apfloat numeric computation exception with an empty detail message. */ public NumericComputationException() { } /** * Constructs a new apfloat numeric computation exception with the specified detail message. * * @param message The detail message. */ public NumericComputationException(String message) { super(message); } /** * Constructs a new apfloat numeric computation exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public NumericComputationException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = 1L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/OverflowException.java000066400000000000000000000046501461767713300260730ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; /** * Exception indicating an overflow in a calculation.

* * For example ApfloatMath.exp(new Apfloat(1e100)).

* * If the exponent is too large to fit in a long, * the situation can't be handled. Note that there is no * "infinity" apfloat value that could be returned as the result. * * @since 1.5 * @version 1.14.0 * @author Mikko Tommila */ public class OverflowException extends NumericComputationException { /** * Constructs a new apfloat overflow exception with an empty detail message. */ public OverflowException() { } /** * Constructs a new apfloat overflow exception with the specified detail message. * * @param message The detail message. */ public OverflowException(String message) { super(message); } /** * Constructs a new apfloat overflow exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public OverflowException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ParallelHelper.java000066400000000000000000000142621461767713300253050ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.Arrays; import java.util.List; import java.util.ArrayList; import java.util.Queue; import java.util.PriorityQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicInteger; /** * Helper methods for parallel algorithms. * * @since 1.8.0 * @version 1.14.0 * @author Mikko Tommila */ class ParallelHelper { @FunctionalInterface public interface ProductKernel { public void run(Queue heap); } private ParallelHelper() { } /** * Multiply two smallest elements in the heap and put the product back to the heap, * until only one element remains. * * @param x The elements to be multiplied. * @param heap The priority queue to use. Must be initially empty. * @param kernel The multiplication kernel callback. */ // Thanks to Peter Luschny and Spiro Trikaliotis for the improved algorithm! public static void parallelProduct(T[] x, Queue heap, ProductKernel kernel) { // If there are lots of numbers then use a fully parallel algorithm, for small products the overhead is not worth it ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); if (x.length >= 1000 && numberOfProcessors > 1) { // First multiply small numbers in parallel; // number size would be so small that they would not be multiplied using a parallel algorithm (roughly dependent on cache L1 size) long maxSize = (long) (ctx.getCacheL1Size() * 2.5 / Math.log((double) ctx.getDefaultRadix())); // There is no efficient "ConcurrentPriorityQueue" data structure, so we just split the data List> subHeaps = new ArrayList<>(); for (int i = 0; i < numberOfProcessors; i++) { subHeaps.add(new PriorityQueue<>(heap)); } int i = 0; for (T a : x) { // Add only small numbers to the parallel heaps, big numbers go to the main heap directly (a.size() <= maxSize ? subHeaps.get(i++) : heap).add(a); i = (i == numberOfProcessors ? 0 : i); } AtomicInteger index = new AtomicInteger(); Runnable runnable = () -> { Queue subHeap = subHeaps.get(index.getAndIncrement()); long size = 0; // Multiply numbers as long as there are at least two and they are small enough // Note that with the heap we will start with the smallest numbers and size will grow while (subHeap.size() > 1 && size <= maxSize) { kernel.run(subHeap); size = subHeap.peek().size(); } synchronized (heap) { // Synchronize the adds; nothing must be reading the heap at the same time heap.addAll(subHeap); } }; // Run the runnable in multiple threads runParallel(runnable, numberOfProcessors - 1); } else { // Use the single-thread algorithm heap.addAll(Arrays.asList(x)); } // Then just multiply the remaining numbers; // they will presumably be so big that the multiplications use the parallel algorithm anyway while (heap.size() > 1) { kernel.run(heap); } } public static T getFuture(Future future) { try { return future.get(); } catch (InterruptedException ie) { throw new ApfloatInterruptedException("Waiting for dispatched task to complete was interrupted", ie); } catch (ExecutionException ee) { throw new ApfloatRuntimeException("Task execution failed", ee); } } public static void runParallel(Runnable runnable) { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfThreads = ctx.getNumberOfProcessors() - 1; runParallel(runnable, numberOfThreads); } private static void runParallel(Runnable runnable, int numberOfThreads) { ApfloatContext ctx = ApfloatContext.getContext(); ExecutorService executorService = ctx.getExecutorService(); List> futures = new ArrayList>(); // Dispatch other threads, if any for (int i = 0; i < numberOfThreads; i++) { futures.add(executorService.submit(runnable)); } // Also run the Runnable in the current thread runnable.run(); // Join the other threads, if any futures.forEach(ParallelHelper::getFuture); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/RadixConversionHelper.java000066400000000000000000000156031461767713300266660ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.List; import java.util.ArrayList; import org.apfloat.spi.Util; import static org.apfloat.spi.RadixConstants.*; /** * Helper class for radix conversion. * * @version 1.9.0 * @author Mikko Tommila */ class RadixConversionHelper { private static class RadixPowerList { public RadixPowerList(int fromRadix, int toRadix, long precision) throws ApfloatRuntimeException { this.list = new ArrayList<>(); this.list.add(new Apfloat(fromRadix, ApfloatHelper.extendPrecision(precision), toRadix)); } public Apfloat pow(long n) throws ApfloatRuntimeException { if (n == 0) { return Apfloat.ONE; } int p = 0; while ((n & 1) == 0) { p++; n >>>= 1; } Apfloat r = get(p); while ((n >>>= 1) > 0) { Apfloat x = get(++p); if ((n & 1) != 0) { r = r.multiply(x); } } return r; } private Apfloat get(int index) throws ApfloatRuntimeException { Apfloat x; if (this.list.size() > index) { x = this.list.get(index); } else { x = get(index - 1); x = x.multiply(x); this.list.add(x); } return x; } private List list; } private RadixConversionHelper() { } public static Apfloat toRadix(Apfloat x, int toRadix) throws ApfloatRuntimeException { if (x.radix() == toRadix) { return x; } if (x.signum() == 0) { return new Apfloat(0, toRadix); } int fromRadix = x.radix(); long size = x.size(), scale = x.scale(), precision = getPrecision(x.precision(), fromRadix, toRadix); RadixPowerList radixPowerList = new RadixPowerList(fromRadix, toRadix, precision); return toRadixIntegerPart(x, toRadix, size, scale, radixPowerList) .add(toRadixFractionalPart(x, toRadix, size, scale, radixPowerList)) .precision(precision); } private static Apfloat toRadixIntegerPart(Apfloat x, int toRadix, long size, long scale, RadixPowerList radixPowerList) throws ApfloatRuntimeException { if (scale <= 0) { // Integer part doesn't exist return Apfloat.ZERO; } else if (scale > size) { // No fractional part; trailing zeros in integer part long shift = scale - size; x = ApfloatMath.scale(x, -shift); x = toRadixNormalizedPart(x, toRadix, size, radixPowerList); return x.multiply(radixPowerList.pow(shift)); } else { // Fractional part exists (might be zero-length though) x = x.truncate(); return toRadixNormalizedPart(x, toRadix, x.scale(), radixPowerList); } } private static Apfloat toRadixFractionalPart(Apfloat x, int toRadix, long size, long scale, RadixPowerList radixPowerList) throws ApfloatRuntimeException { if (size > scale) { // Fractional part exists if (scale > 0) { // Both integer and fractional parts exist x = x.frac(); size -= scale; scale = 0; } long precision = getPrecision(x.precision(), x.radix(), toRadix), shift = size - scale; x = ApfloatMath.scale(x, shift); x = toRadixNormalizedPart(x, toRadix, size, radixPowerList); return x.precision(precision).divide(radixPowerList.pow(shift)); } else { // Fractional part doesn't exist return Apfloat.ZERO; } } private static Apfloat toRadixNormalizedPart(Apfloat x, int toRadix, long size, RadixPowerList radixPowerList) throws ApfloatRuntimeException { long maxPow2 = Util.round2down(size); return split(x, toRadix, size, maxPow2, radixPowerList); } private static Apfloat split(Apfloat x, int toRadix, long size, long split, RadixPowerList radixPowerList) throws ApfloatRuntimeException { if (size <= 0) { return Apfloat.ZERO; } else if (size <= LONG_DIGITS[x.radix()]) { return new Apfloat(x.longValue(), Apfloat.INFINITE, toRadix); } else { x = ApfloatMath.scale(x, -split); Apfloat top = x.truncate(), bottom = ApfloatMath.scale(x.frac(), split); return split(top, toRadix, size - split, split >> 1, radixPowerList).multiply(radixPowerList.pow(split)) .add(split(bottom, toRadix, split, split >> 1, radixPowerList)); } } private static long getPrecision(long precision, int fromRadix, int toRadix) throws ApfloatRuntimeException { long newPrecision = (long) ((double) precision * Math.log((double) fromRadix) / Math.log((double) toRadix)); if (fromRadix < toRadix) { // Underflow is possible but overflow not, in the above calculation newPrecision = Math.max(1, newPrecision); } return Util.ifFinite(precision, newPrecision); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/RootFinder.java000066400000000000000000000055351461767713300244670ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.function.BiFunction; import java.util.function.Function; import org.apfloat.spi.Util; /** * Helper class for finding roots of functions. * * @since 1.13.0 * @version 1.13.0 * @author Mikko Tommila */ class RootFinder { private RootFinder() { } /** * Find the root of the given function with Newton's method, starting from the given initial guess. * * @param f The function. * @param fp The derivative of the function, first argument is x, second argument is f(x) * @param y The function value to match (e.g. zero to find zeros, some other value to find inverses of functions) * @param initialGuess The initial guess * @param targetPrecision Target precision of the result * @return The root */ public static Apfloat findRoot(Function f, BiFunction fp, Apfloat y, Apfloat initialGuess, long targetPrecision) { Apfloat x = initialGuess; long workingPrecision = x.precision(), precision; do { Apfloat fn = f.apply(x), fpn = fp.apply(x, fn), d = fn.subtract(y).divide(fpn); precision = (d.signum() == 0 ? x.precision() : x.scale() - d.scale()); if (precision > 0) { workingPrecision = Math.min(targetPrecision, Math.max(workingPrecision, Util.ifFinite(precision, 2 * Util.ifFinite(precision, 2 * precision)))); } x = x.subtract(d).precision(workingPrecision); } while (precision < targetPrecision); return x.precision(targetPrecision); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/RoundingHelper.java000066400000000000000000000221361461767713300253350ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import static org.apfloat.ApfloatMath.abs; /** * Helper class for rounding functions. * * @since 1.7.0 * @version 1.11.0 * @author Mikko Tommila */ class RoundingHelper { private RoundingHelper() { } public static Apfloat roundToMultiple(Apfloat x, Apfloat y, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0) { return x; } else if (y.signum() == 0) { throw new ArithmeticException("Non-zero as multiple of zero"); } // Get rid of residual digits int signum = x.signum(); x = roundToPrecision(abs(x), x.precision(), RoundingMode.UNNECESSARY); y = roundToPrecision(abs(y), y.precision(), RoundingMode.UNNECESSARY); long precision; if (x.compareTo(y) < 0) { precision = Apfloat.EXTRA_PRECISION; // abs(x) < abs(y) } else { long scaleDiff = x.scale() - y.scale(); // We now know that x.scale() >= y.scale() scaleDiff = (scaleDiff < 0 ? Apfloat.INFINITE : scaleDiff); // Check for overflow precision = ApfloatHelper.extendPrecision(scaleDiff); // Some extra precision to avoid round-off errors } Apfloat i = x.precision(precision).divide(y.precision(precision)); Apint r = roundToInteger(i, RoundingMode.HALF_UP), two = new Apint(2, x.radix()); if (r.multiply(y.precision(Apfloat.INFINITE)).equals(x.precision(Apfloat.INFINITE))) { // x / y is an integer i = r; } else if ((r = roundToInteger(i.multiply(two), RoundingMode.HALF_UP)).multiply(y.precision(Apfloat.INFINITE)).equals(x.precision(Apfloat.INFINITE).multiply(two))) { // x / y is a half-integer i = new Aprational(r, two); // In an odd radix you can't represent half with an exact expansion like 0.5 in decimal } i = (signum < 0 ? i.negate() : i); i = roundToInteger(i, roundingMode); i = i.multiply(y); return i; } public static Aprational roundToMultiple(Aprational x, Aprational y, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0) { return x; } else if (y.signum() == 0) { throw new ArithmeticException("Non-zero as multiple of zero"); } y = AprationalMath.abs(y); Aprational i = roundToInteger(x.divide(y), roundingMode); i = i.multiply(y); return i; } public static Apfloat roundToPlaces(Apfloat x, long places, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { if (x.signum() == 0) { return x; } x = x.scale(places); if (x.signum() == 0) { // Underflow now, and might overflow later throw new OverflowException("Underflow / overflow"); } x = roundToInteger(x, roundingMode); if (places == Long.MIN_VALUE) { x = ApfloatMath.scale(x, Long.MIN_VALUE >>> 1); x = ApfloatMath.scale(x, Long.MIN_VALUE >>> 1); } else { x = ApfloatMath.scale(x, -places); } return x; } public static Apfloat roundToPrecision(Apfloat x, long precision, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { if (precision <= 0) { throw new IllegalArgumentException("Invalid precision: " + precision); } if (x.signum() == 0 || precision == Apfloat.INFINITE) { return x.precision(precision); } long targetPrecision = precision; precision = Math.min(precision, x.size()); // To get rid of any residual digits // Can't optimize by checking x.size() <= precision as the number might have hidden residual digits long scale = x.scale(); boolean overflow = (scale - precision >= scale); if (overflow) { // Avoid overflow of longs, do scaling in two parts x = x.scale(-scale); x = x.scale(precision); } else { x = x.scale(precision - scale); } x = roundToInteger(x, roundingMode); if (overflow) { // Avoid overflow of longs, do scaling in two parts x = ApfloatMath.scale(x, -precision); x = ApfloatMath.scale(x, scale); } else { x = ApfloatMath.scale(x, scale - precision); } return x.precision(targetPrecision); } public static Apint roundToInteger(Apfloat x, RoundingMode roundingMode) throws IllegalArgumentException, ArithmeticException, ApfloatRuntimeException { Apint i; switch (roundingMode) { case UP: i = x.roundAway(); break; case DOWN: i = x.truncate(); break; case CEILING: i = x.ceil(); break; case FLOOR: i = x.floor(); break; case HALF_UP: case HALF_DOWN: case HALF_EVEN: Apint whole = x.truncate(); Apfloat fraction = x.frac().abs(); int comparison = fraction.compareToHalf(); if (comparison < 0 || comparison == 0 && roundingMode.equals(RoundingMode.HALF_DOWN)) { i = x.truncate(); } else if (comparison > 0 || comparison == 0 && roundingMode.equals(RoundingMode.HALF_UP)) { i = x.roundAway(); } else { i = (isEven(whole) ? x.truncate() : x.roundAway()); } break; case UNNECESSARY: if (x.size() > x.scale()) { throw new ArithmeticException("Rounding necessary"); } i = x.truncate(); // To get rid of any residual digits break; default: throw new IllegalArgumentException("Unknown rounding mode: " + roundingMode); } return i; } public static int compareToHalf(Apfloat x) { int comparison; if (x.radix() % 2 == 0) { comparison = x.compareTo(new Apfloat("0." + Character.forDigit(x.radix() / 2, x.radix()), Apfloat.INFINITE, x.radix())); } else { // In an odd radix, half has an infinite digit expansion Apint one = new Apint(1, x.radix()); Apint two = new Apint(2, x.radix()); comparison = x.precision(Apfloat.INFINITE).multiply(two).compareTo(one); } return comparison; } public static int compareToHalf(Aprational x) { Aprational half = new Aprational(new Apint(1, x.radix()), new Apint(2, x.radix())); int comparison = x.compareTo(half); return comparison; } private static boolean isEven(Apint x) { // This could be further optimized if the radix is even // Note that any fractional part can never be exactly half when the radix is odd as a float, only as a rational Apint two = new Apint(2, x.radix()); return (x.mod(two).signum() == 0); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ShutdownMap.java000066400000000000000000000036441461767713300246640ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.Map; import java.util.AbstractMap; import java.util.Set; /** * Map that always throws ApfloatRuntimeException on all operations. * Can be used to replace cache maps after JVM shutdown and clean-up * has been initiated to prevent other threads from performing any operations. * * @since 1.6.2 * @version 1.6.2 * @author Mikko Tommila */ class ShutdownMap extends AbstractMap { public ShutdownMap() { } @Override public Set> entrySet() { throw new ApfloatRuntimeException("Shutdown in progress"); } @Override public V put(K key, V value) { throw new ApfloatRuntimeException("Shutdown in progress"); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/ZetaHelper.java000066400000000000000000000235651461767713300244620ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import org.apfloat.spi.Util; /** * Helper class for the Riemann zeta function. * * @since 1.11.0 * @version 1.14.0 * @author Mikko Tommila */ class ZetaHelper { // See http://numbers.computation.free.fr/Constants/Miscellaneous/zetaevaluations.pdf // Numerical evaluation of the Riemann Zeta-function, Xavier Gourdon and Pascal Sebah, 23 July 2003 // See https://arxiv.org/pdf/1703.01414.pdf // The Zetafast algorithm for computing zeta functions, Kurt Fischer, 8 June 2017 public static Apcomplex zeta(Apcomplex s) { int radix = s.radix(); Apint one = Apint.ONES[radix]; if (s.equals(one)) { throw new ArithmeticException("Zeta of one"); } Apint two = new Apint(2, radix); if (s.isZero()) { return new Aprational(one, two).negate(); } long precision = s.precision(); if (s.isInteger() && s.real().signum() < 0) { if (s.real().truncate().mod(two).signum() == 0) { return Apcomplex.ZEROS[radix]; } if (precision == Apfloat.INFINITE) { try { long n1 = one.subtract(s.real()).longValueExact(); return AprationalMath.bernoulli(n1, radix).divide(new Apint(n1, radix)).negate(); } catch (ArithmeticException ae) { // longValueExact overflow } } } if (precision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot calculate zeta function to infinite precision"); } if (s.real().signum() < 0) { long extraPrecision = ApfloatHelper.getSmallExtraPrecision(radix); s = ApfloatHelper.extendPrecision(s, extraPrecision); Apcomplex result = chi(s).multiply(zeta(one.subtract(s))); return ApfloatHelper.reducePrecision(result, extraPrecision); } if (s.imag().signum() < 0) { return zeta(s.conj()).conj(); } if (s.imag().doubleValue() == Double.POSITIVE_INFINITY) { throw new OverflowException("Imaginary part too large"); } if (s.real().compareTo(one) < 0 && s.imag().compareTo(new Apint(50000, radix)) > 0) { // Zetafast is only faster for rather large values of Im(s) return new ZetaHelper().zetafast(s); } else { return alternatingSum(s); } } private static Apcomplex chi(Apcomplex s) { int radix = s.radix(); Apint one = new Apint(1, radix), two = new Apint(2, radix); Apfloat pi = ApfloatMath.pi(s.precision(), radix); Apcomplex s1 = s.subtract(one); return ApcomplexMath.pow(two, s).multiply(ApcomplexMath.pow(pi, s1)).multiply(ApcomplexMath.sin(pi.multiply(s).divide(two))).multiply(ApcomplexMath.gamma(s1.negate())); } public static Apcomplex alternatingSum(Apcomplex s) { int radix = s.radix(); long doublePrecision = ApfloatHelper.getDoublePrecision(radix), workingPrecision = s.precision(); Apint one = new Apint(1, radix), two = new Apint(2, radix), four = new Apint(4, radix); double t = Math.abs(s.imag().doubleValue()), s12 = ApcomplexMath.abs(one.subtract(ApcomplexMath.pow(two, one.subtract(s.precision(doublePrecision))))).doubleValue(); long n = (long) ((workingPrecision * Math.log(radix) + t * Math.PI / 2 + Math.log((1 + 2 * t) / s12)) / Math.log(3 + Math.sqrt(8))), n2 = Util.multiplyExact(n, 2); Apfloat denominator = ApfloatMath.factorial(n2, workingPrecision, radix), numerator = new Apint(n, radix).multiply(denominator).multiply(ApfloatMath.pow(four.precision(workingPrecision), n)), d = Apfloat.ZERO; Apcomplex sum = Apcomplex.ZERO; for (long k = n; k > 0; k--) { numerator = numerator.divide(new Apint(n + k, radix)); d = d.add(numerator.divide(denominator)); numerator = numerator.divide(four); denominator = denominator.multiply(new Apint(n - k + 1, radix)).divide(new Apint(2 * k, radix)).divide(new Apint(2 * k - 1, radix)); sum = sum.add(((k & 1) == 0 ? d.negate() : d).multiply(ApcomplexMath.pow(new Apint(k, radix), s.negate()))); } d = d.add(numerator.divide(denominator)); Apcomplex result = one.divide(d.multiply(one.subtract(ApcomplexMath.pow(two, one.subtract(s))))).multiply(sum); return result; } public Apcomplex zetafast(Apcomplex s) { this.radix = s.radix(); s = ApfloatHelper.extendPrecision(s); this.workingPrecision = s.precision(); double t = s.imag().doubleValue(); this.v = findRoot(s, t, radix, workingPrecision); double N = 1.11 * Math.sqrt(1 + (0.5 + t) / v); this.NN = new Apfloat(N, workingPrecision, radix); long M = (long) Math.ceil(N); this.one = new Apint(1, radix); this.two = new Apint(2, radix); this.pi = ApfloatMath.pi(workingPrecision, radix); this.i = new Apcomplex(Apcomplex.ZERO, one); this.s1 = s.subtract(one); this.oneS = s1.negate(); this.iTwoPiN = i.divide(two.multiply(pi).multiply(NN)); this.gammaS = ApcomplexMath.gamma(s); Apint vv = new Apint(v, radix); Apcomplex result = D(N, s).add(E1(M, s)).subtract(ApcomplexMath.gamma(oneS.add(vv)).divide(oneS.multiply(ApcomplexMath.gamma(vv))).multiply(ApcomplexMath.pow(NN, oneS))); result = ApfloatHelper.reducePrecision(result); return result; } private static long findRoot(Apcomplex s, double t, int radix, long workingPrecision) { double m = Math.max(1 - s.real().doubleValue(), 0) / 2, x = 0, p; do { p = x; x = Math.log(8) + workingPrecision * Math.log(radix) + m * Math.log(0.5 + x + t); } while (Math.ceil(x) != Math.ceil(p)); return (long) Math.ceil(x); } private Apcomplex D(double N, Apcomplex s) { double lambda = 3.151; long limit = (long) Math.ceil(lambda * v * N); Apcomplex sum = Apcomplex.ZERO; for (long n = 1; n <= limit; n++) { Apint nn = new Apint(n, radix); sum = sum.add(ApcomplexMath.pow(nn, s.negate()).multiply(Q(v, nn.divide(NN)))); } return sum; } private Apcomplex Q(long v, Apfloat m) { Apfloat numerator = new Apfloat(1, workingPrecision, radix), denominator = numerator; Apcomplex sum = Apcomplex.ZERO; for (long w = 0; w < v; w++) { sum = sum.add(numerator.divide(denominator)); numerator = numerator.multiply(m); denominator = denominator.multiply(new Apint(w + 1, radix)); } Apcomplex result = sum.multiply(ApcomplexMath.exp(m.negate())); return result; } private Apcomplex E1(long M, Apcomplex s) { Apcomplex sum = Apcomplex.ZERO; for (long m = 1; m <= M; m++) { sum = sum.add(E1(new Apint(m, radix), s)); } Apcomplex result = ApcomplexMath.pow(two.multiply(pi), s1).multiply(ApcomplexMath.gamma(oneS)).multiply(ApcomplexMath.exp(i.multiply(pi).divide(two).multiply(oneS))).multiply(sum); return result; } private Apcomplex E1(Apcomplex m, Apcomplex s) { Apcomplex miTwoPiN = m.add(iTwoPiN), denominator = gammaS, numerator = denominator.multiply(ApcomplexMath.pow(miTwoPiN, s1)), sum = Apcomplex.ZERO; for (long w = 0; w < v; w++) { Apint ww = new Apint(w, radix); sum = sum.add(numerator.divide(denominator)); Apint w1 = ww.add(one); numerator = numerator.multiply(iTwoPiN.negate()); denominator = denominator.multiply(w1).divide(s.subtract(w1)).multiply(miTwoPiN); } Apcomplex result = ApcomplexMath.pow(m, s1).subtract(sum); return result; } private int radix; private long workingPrecision; private long v; private Apfloat NN; private Apint one; private Apint two; private Apfloat pi; private Apcomplex i; private Apcomplex oneS; private Apcomplex s1; private Apcomplex iTwoPiN; private Apcomplex gammaS; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/doc-files/000077500000000000000000000000001461767713300234065ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java/org/apfloat/doc-files/apfloat-classes.gif000066400000000000000000000045251461767713300271640ustar00rootroot00000000000000GIF89at3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f!,t H*\ȰÇ#JHŋ3jȱǏ CIr! %SnDq!˗*cR<2aM8#4H3χ;!NyIѣH*]ʔ(eԩʐ+֙P*W%͞ ;Rچ;dUc]zQkOw ֜B5+mI㚍B^[/(,1wթ mx'y!_Wa)}[A ԙqx[i~Q"}x(bA&Uy8ݍ8#G1#$cC=$]*C2H~L!d 5/N$HP"$H[ʓ]Gb[ )З!5Pjb' i@WveAty&Hֹ灃uxv&\F 4桍zvrFt)% Ԟ*z(TT68S} kNīNfXly&Ǿj&KAK Vm$+`iZG+ڛGݺxGƪL՗YG [BD?[w0_MV]qWxpleyE 6)x1fsGGdlnᵗAo?wNPG-TW=b<q5'Ո(EdmhC_ d-H=eoLv_7V+˲j6vc]fw9؆8LJMyҟ#ެss?nQ* ѧomGmQ+ d [Tp"z X$n[1Ktm2,OA۸-ZEBV$bw&u H5y5$J:929Q 8h3jq7p[ 1Sx" G1Q19AW^&$J=6a!\@X؅MҊU哉ʤINP`_fTLbA0JtbDj*xD7Y!y#3Mj{-:' QljkZYYs-#iO3I1yn"#B,%_̖E8L[:RhNI`C.,Mf7٫99EC%MKM/,ھ25I* ~fJL+l2qKJ\P7tKZX ;apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/000077500000000000000000000000001461767713300233555ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/AbstractConvolutionBuilder.java000066400000000000000000000155131461767713300315370ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.spi.ConvolutionBuilder; import org.apfloat.spi.ConvolutionStrategy; import org.apfloat.spi.NTTBuilder; import org.apfloat.spi.NTTStrategy; import org.apfloat.spi.Util; /** * Abstract base class for creating convolutions of suitable type for the specified length.

* * Based on a work estimate, depending on the operand sizes and implementation-dependent * factors, the O(n2) long multiplication, Karatsuba multiplication and * the NTT algorithms are chosen e.g. as follows: * * * * * * * * * * * * * * * * * * *
Convolution algorithms
size1size2Algorithm
1616Long
16256Long
3232Long
32256Long
6464Karatsuba
64256NTT
6465536Karatsuba
128128NTT
12865536NTT
1284294967296Karatsuba
256256NTT
2564294967296Karatsuba
512512NTT
5124294967296NTT
* * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public abstract class AbstractConvolutionBuilder implements ConvolutionBuilder { /** * Subclass constructor. */ protected AbstractConvolutionBuilder() { } @Override public ConvolutionStrategy createConvolution(int radix, long size1, long size2, long resultSize) { long minSize = Math.min(size1, size2), maxSize = Math.max(size1, size2), totalSize = size1 + size2; if (minSize == 1) { return createShortConvolutionStrategy(radix); } else if (minSize <= getKaratsubaCutoffPoint()) { return createMediumConvolutionStrategy(radix); } else { float mediumCost = (float) minSize * maxSize, karatsubaCost = getKaratsubaCostFactor() * (float) Math.pow((double) minSize, LOG2_3) * maxSize / minSize, nttCost = getNTTCostFactor() * totalSize * Util.log2down(totalSize); if (mediumCost <= Math.min(karatsubaCost, nttCost)) { return createMediumConvolutionStrategy(radix); } else if (karatsubaCost <= nttCost) { return createKaratsubaConvolutionStrategy(radix); } else { ApfloatContext ctx = ApfloatContext.getContext(); NTTBuilder nttBuilder = ctx.getBuilderFactory().getNTTBuilder(); NTTStrategy nttStrategy = nttBuilder.createNTT(totalSize); return createThreeNTTConvolutionStrategy(radix, nttStrategy); } } } /** * Get the Karatsuba convolution cutoff point. * When either operand is shorter than this then the * medium-length convolution strategy should be used instead. * * @return The Karatsuba convolution cutoff point. * * @since 1.7.0 */ protected abstract int getKaratsubaCutoffPoint(); /** * Get the Karatsuba convolution cost factor. * It is used in determining the most efficient * convolution strategy for the given data lengths. * * @return The Karatsuba convolution cost factor. * * @since 1.7.0 */ protected abstract float getKaratsubaCostFactor(); /** * Get the NTT convolution cost factor. * It is used in determining the most efficient * convolution strategy for the given data lengths. * * @return The NTT convolution cost factor. * * @since 1.7.0 */ protected abstract float getNTTCostFactor(); /** * Create a short-length convolution strategy where the size of either * data set is one. * * @param radix The radix that will be used. * * @return A new short-length convolution strategy. * * @since 1.7.0 */ protected abstract ConvolutionStrategy createShortConvolutionStrategy(int radix); /** * Create a medium-length convolution strategy where the size of one * of the data sets is relatively small (but more than one). * * @param radix The radix that will be used. * * @return A new medium-length convolution strategy. * * @since 1.7.0 */ protected abstract ConvolutionStrategy createMediumConvolutionStrategy(int radix); /** * Create a Karatsuba convolution strategy. * * @param radix The radix that will be used. * * @return A new Karatsuba convolution strategy. * * @since 1.7.0 */ protected abstract ConvolutionStrategy createKaratsubaConvolutionStrategy(int radix); /** * Create a 3-NTT convolution strategy. * * @param radix The radix that will be used. * @param nttStrategy The underlying NTT strategy. * * @return A new 3-NTT convolution strategy. * * @since 1.7.0 */ protected abstract ConvolutionStrategy createThreeNTTConvolutionStrategy(int radix, NTTStrategy nttStrategy); private static final double LOG2_3 = Math.log(3.0) / Math.log(2.0); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/AbstractDataStorageBuilder.java000066400000000000000000000107251461767713300314160ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorageBuilder; import org.apfloat.spi.DataStorage; /** * Abstract base class for a data storage creation strategy. * Depending on the implementation-specific element size, the * requested data length and threshold values configured in the * current {@link ApfloatContext}, different types of data storages * are created. * * @since 1.7.0 * @version 1.8.2 * @author Mikko Tommila */ public abstract class AbstractDataStorageBuilder implements DataStorageBuilder { /** * Subclass constructor. */ protected AbstractDataStorageBuilder() { } @Override public DataStorage createDataStorage(long size) throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); // Sizes are in bytes if (size <= ctx.getMemoryThreshold() && size <= getMaxCachedSize()) { return createCachedDataStorage(); } else { return createNonCachedDataStorage(); } } @Override public DataStorage createCachedDataStorage(long size) throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); // Sizes are in bytes if (size <= ctx.getMaxMemoryBlockSize() && size <= getMaxCachedSize()) { // Use memory data storage if it can fit in memory return createCachedDataStorage(); } else { // If it can't fit in memory then still have to use disk data storage return createNonCachedDataStorage(); } } @Override public DataStorage createDataStorage(DataStorage dataStorage) throws ApfloatRuntimeException { if (isCached(dataStorage)) { long size = dataStorage.getSize(); ApfloatContext ctx = ApfloatContext.getContext(); // Sizes are in bytes if (size > ctx.getMemoryThreshold()) { // If it is a memory data storage and should be moved to disk then do so DataStorage tmp = createNonCachedDataStorage(); tmp.copyFrom(dataStorage); dataStorage = tmp; } } return dataStorage; } /** * Get the maximum cached data storage size. * * @return The maximum cached data storage size. */ protected abstract long getMaxCachedSize(); /** * Create a cached data storage. * * @return A new cached data storage. */ protected abstract DataStorage createCachedDataStorage() throws ApfloatRuntimeException; /** * Create a non-cached data storage. * * @return A new non-cached data storage. */ protected abstract DataStorage createNonCachedDataStorage() throws ApfloatRuntimeException; /** * Test if the data storage is of cached type. * * @param dataStorage The data storage. * * @return If the data storage is cached. */ protected abstract boolean isCached(DataStorage dataStorage) throws ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/AbstractNTTBuilder.java000066400000000000000000000115401461767713300276610ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.spi.BuilderFactory; import org.apfloat.spi.NTTBuilder; import org.apfloat.spi.NTTStrategy; import org.apfloat.spi.Util; /** * Abstract base class for creating Number Theoretic Transforms suitable for the * specified length, based on available memory configured in the {@link ApfloatContext}. * * @since 1.7.0 * @version 1.8.3 * @author Mikko Tommila */ public abstract class AbstractNTTBuilder implements NTTBuilder { /** * Subclass constructor. */ protected AbstractNTTBuilder() { } @Override public NTTStrategy createNTT(long size) { ApfloatContext ctx = ApfloatContext.getContext(); BuilderFactory builderFactory = ctx.getBuilderFactory(); int cacheSize = ctx.getCacheL1Size() / builderFactory.getElementSize(); long maxMemoryBlockSize = ctx.getMaxMemoryBlockSize() / builderFactory.getElementSize(); NTTStrategy nttStrategy; boolean useFactor3 = false; size = Util.round23up(size); // Round up to the nearest power of two or three times a power of two long power2size = (size & -size); // Power-of-two factor of the above if (size != power2size) { // A factor of three will be used, so the power-of-two part is one third of the whole transform length useFactor3 = true; } // Select transform for the power-of-two part if (power2size <= cacheSize / 2) { // The whole transform plus w-table fits into the cache, so use the simplest approach nttStrategy = createSimpleFNTStrategy(power2size); } else if (power2size <= maxMemoryBlockSize && power2size <= Integer.MAX_VALUE) { // The whole transform fits into the available main memory, so use a six-step in-memory approach nttStrategy = createSixStepFNTStrategy(power2size); } else { // The whole transform won't fit into available memory, so use a two-pass disk based approach nttStrategy = createTwoPassFNTStrategy(power2size); } if (useFactor3) { // Allow using a factor of three in any of the above selected transforms nttStrategy = createFactor3NTTStrategy(size, nttStrategy); } return nttStrategy; } /** * Create a simple NTT strategy. * * @param size The transform length that will be used. * * @return A new simple NTT strategy. */ protected abstract NTTStrategy createSimpleFNTStrategy(long size); /** * Create a six-step NTT strategy. * * @param size The transform length that will be used. * * @return A new six-step NTT strategy. */ protected NTTStrategy createSixStepFNTStrategy(long size) { return new SixStepFNTStrategy(); } /** * Create a two-pass NTT strategy. * * @param size The transform length that will be used. * * @return A new two-pass NTT strategy. */ protected NTTStrategy createTwoPassFNTStrategy(long size) { return new TwoPassFNTStrategy(); } /** * Create a factor-3 NTT strategy on top of another NTT strategy. * * @param size The transform length that will be used. * @param nttStrategy The underlying factor-2 NTT strategy. * * @return A new factor-3 NTT strategy. */ protected NTTStrategy createFactor3NTTStrategy(long size, NTTStrategy nttStrategy) { return new Factor3NTTStrategy(nttStrategy); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/AbstractStepFNTStrategy.java000066400000000000000000000120241461767713300307110ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import org.apfloat.spi.NTTStrategy; import org.apfloat.spi.NTTStepStrategy; import org.apfloat.spi.Util; /** * Abstract superclass for step-based FNT strategies.

* * All access to this class must be externally synchronized. * * @see NTTStepStrategy * * @since 1.7.0 * @version 1.8.0 * @author Mikko Tommila */ public abstract class AbstractStepFNTStrategy implements NTTStrategy, Parallelizable { /** * Subclass constructor. */ protected AbstractStepFNTStrategy() { ApfloatContext ctx = ApfloatContext.getContext(); this.stepStrategy = ctx.getBuilderFactory().getNTTBuilder().createNTTSteps(); } @Override public void transform(DataStorage dataStorage, int modulus) throws ApfloatRuntimeException { long length = dataStorage.getSize(); // Transform length n if (length > this.stepStrategy.getMaxTransformLength()) { throw new TransformLengthExceededException("Maximum transform length exceeded: " + length + " > " + this.stepStrategy.getMaxTransformLength()); } if (length < 2) { return; } assert (length == (length & -length)); // Must be a power of two // Treat the input data as a n1 x n2 matrix int logLength = Util.log2down(length), n1 = logLength >> 1, n2 = logLength - n1; n1 = 1 << n1; n2 = 1 << n2; // Now n2 >= n1 transform(dataStorage, n1, n2, length, modulus); } @Override public void inverseTransform(DataStorage dataStorage, int modulus, long totalTransformLength) throws ApfloatRuntimeException { long length = dataStorage.getSize(); // Transform length n if (Math.max(length, totalTransformLength) > this.stepStrategy.getMaxTransformLength()) { throw new TransformLengthExceededException("Maximum transform length exceeded: " + Math.max(length, totalTransformLength) + " > " + this.stepStrategy.getMaxTransformLength()); } if (length < 2) { return; } assert (length == (length & -length)); // Must be a power of two // Treat the input data as a n1 x n2 matrix int logLength = Util.log2down(length), n1 = logLength >> 1, n2 = logLength - n1; n1 = 1 << n1; n2 = 1 << n2; // Now n2 >= n1 inverseTransform(dataStorage, n1, n2, length, totalTransformLength, modulus); } @Override public long getTransformLength(long size) { return Util.round2up(size); } /** * Transform the data in steps. * * @param dataStorage The data. * @param n1 Height of the data matrix. * @param n2 Width of the data matrix. * @param length Length of the data. * @param modulus Which modulus to use. */ protected abstract void transform(DataStorage dataStorage, int n1, int n2, long length, int modulus) throws ApfloatRuntimeException; /** * Inverse transform the data in steps. * * @param dataStorage The data. * @param n1 Height of the data matrix. * @param n2 Width of the data matrix. * @param length Length of the data. * @param totalTransformLength Total transform length. * @param modulus Which modulus to use. */ protected abstract void inverseTransform(DataStorage dataStorage, int n1, int n2, long length, long totalTransformLength, int modulus) throws ApfloatRuntimeException; /** * The NTT steps. */ protected NTTStepStrategy stepStrategy; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/ApfloatInternalException.java000066400000000000000000000054541461767713300311720ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; /** * Exception indicating some unexpected apfloat * implementation specific error situation. * This exception can be thrown in different situations, for example: * *

    *
  • Backing storage failure. For example, if a number is stored on disk, * an IOException can be thrown in any of the disk operations, * if e.g. a file can't be created, or if the disk is full.
  • *
  • Operands of some operation have different radixes.
  • *
  • Other internal limitation, e.g. the maximum transform length * mathematically possible for the implementation, is exceeded.
  • *
* * @since 1.5 * @version 1.5 * @author Mikko Tommila */ public class ApfloatInternalException extends ApfloatRuntimeException { /** * Constructs a new apfloat internal exception with an empty detail message. */ public ApfloatInternalException() { } /** * Constructs a new apfloat internal exception with the specified detail message. * * @param message The detail message. */ public ApfloatInternalException(String message) { super(message); } /** * Constructs a new apfloat internal exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public ApfloatInternalException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/BackingStorageException.java000066400000000000000000000046331461767713300307700ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Exception indicating a backing storage failure.

* * For example, a large number can be stored on disk. * An IOException can be thrown in any of * the disk operations, for example if a file can't be * created, or if the disk is full. * * @since 1.5 * @version 1.5 * @author Mikko Tommila */ public class BackingStorageException extends ApfloatInternalException { /** * Constructs a new apfloat backing storage exception with an empty detail message. */ public BackingStorageException() { } /** * Constructs a new apfloat backing storage exception with the specified detail message. * * @param message The detail message. */ public BackingStorageException(String message) { super(message); } /** * Constructs a new apfloat backing storage exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public BackingStorageException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/ConcurrentSoftHashMap.java000066400000000000000000000065701461767713300304500ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.lang.ref.SoftReference; import java.util.AbstractMap; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentHashMap; /** * ConcurrentHashMap with softly referenced values. * The maximum map size is assumed to be limited so no * effort is made to expunge entries for stale values.

* * Values are not properly compared for equality so * the only actual concurrent method implemented is * putIfAbsent().

* * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ class ConcurrentSoftHashMap extends AbstractMap implements ConcurrentMap { private ConcurrentHashMap> map; public ConcurrentSoftHashMap() { this.map = new ConcurrentHashMap<>(); } @Override public void clear() { this.map.clear(); } @Override public Set> entrySet() { throw new UnsupportedOperationException(); } @Override public V get(Object key) { return unwrap(this.map.get(key)); } @Override public V put(K key, V value) { return unwrap(this.map.put(key, wrap(value))); } @Override public V putIfAbsent(K key, V value) { return unwrap(this.map.putIfAbsent(key, wrap(value))); } @Override public V remove(Object key) { return unwrap(this.map.remove(key)); } @Override public boolean remove(Object key, Object value) { throw new UnsupportedOperationException(); } @Override public V replace(K key, V value) { throw new UnsupportedOperationException(); } @Override public boolean replace(K key, V oldValue, V newValue) { throw new UnsupportedOperationException(); } @Override public int size() { return this.map.size(); } private SoftReference wrap(V value) { return new SoftReference<>(value); } private V unwrap(SoftReference value) { return (value == null ? null : value.get()); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/DiskDataStorage.java000066400000000000000000000742441461767713300272440ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.File; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.RandomAccessFile; import java.io.Serializable; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.nio.ByteBuffer; import java.nio.channels.Channels; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.HashSet; import java.util.Set; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatInterruptedException; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.DataStorage; import org.apfloat.spi.FilenameGenerator; import org.apfloat.spi.MatrixStrategy; /** * Abstract base class for disk-based data storage, containing the common * functionality independent of the element type. * * @version 1.14.0 * @author Mikko Tommila */ public abstract class DiskDataStorage extends DataStorage { private static class FileStorage implements Serializable { public FileStorage() throws ApfloatRuntimeException { init(); } private void init() throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); FilenameGenerator generator = ctx.getFilenameGenerator(); this.filename = generator.generateFilename(); this.file = new File(this.filename); try { if (!this.file.createNewFile()) { throw new BackingStorageException("Failed to create new file \"" + this.file.getAbsolutePath() + '\"'); } // Ensure file is deleted always this.file.deleteOnExit(); this.randomAccessFile = new RandomAccessFile(this.file, "rw"); } catch (IOException ioe) { throw new BackingStorageException("Unable to access file \"" + this.file.getAbsolutePath() + '\"', ioe); } this.fileChannel = this.randomAccessFile.getChannel(); referenceFileStorage(this); // To put to reference queue after garbage collection } public void setSize(long size) throws IOException, ApfloatRuntimeException { try { getRandomAccessFile().setLength(size); } catch (IOException ioe) { // Probably out of disk space - run garbage collection and process reference queue to delete unused files, then retry System.gc(); forceFreeFileStorage(); getRandomAccessFile().setLength(size); } } public void transferFrom(ReadableByteChannel in, long position, long size) throws ApfloatRuntimeException { try { if (in instanceof FileChannel) { // Optimized transferFrom() between two FileChannels while (size > 0) { long count = getFileChannel().transferFrom(in, position, size); position += count; size -= count; assert (size >= 0); } } else { // The FileChannel transferFrom() uses an 8kB buffer, which is too small and inefficient // So we use a similar mechanism but with a custom buffer size ByteBuffer buffer = getDirectByteBuffer(); while (size > 0) { buffer.clear(); int readCount = (int) Math.min(size, buffer.capacity()); buffer.limit(readCount); readCount = in.read(buffer); buffer.flip(); while (readCount > 0) { int writeCount = getFileChannel().write(buffer, position); position += writeCount; size -= writeCount; readCount -= writeCount; } assert (readCount == 0); assert (size >= 0); } } } catch (IOException ioe) { throw new BackingStorageException("Unable to write to file \"" + this.file.getAbsolutePath() + '\"', ioe); } } public void transferTo(WritableByteChannel out, long position, long size) throws ApfloatRuntimeException { try { if (out instanceof FileChannel) { // Optimized transferTo() between two FileChannels while (size > 0) { long count = getFileChannel().transferTo(position, size, out); position += count; size -= count; assert (size >= 0); } } else { // The DiskChannel transferTo() uses an 8kB buffer, which is too small and inefficient // So we use a similar mechanism but with a custom buffer size ByteBuffer buffer = getDirectByteBuffer(); while (size > 0) { buffer.clear(); int readCount = (int) Math.min(size, buffer.capacity()); buffer.limit(readCount); readCount = getFileChannel().read(buffer, position); buffer.flip(); while (readCount > 0) { int writeCount = out.write(buffer); position += writeCount; size -= writeCount; readCount -= writeCount; } assert (readCount == 0); assert (size >= 0); } } } catch (IOException ioe) { throw new BackingStorageException("Unable to read from file \"" + this.file.getAbsolutePath() + '\"', ioe); } } public File getFile() { return this.file; } public RandomAccessFile getRandomAccessFile() { return this.randomAccessFile; } public FileChannel getFileChannel() { return this.fileChannel; } // Writes the file contents to the serialization stream private void writeObject(ObjectOutputStream out) throws IOException { long size = getFileChannel().size(); out.writeLong(size); transferTo(Channels.newChannel(out), 0, size); out.defaultWriteObject(); } // Reads file contents from the serialization stream private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { init(); long size = in.readLong(); setSize(size); transferFrom(Channels.newChannel(in), 0, size); in.defaultReadObject(); } private static final long serialVersionUID = 2062430603153403341L; // These fields are not serialized automatically private transient String filename; private transient File file; private transient RandomAccessFile randomAccessFile; private transient FileChannel fileChannel; } // A PhantomReference is used so it's only queued when the Apfloat can't become accessible in any way (e.g. if it's weakly referenced) private static class FileStorageReference extends PhantomReference { public FileStorageReference(FileStorage fileStorage, ReferenceQueue queue) { super(fileStorage, queue); this.file = fileStorage.getFile(); this.randomAccessFile = fileStorage.getRandomAccessFile(); this.fileChannel = fileStorage.getFileChannel(); } public void dispose() { try { this.fileChannel.close(); } catch (IOException ioe) { // Ignore } try { this.randomAccessFile.close(); } catch (IOException ioe) { // Ignore } // If deletion fails now, at least deleteOnExit() has been called this.file.delete(); } private File file; private RandomAccessFile randomAccessFile; private FileChannel fileChannel; } /** * Default constructor. */ protected DiskDataStorage() throws ApfloatRuntimeException { this.fileStorage = createFileStorage(); } /** * Subsequence constructor. * * @param diskDataStorage The originating data storage. * @param offset The subsequence starting position. * @param length The subsequence length. */ protected DiskDataStorage(DiskDataStorage diskDataStorage, long offset, long length) { super(diskDataStorage, offset, length); this.fileStorage = diskDataStorage.fileStorage; } @Override public boolean isCached() { return false; } @Override protected void implCopyFrom(DataStorage dataStorage, long size) throws ApfloatRuntimeException { if (dataStorage == this) { setSize(size); return; } assert (size > 0); assert (!isReadOnly()); assert (!isSubsequenced()); int unitSize = getUnitSize(); long byteSize = size * unitSize; assert (byteSize > 0); try { this.fileStorage.setSize(byteSize); long readSize = Math.min(size, dataStorage.getSize()), oldSize = readSize * unitSize, padSize = byteSize - oldSize; if (dataStorage instanceof DiskDataStorage) { // Optimized disk-to-disk copy DiskDataStorage that = (DiskDataStorage) dataStorage; that.transferTo(getFileChannel().position(0), that.getOffset() * unitSize, oldSize); } else { // Un-optimized copy from arbitrary data storage long position = 0; int bufferSize = getBlockSize() / unitSize; while (readSize > 0) { int length = (int) Math.min(bufferSize, readSize); try (ArrayAccess readArrayAccess = dataStorage.getArray(READ, position, length); ArrayAccess writeArrayAccess = getArray(WRITE, position, length)) { System.arraycopy(readArrayAccess.getData(), readArrayAccess.getOffset(), writeArrayAccess.getData(), writeArrayAccess.getOffset(), length); } readSize -= length; position += length; } } pad(oldSize, padSize); } catch (IOException ioe) { throw new BackingStorageException("Unable to copy to file \"" + getFilename() + '\"', ioe); } } @Override protected long implGetSize() throws ApfloatRuntimeException { try { return getFileChannel().size() / getUnitSize(); } catch (IOException ioe) { throw new BackingStorageException("Unable to access file \"" + getFilename() + '\"', ioe); } } @Override protected void implSetSize(long size) throws ApfloatRuntimeException { assert (size > 0); assert (!isReadOnly()); assert (!isSubsequenced()); size *= getUnitSize(); assert (size > 0); try { long oldSize = getFileChannel().size(), padSize = size - oldSize; this.fileStorage.setSize(size); pad(oldSize, padSize); } catch (IOException ioe) { throw new BackingStorageException("Unable to access file \"" + getFilename() + '\"', ioe); } } @Override protected synchronized ArrayAccess implGetArray(int mode, int startColumn, int columns, int rows) throws ApfloatRuntimeException { int width = (int) (getSize() / rows); if (columns != (columns & -columns) || rows != (rows & -rows) || startColumn + columns > width) { throw new ApfloatInternalException("Invalid size"); } ArrayAccess arrayAccess = createArrayAccess(mode, startColumn, columns, rows); if ((mode & READ) != 0) { long readPosition = startColumn; int writePosition = 0; for (int i = 0; i < rows; i++) { readToArray(readPosition, arrayAccess, writePosition, columns); readPosition += width; writePosition += columns; } } return arrayAccess; } @Override protected synchronized ArrayAccess implGetTransposedArray(int mode, int startColumn, int columns, int rows) throws ApfloatRuntimeException { int width = (int) (getSize() / rows); if (columns != (columns & -columns) || rows != (rows & -rows) || startColumn + columns > width) { throw new ApfloatInternalException("Invalid size"); } int blockSize = columns * rows, b = Math.min(columns, rows); ArrayAccess arrayAccess = createTransposedArrayAccess(mode, startColumn, columns, rows); if ((mode & READ) != 0) { // Read the data from the input file in b x b blocks ApfloatContext ctx = ApfloatContext.getContext(); MatrixStrategy matrixStrategy = ctx.getBuilderFactory().getMatrixBuilder().createMatrix(); if (columns < rows) { // Taller than wide section long readPosition = startColumn; for (int i = 0; i < rows; i += b) { int writePosition = i; for (int j = 0; j < b; j++) { readToArray(readPosition, arrayAccess, writePosition, b); readPosition += width; writePosition += rows; } // Transpose the b x b block ArrayAccess subArrayAccess = arrayAccess.subsequence(i, blockSize - i); matrixStrategy.transposeSquare(subArrayAccess, b, rows); } } else { // Wider than tall section for (int i = 0; i < b; i++) { long readPosition = startColumn + i * width; int writePosition = i * b; for (int j = 0; j < columns; j += b) { readToArray(readPosition, arrayAccess, writePosition, b); readPosition += b; writePosition += b * b; } } for (int i = 0; i < blockSize; i += b * b) { // Transpose the b x b block ArrayAccess subArrayAccess = arrayAccess.subsequence(i, blockSize - i); matrixStrategy.transposeSquare(subArrayAccess, b, b); } } } return arrayAccess; } /** * Write the data back to the same location in the file that was retrieved with * {@link #implGetArray(int,int,int,int)}. * * @param arrayAccess The transposed array access. * @param startColumn The starting column where data is stored. * @param columns The number of columns of data. * @param rows The number of rows of data. * * @since 1.7.0 */ protected synchronized void setArray(ArrayAccess arrayAccess, int startColumn, int columns, int rows) throws ApfloatRuntimeException { int width = (int) (getSize() / rows); int readPosition = 0; long writePosition = startColumn; for (int i = 0; i < rows; i++) { writeFromArray(arrayAccess, readPosition, writePosition, columns); readPosition += columns; writePosition += width; } } /** * Write the data back to the same location in the file that was retrieved with * {@link #implGetTransposedArray(int,int,int,int)}. * * @param arrayAccess The transposed array access. * @param startColumn The starting column where data is stored. * @param columns The number of columns of data. * @param rows The number of rows of data. * * @since 1.7.0 */ protected synchronized void setTransposedArray(ArrayAccess arrayAccess, int startColumn, int columns, int rows) throws ApfloatRuntimeException { int width = (int) (getSize() / rows); int blockSize = arrayAccess.getLength(), b = Math.min(columns, rows); ApfloatContext ctx = ApfloatContext.getContext(); MatrixStrategy matrixStrategy = ctx.getBuilderFactory().getMatrixBuilder().createMatrix(); if (columns < rows) { // Taller than wide section long writePosition = startColumn; for (int i = 0; i < rows; i += b) { int readPosition = i; // Transpose the b x b block ArrayAccess subArrayAccess = arrayAccess.subsequence(i, blockSize - i); matrixStrategy.transposeSquare(subArrayAccess, b, rows); for (int j = 0; j < b; j++) { writeFromArray(arrayAccess, readPosition, writePosition, b); readPosition += rows; writePosition += width; } } } else { // Wider than tall section for (int i = 0; i < blockSize; i += b * b) { // Transpose the b x b block ArrayAccess subArrayAccess = arrayAccess.subsequence(i, blockSize - i); matrixStrategy.transposeSquare(subArrayAccess, b, b); } for (int i = 0; i < b; i++) { long writePosition = startColumn + i * width; int readPosition = i * b; for (int j = 0; j < columns; j += b) { writeFromArray(arrayAccess, readPosition, writePosition, b); readPosition += b * b; writePosition += b; } } } } private void readToArray(long readPosition, ArrayAccess arrayAccess, int writePosition, int length) throws ApfloatRuntimeException { try (ArrayAccess readArrayAccess = getArray(READ, readPosition, length)) { System.arraycopy(readArrayAccess.getData(), readArrayAccess.getOffset(), arrayAccess.getData(), arrayAccess.getOffset() + writePosition, length); } } private void writeFromArray(ArrayAccess arrayAccess, int readPosition, long writePosition, int length) throws ApfloatRuntimeException { try (ArrayAccess writeArrayAccess = getArray(WRITE, writePosition, length)) { System.arraycopy(arrayAccess.getData(), arrayAccess.getOffset() + readPosition, writeArrayAccess.getData(), writeArrayAccess.getOffset(), length); } } /** * Create an empty ArrayAccess. * * @param mode Whether the array is prepared for reading, writing or both. The value should be {@link #READ}, {@link #WRITE} or a combination of these. * @param startColumn The starting column where data is stored. * @param columns The number of columns of data. * @param rows The number of rows of data. * * @return Access to an empty array of the specified size and position. * * @since 1.7.0 */ protected abstract ArrayAccess createArrayAccess(int mode, int startColumn, int columns, int rows); /** * Create an empty transposed ArrayAccess. * * @param mode Whether the array is prepared for reading, writing or both. The value should be {@link #READ}, {@link #WRITE} or a combination of these. * @param startColumn The starting column where data is stored. * @param columns The number of columns of data. * @param rows The number of rows of data. * * @return Access to an empty array of the specified size and position. * * @since 1.7.0 */ protected abstract ArrayAccess createTransposedArrayAccess(int mode, int startColumn, int columns, int rows); /** * Transfer from a readable channel, possibly in multiple chunks. * * @param in Input channel. * @param position Start position of transfer. * @param size Total number of bytes to transfer. */ protected void transferFrom(ReadableByteChannel in, long position, long size) throws ApfloatRuntimeException { this.fileStorage.transferFrom(in, position, size); } /** * Transfer to a writable channel, possibly in multiple chunks. * * @param out Output channel. * @param position Start position of transfer. * @param size Total number of bytes to transfer. */ protected void transferTo(WritableByteChannel out, long position, long size) throws ApfloatRuntimeException { this.fileStorage.transferTo(out, position, size); } /** * Convenience method for getting the block size (in bytes) for the * current {@link ApfloatContext}. * * @return I/O block size, in bytes. */ protected static int getBlockSize() { ApfloatContext ctx = ApfloatContext.getContext(); return ctx.getBlockSize(); } /** * Size of the element type, in bytes. * * @return Size of the element type, in bytes. */ protected abstract int getUnitSize(); /** * Filename of the underlying disk data storage. * * @return Filename of the underlying disk data storage. */ protected final String getFilename() { return this.fileStorage.getFile().getAbsolutePath(); } /** * The FileChannel of the underlying disk file. * * @return The FileChannel of the underlying disk file. */ protected final FileChannel getFileChannel() { return this.fileStorage.getFileChannel(); } static synchronized void cleanUp() throws ApfloatRuntimeException { for (FileStorageReference reference : DiskDataStorage.references) { // Just remove everything that has been created reference.dispose(); reference.clear(); } DiskDataStorage.references.clear(); DiskDataStorage.cleanUp = true; } static synchronized void gc() throws ApfloatRuntimeException { forceFreeFileStorage(); } private void pad(long position, long size) throws IOException, ApfloatRuntimeException { transferFrom(ZERO_CHANNEL, position, size); } private static final ReadableByteChannel ZERO_CHANNEL = new ReadableByteChannel() { @Override public int read(ByteBuffer buffer) { int writeLength = buffer.remaining(); for (int i = 0; i < writeLength; i++) { buffer.put((byte) 0); } return writeLength; } @Override public void close() {} @Override public boolean isOpen() { return true; } }; private static synchronized FileStorage createFileStorage() throws ApfloatInternalException { if (DiskDataStorage.cleanUp) { throw new ApfloatInternalException("Shutdown has been initiated, clean-up is in progress"); } freeFileStorage(); // Before creating new files, delete the ones that have been garbage collected FileStorage fileStorage = new FileStorage(); return fileStorage; }; private static synchronized void referenceFileStorage(FileStorage fileStorage) throws ApfloatInternalException { if (DiskDataStorage.cleanUp) { new FileStorageReference(fileStorage, null).dispose(); // Delete the file immediately; it skipped the clean-up procedure throw new ApfloatInternalException("Shutdown has been initiated, clean-up is in progress"); } // The reference might not really be needed for anything else than queuing in the reference queue, // but we have to keep a hard reference to it to have it queued FileStorageReference reference = new FileStorageReference(fileStorage, DiskDataStorage.referenceQueue); DiskDataStorage.references.add(reference); } private static synchronized void freeFileStorage() { FileStorageReference reference; // Just check if there's anything that can be cleaned up immediately while ((reference = (FileStorageReference) DiskDataStorage.referenceQueue.poll()) != null) { reference.dispose(); reference.clear(); DiskDataStorage.references.remove(reference); } } private static synchronized void forceFreeFileStorage() throws ApfloatInternalException { try { FileStorageReference reference; // Instead of poll(), wait for some time for GC to finish; we want to free as much disk as possible e.g. if we are out of disk space so waiting some time is not that bad while ((reference = (FileStorageReference) DiskDataStorage.referenceQueue.remove(TIMEOUT)) != null) { reference.dispose(); reference.clear(); DiskDataStorage.references.remove(reference); } } catch (InterruptedException ie) { throw new ApfloatInterruptedException("Reference queue polling was interrupted", ie); } } private static ByteBuffer getDirectByteBuffer() { // Since direct buffers are allocated outside of the heap they can behave strangely in relation to GC // So we try to make them as long-lived as possible and cache them in a ThreadLocal ByteBuffer buffer = null; int blockSize = getBlockSize(); SoftReference reference = DiskDataStorage.threadLocal.get(); if (reference != null) { buffer = reference.get(); if (buffer != null && buffer.capacity() != blockSize) { // Clear references to the direct buffer so it may be GC'd reference.clear(); buffer = null; } } if (buffer == null) { buffer = ByteBuffer.allocateDirect(blockSize); reference = new SoftReference<>(buffer); DiskDataStorage.threadLocal.set(reference); } return buffer; } private static final long serialVersionUID = 741984828408146034L; private static final long TIMEOUT = 1000; // Reference queue waiting timeout when forcing deleting garbage collected files private static ReferenceQueue referenceQueue = new ReferenceQueue<>(); private static Set references = new HashSet<>(); private static ThreadLocal> threadLocal = new ThreadLocal<>(); private static boolean cleanUp = false; private FileStorage fileStorage; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/DoubleBaseMath.java000066400000000000000000000240561461767713300270460ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.Serializable; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import static org.apfloat.internal.DoubleRadixConstants.*; /** * Mathematical operations on numbers in a base. * Implementation for the double type. * * @version 1.8.2 * @author Mikko Tommila */ public class DoubleBaseMath implements Serializable { /** * Creates a base math using the specified radix. * * @param radix The radix that will be used. */ public DoubleBaseMath(int radix) { this.radix = radix; this.inverseBase = 1.0 / BASE[radix]; } /** * Addition in some base. Adds the data words * of src1 and src2 and stores the result to * dst. src2 may be null, in * which case it is ignored (only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] + src2[i]. * * @param src1 First source data sequence. Can be null, in which case it's ignored. * @param src2 Second source data sequence. Can be null, in which case it's ignored. * @param carry Input carry bit. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the addition of the last (leftmost) word in the accessed sequence. */ public double baseAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, double carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); boolean sameDst = (src1 == dst || src2 == dst); double base = BASE[this.radix]; for (long i = 0; i < size; i++) { double result = (src1 == null ? 0 : src1.getDouble()) + carry + (src2 == null ? 0 : src2.getDouble()); carry = (result >= base ? 1 : 0); result -= (result >= base ? base : 0); dst.setDouble(result); if (src1 != null) src1.next(); if (src2 != null) src2.next(); if (!sameDst) dst.next(); } return carry; } /** * Subtraction in some base. Subtracts the data words * of src1 and src2 and stores the result to * dst. src1 and src2 may be * null, in which case they are ignored (the values are assumed * to be zero and only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] - src2[i]. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param carry Input carry bit. This is subtracted from the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the subtraction of the last (leftmost) word in the accessed sequence. The value is 1 if the carry is set, and 0 otherwise. */ public double baseSubtract(DataStorage.Iterator src1, DataStorage.Iterator src2, double carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); assert (src2 != dst); double base = BASE[this.radix]; for (long i = 0; i < size; i++) { double result = (src1 == null ? 0 : src1.getDouble()) - carry - (src2 == null ? 0 : src2.getDouble()); carry = (result < 0 ? 1 : 0); result += (result < 0 ? base : 0); dst.setDouble(result); if (src1 != null && src1 != dst) src1.next(); if (src2 != null) src2.next(); dst.next(); } return carry; } /** * Multiplication and addition in some base. Multiplies the data words * of src1 by src3 and adds the result to the * words in src2, and stores the result to dst. * src2 may be null, in which case it is ignored * (the values are assumed to be zero).

* * Assumes that the result from the addition doesn't overflow the upper * result word (to larger than the base). This is the case e.g. when using * this method to perform an arbitrary precision multiplication.

* * Essentially calculates dst[i] = src1[i] * src3 + src2[i]. * * @param src1 First source data sequence. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param src3 Multiplicand. All elements of src1 are multiplied by this value. * @param carry Input carry word. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry word. Propagated carry word from the multiplication and addition of the last (leftmost) word in the accessed sequence. */ public double baseMultiplyAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, double src3, double carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != src2); assert (src1 != dst); double base = BASE[this.radix]; for (long i = 0; i < size; i++) { double a = src1.getDouble(), b = src3; carry += (src2 == null ? 0 : src2.getDouble()); long tmp = (long) a * (long) b + (long) carry; carry = (double) (long) ((a * b + carry) * this.inverseBase); double result = (double) (tmp - (long) carry * (long) base); carry += (result >= base ? 1 : 0); result -= (result >= base ? base : 0); carry -= (result < 0 ? 1 : 0); result += (result < 0 ? base : 0); dst.setDouble(result); // = a * b % base src1.next(); if (src2 != null && src2 != dst) src2.next(); dst.next(); } return carry; } /** * Division in some base. Divides the data words * of src1 by src2 and stores the result to * dst. src1 may be null, * in which case it is ignored (the values are assumed to be * zero and only the carry division is propagated).

* * Essentially calculates dst[i] = src1[i] / src2. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Divisor. All elements of src1 are divided by this value. * @param carry Input carry word. Used as the upper word for the division of the first input element. This should be the remainder word returned from the previous block processed. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Remainder word of the propagated division of the last (rightmost) word in the accessed sequence. */ public double baseDivide(DataStorage.Iterator src1, double src2, double carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != dst); double base = BASE[this.radix], inverseDivisor = 1.0 / src2; for (long i = 0; i < size; i++) { double a = (src1 == null ? 0 : src1.getDouble()); long tmp = (long) carry * (long) base + (long) a; double result = (double) (long) ((carry * base + a) * inverseDivisor); carry = (double) (tmp - (long) result * (long) src2); result += (carry >= src2 ? 1 : 0); carry -= (carry >= src2 ? src2 : 0); result -= (carry < 0 ? 1 : 0); carry += (carry < 0 ? src2 : 0); dst.setDouble(result); // = carry * base % src2 if (src1 != null) src1.next(); dst.next(); } return carry; } private static final long serialVersionUID = 4560898425815362356L; private int radix; private double inverseBase; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/DoubleCRTMath.java000066400000000000000000000160521461767713300266210ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import static org.apfloat.internal.DoubleModConstants.*; import static org.apfloat.internal.DoubleRadixConstants.*; /** * Basic arithmetic for calculating the Chinese Remainder * Theorem. Works for the double type. * * @version 1.6 * @author Mikko Tommila */ public class DoubleCRTMath extends DoubleBaseMath { /** * Creates a carry-CRT math using the specified radix. * * @param radix The radix that will be used. */ public DoubleCRTMath(int radix) { super(radix); this.base = (long) BASE[radix]; this.inverseBase = 1.0 / BASE[radix]; } /** * Multiplies two words by one word to produce a result of three words. * Most significant word is stored first. * * @param src Source array, first multiplicand. * @param factor Second multiplicand. * @param dst Destination array. */ public final void multiply(double[] src, double factor, double[] dst) { long tmp = (long) src[1] * (long) factor, carry = (long) ((src[1] * factor + (double) (tmp & 0x8000000000000000L)) * INVERSE_2_64); carry = (carry << 64 - MAX_POWER_OF_TWO_BITS) | (tmp >>> MAX_POWER_OF_TWO_BITS); dst[2] = (double) (tmp & BASE_MASK); // = tmp % MAX_POWER_OF_TWO_BASE tmp = (long) src[0] * (long) factor + carry; carry = (long) ((src[0] * factor + (double) carry + (double) (tmp & 0x8000000000000000L)) * INVERSE_2_64); carry = (carry << 64 - MAX_POWER_OF_TWO_BITS) | (tmp >>> MAX_POWER_OF_TWO_BITS); dst[1] = (double) (tmp & BASE_MASK); // = tmp % MAX_POWER_OF_TWO_BASE dst[0] = (double) carry; } /** * Compares three words. Most significant word is stored first. * * @param src1 First operand. * @param src2 Second operand. * * @return Less than zero if src1 < src2, greater than zero if src1 > src2 and zero if src1 == src2. */ public final double compare(double[] src1, double[] src2) { double result = src1[0] - src2[0]; if (result != 0) { return result; } result = src1[1] - src2[1]; if (result != 0) { return result; } return src1[2] - src2[2]; } /** * Adds three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. * * @return Overflow carry bit. */ public final double add(double[] src, double[] srcDst) { double result = srcDst[2] + src[2], carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[2] = result; result = srcDst[1] + src[1] + carry; carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[1] = result; result = srcDst[0] + src[0] + carry; carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[0] = result; return carry; } /** * Subtracts three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. */ public final void subtract(double[] src, double[] srcDst) { double result = srcDst[2] - src[2], carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[2] = result; result = srcDst[1] - src[1] - carry; carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[1] = result; result = srcDst[0] - src[0] - carry; // carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[0] = result; } /** * Divides three words by the base to produce two words. Most significant word is stored first. * * @param srcDst Source and destination of the operation. * * @return Remainder of the division. */ public final double divide(double[] srcDst) { long tmp = ((long) srcDst[0] << MAX_POWER_OF_TWO_BITS) + (long) srcDst[1], result = (long) ((srcDst[0] * MAX_POWER_OF_TWO_BASE + srcDst[1]) * this.inverseBase), carry = tmp - result * this.base; // = tmp % divisor if (carry >= this.base) { carry -= this.base; result++; } if (carry < 0) { carry += this.base; result--; } srcDst[0] = 0; srcDst[1] = (double) result; tmp = (carry << MAX_POWER_OF_TWO_BITS) + (long) srcDst[2]; result = (long) (((double) carry * MAX_POWER_OF_TWO_BASE + srcDst[2]) * this.inverseBase); carry = tmp - result * this.base; // = tmp % divisor if (carry >= this.base) { carry -= this.base; result++; } if (carry < 0) { carry += this.base; result--; } srcDst[2] = (double) result; return (double) carry; } private static final long serialVersionUID = -8414531999881223922L; private static final long BASE_MASK = (1L << MAX_POWER_OF_TWO_BITS) - 1; private static final double INVERSE_2_64 = 1.0 / 18446744073709551616.0; private long base; private double inverseBase; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/DoubleConstants.java000066400000000000000000000031531461767713300273310ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants needed for various algorithms for the double type. * * @since 1.4 * @version 1.4 * @author Mikko Tommila */ public interface DoubleConstants { /** * Relative cost of Karatsuba multiplication. */ public static final float KARATSUBA_COST_FACTOR = 4.3f; /** * Relative cost of NTT multiplication. */ public static final float NTT_COST_FACTOR = 6.2f; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/DoubleElementaryModMath.java000066400000000000000000000127511461767713300307400ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Elementary modulo arithmetic functions for double data. * Note that although a floating-point data type is used, the data * will always be integers.

* * Modular addition and subtraction are trivial, when the modulus is less * than 252 and overflow can be detected easily.

* * Modular multiplication is more complicated, and since it is usually * the single most time consuming operation in the whole program execution, * the very core of the Number Theoretic Transform (NTT), it should be * carefully optimized.

* * The algorithm for multiplying two doubles containing an * integer and taking the remainder is not entirely obvious. The basic problem * is to get the full 104-bit result of multiplying two 52-bit integers. * This can basically be done in two parts: by multiplying two * longs, the lowest 64 bits can be acquired easily. Multiplying * the doubles as floating-point numbers and scaling properly, the * highest (roughly) 52 bits of the result can be acquired.

* * The first observation is that since the modulus is practically * constant, it should be more efficient to calculate (once) the inverse * of the modulus, and then subsequently multiply by the inverse of the * modulus instead of dividing by it.

* * The second observation is that to get the remainder of the division, * we don't necessarily need the actual result of the division (we just * want the remainder). So, we should discard the topmost 52 bits of the * full 104-bit result whenever possible, to save a few operations.

* * The basic approach is to get an approximation of a * b / modulus * (using floating-point operands, that is doubles). The approximation * should be within +1 or -1 of the correct result. Then calculate * a * b - approximateDivision * modulus to get the remainder. * This calculation must use the lowest 52 (or more, actually 64) bits * and is done using longs. As the modulus is less than 252 * it is easy to detect the case when the approximate division was off by one (and * the remainder is ±modulus off).

* * To ensure that only one comparison is needed in the check for the approximate * division, we use 1 / (modulus + 0.5) as the inverse modulus. In * this case the result of the approximate division is always either correct or * 1 less. * * @version 1.0 * @author Mikko Tommila */ public class DoubleElementaryModMath { /** * Default constructor. */ public DoubleElementaryModMath() { } /** * Modular multiplication. * * @param a First operand. * @param b Second operand. * * @return a * b % modulus */ public final double modMultiply(double a, double b) { double r = (double) ((long) a * (long) b - this.longModulus * (long) (a * b * this.inverseModulus)); return (r >= this.modulus ? r - this.modulus : r); } /** * Modular addition. * * @param a First operand. * @param b Second operand. * * @return (a + b) % modulus */ public final double modAdd(double a, double b) { double r = a + b; return (r >= this.modulus ? r - this.modulus : r); } /** * Modular subtraction. The result is always >= 0. * * @param a First operand. * @param b Second operand. * * @return (a - b + modulus) % modulus */ public final double modSubtract(double a, double b) { double r = a - b; return (r < 0.0 ? r + this.modulus : r); } /** * Get the modulus. * * @return The modulus. */ public final double getModulus() { return this.modulus; } /** * Set the modulus. * * @param modulus The modulus. */ public final void setModulus(double modulus) { this.inverseModulus = 1.0 / (modulus + 0.5); // Round down this.longModulus = (long) modulus; this.modulus = modulus; } private long longModulus; private double modulus; private double inverseModulus; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/DoubleModConstants.java000066400000000000000000000043411461767713300277710ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants needed for various modular arithmetic operations for the double type. * * @version 1.0 * @author Mikko Tommila */ public interface DoubleModConstants { /** * Moduli to be used in number theoretic transforms. * Allows transform lengths upto 3*243. */ public static final double MODULUS[] = { 1952732650930177.0, 1899956092796929.0, 1636073302130689.0 }; /** * Primitive roots for the corresponding moduli. */ public static final double PRIMITIVE_ROOT[] = { 5.0, 7.0, 17.0 }; /** * Maximum transform length for the moduli. */ public static final long MAX_TRANSFORM_LENGTH = 26388279066624L; /** * Maximum bits in a power-of-two base that fits in a double. */ public static final int MAX_POWER_OF_TWO_BITS = 51; /** * Maximum power-of-two base that fits in a double. */ public static final double MAX_POWER_OF_TWO_BASE = (double) (1L << MAX_POWER_OF_TWO_BITS); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/DoubleRadixConstants.java000066400000000000000000000324521461767713300303250ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants related to different radixes for the double data type. * * @version 1.0 * @author Mikko Tommila */ public interface DoubleRadixConstants { /** * Bases for radixes 2, ..., 36. The base is the radix to the maximum power * so that the base is less than all moduli used. */ public static final double BASE[] = { (double) -1L, (double) -1L, (double) 1125899906842624L, (double) 617673396283947L, (double) 1125899906842624L, (double) 476837158203125L, (double) 609359740010496L, (double) 1628413597910449L, (double) 281474976710656L, (double) 205891132094649L, (double) 1000000000000000L, (double) 379749833583241L, (double) 1283918464548864L, (double) 302875106592253L, (double) 793714773254144L, (double) 129746337890625L, (double) 281474976710656L, (double) 582622237229761L, (double) 1156831381426176L, (double) 116490258898219L, (double) 204800000000000L, (double) 350277500542221L, (double) 584318301411328L, (double) 952809757913927L, (double) 1521681143169024L, (double) 95367431640625L, (double) 141167095653376L, (double) 205891132094649L, (double) 296196766695424L, (double) 420707233300201L, (double) 590490000000000L, (double) 819628286980801L, (double) 1125899906842624L, (double) 1531578985264449L, (double) 60716992766464L, (double) 78815638671875L, (double) 101559956668416L }; /** * The power of the radix in each base. */ public static final int BASE_DIGITS[] = { -1, -1, 50, 31, 25, 21, 19, 18, 16, 15, 15, 14, 14, 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9 }; /** * The minimum number in each radix to have the specified amount of digits. */ public static final double MINIMUM_FOR_DIGITS[][] = { null, null, { (double) 1L, (double) 2L, (double) 4L, (double) 8L, (double) 16L, (double) 32L, (double) 64L, (double) 128L, (double) 256L, (double) 512L, (double) 1024L, (double) 2048L, (double) 4096L, (double) 8192L, (double) 16384L, (double) 32768L, (double) 65536L, (double) 131072L, (double) 262144L, (double) 524288L, (double) 1048576L, (double) 2097152L, (double) 4194304L, (double) 8388608L, (double) 16777216L, (double) 33554432L, (double) 67108864L, (double) 134217728L, (double) 268435456L, (double) 536870912L, (double) 1073741824L, (double) 2147483648L, (double) 4294967296L, (double) 8589934592L, (double) 17179869184L, (double) 34359738368L, (double) 68719476736L, (double) 137438953472L, (double) 274877906944L, (double) 549755813888L, (double) 1099511627776L, (double) 2199023255552L, (double) 4398046511104L, (double) 8796093022208L, (double) 17592186044416L, (double) 35184372088832L, (double) 70368744177664L, (double) 140737488355328L, (double) 281474976710656L, (double) 562949953421312L }, { (double) 1L, (double) 3L, (double) 9L, (double) 27L, (double) 81L, (double) 243L, (double) 729L, (double) 2187L, (double) 6561L, (double) 19683L, (double) 59049L, (double) 177147L, (double) 531441L, (double) 1594323L, (double) 4782969L, (double) 14348907L, (double) 43046721L, (double) 129140163L, (double) 387420489L, (double) 1162261467L, (double) 3486784401L, (double) 10460353203L, (double) 31381059609L, (double) 94143178827L, (double) 282429536481L, (double) 847288609443L, (double) 2541865828329L, (double) 7625597484987L, (double) 22876792454961L, (double) 68630377364883L, (double) 205891132094649L }, { (double) 1L, (double) 4L, (double) 16L, (double) 64L, (double) 256L, (double) 1024L, (double) 4096L, (double) 16384L, (double) 65536L, (double) 262144L, (double) 1048576L, (double) 4194304L, (double) 16777216L, (double) 67108864L, (double) 268435456L, (double) 1073741824L, (double) 4294967296L, (double) 17179869184L, (double) 68719476736L, (double) 274877906944L, (double) 1099511627776L, (double) 4398046511104L, (double) 17592186044416L, (double) 70368744177664L, (double) 281474976710656L }, { (double) 1L, (double) 5L, (double) 25L, (double) 125L, (double) 625L, (double) 3125L, (double) 15625L, (double) 78125L, (double) 390625L, (double) 1953125L, (double) 9765625L, (double) 48828125L, (double) 244140625L, (double) 1220703125L, (double) 6103515625L, (double) 30517578125L, (double) 152587890625L, (double) 762939453125L, (double) 3814697265625L, (double) 19073486328125L, (double) 95367431640625L }, { (double) 1L, (double) 6L, (double) 36L, (double) 216L, (double) 1296L, (double) 7776L, (double) 46656L, (double) 279936L, (double) 1679616L, (double) 10077696L, (double) 60466176L, (double) 362797056L, (double) 2176782336L, (double) 13060694016L, (double) 78364164096L, (double) 470184984576L, (double) 2821109907456L, (double) 16926659444736L, (double) 101559956668416L }, { (double) 1L, (double) 7L, (double) 49L, (double) 343L, (double) 2401L, (double) 16807L, (double) 117649L, (double) 823543L, (double) 5764801L, (double) 40353607L, (double) 282475249L, (double) 1977326743L, (double) 13841287201L, (double) 96889010407L, (double) 678223072849L, (double) 4747561509943L, (double) 33232930569601L, (double) 232630513987207L }, { (double) 1L, (double) 8L, (double) 64L, (double) 512L, (double) 4096L, (double) 32768L, (double) 262144L, (double) 2097152L, (double) 16777216L, (double) 134217728L, (double) 1073741824L, (double) 8589934592L, (double) 68719476736L, (double) 549755813888L, (double) 4398046511104L, (double) 35184372088832L }, { (double) 1L, (double) 9L, (double) 81L, (double) 729L, (double) 6561L, (double) 59049L, (double) 531441L, (double) 4782969L, (double) 43046721L, (double) 387420489L, (double) 3486784401L, (double) 31381059609L, (double) 282429536481L, (double) 2541865828329L, (double) 22876792454961L }, { (double) 1L, (double) 10L, (double) 100L, (double) 1000L, (double) 10000L, (double) 100000L, (double) 1000000L, (double) 10000000L, (double) 100000000L, (double) 1000000000L, (double) 10000000000L, (double) 100000000000L, (double) 1000000000000L, (double) 10000000000000L, (double) 100000000000000L }, { (double) 1L, (double) 11L, (double) 121L, (double) 1331L, (double) 14641L, (double) 161051L, (double) 1771561L, (double) 19487171L, (double) 214358881L, (double) 2357947691L, (double) 25937424601L, (double) 285311670611L, (double) 3138428376721L, (double) 34522712143931L }, { (double) 1L, (double) 12L, (double) 144L, (double) 1728L, (double) 20736L, (double) 248832L, (double) 2985984L, (double) 35831808L, (double) 429981696L, (double) 5159780352L, (double) 61917364224L, (double) 743008370688L, (double) 8916100448256L, (double) 106993205379072L }, { (double) 1L, (double) 13L, (double) 169L, (double) 2197L, (double) 28561L, (double) 371293L, (double) 4826809L, (double) 62748517L, (double) 815730721L, (double) 10604499373L, (double) 137858491849L, (double) 1792160394037L, (double) 23298085122481L }, { (double) 1L, (double) 14L, (double) 196L, (double) 2744L, (double) 38416L, (double) 537824L, (double) 7529536L, (double) 105413504L, (double) 1475789056L, (double) 20661046784L, (double) 289254654976L, (double) 4049565169664L, (double) 56693912375296L }, { (double) 1L, (double) 15L, (double) 225L, (double) 3375L, (double) 50625L, (double) 759375L, (double) 11390625L, (double) 170859375L, (double) 2562890625L, (double) 38443359375L, (double) 576650390625L, (double) 8649755859375L }, { (double) 1L, (double) 16L, (double) 256L, (double) 4096L, (double) 65536L, (double) 1048576L, (double) 16777216L, (double) 268435456L, (double) 4294967296L, (double) 68719476736L, (double) 1099511627776L, (double) 17592186044416L }, { (double) 1L, (double) 17L, (double) 289L, (double) 4913L, (double) 83521L, (double) 1419857L, (double) 24137569L, (double) 410338673L, (double) 6975757441L, (double) 118587876497L, (double) 2015993900449L, (double) 34271896307633L }, { (double) 1L, (double) 18L, (double) 324L, (double) 5832L, (double) 104976L, (double) 1889568L, (double) 34012224L, (double) 612220032L, (double) 11019960576L, (double) 198359290368L, (double) 3570467226624L, (double) 64268410079232L }, { (double) 1L, (double) 19L, (double) 361L, (double) 6859L, (double) 130321L, (double) 2476099L, (double) 47045881L, (double) 893871739L, (double) 16983563041L, (double) 322687697779L, (double) 6131066257801L }, { (double) 1L, (double) 20L, (double) 400L, (double) 8000L, (double) 160000L, (double) 3200000L, (double) 64000000L, (double) 1280000000L, (double) 25600000000L, (double) 512000000000L, (double) 10240000000000L }, { (double) 1L, (double) 21L, (double) 441L, (double) 9261L, (double) 194481L, (double) 4084101L, (double) 85766121L, (double) 1801088541L, (double) 37822859361L, (double) 794280046581L, (double) 16679880978201L }, { (double) 1L, (double) 22L, (double) 484L, (double) 10648L, (double) 234256L, (double) 5153632L, (double) 113379904L, (double) 2494357888L, (double) 54875873536L, (double) 1207269217792L, (double) 26559922791424L }, { (double) 1L, (double) 23L, (double) 529L, (double) 12167L, (double) 279841L, (double) 6436343L, (double) 148035889L, (double) 3404825447L, (double) 78310985281L, (double) 1801152661463L, (double) 41426511213649L }, { (double) 1L, (double) 24L, (double) 576L, (double) 13824L, (double) 331776L, (double) 7962624L, (double) 191102976L, (double) 4586471424L, (double) 110075314176L, (double) 2641807540224L, (double) 63403380965376L }, { (double) 1L, (double) 25L, (double) 625L, (double) 15625L, (double) 390625L, (double) 9765625L, (double) 244140625L, (double) 6103515625L, (double) 152587890625L, (double) 3814697265625L }, { (double) 1L, (double) 26L, (double) 676L, (double) 17576L, (double) 456976L, (double) 11881376L, (double) 308915776L, (double) 8031810176L, (double) 208827064576L, (double) 5429503678976L }, { (double) 1L, (double) 27L, (double) 729L, (double) 19683L, (double) 531441L, (double) 14348907L, (double) 387420489L, (double) 10460353203L, (double) 282429536481L, (double) 7625597484987L }, { (double) 1L, (double) 28L, (double) 784L, (double) 21952L, (double) 614656L, (double) 17210368L, (double) 481890304L, (double) 13492928512L, (double) 377801998336L, (double) 10578455953408L }, { (double) 1L, (double) 29L, (double) 841L, (double) 24389L, (double) 707281L, (double) 20511149L, (double) 594823321L, (double) 17249876309L, (double) 500246412961L, (double) 14507145975869L }, { (double) 1L, (double) 30L, (double) 900L, (double) 27000L, (double) 810000L, (double) 24300000L, (double) 729000000L, (double) 21870000000L, (double) 656100000000L, (double) 19683000000000L }, { (double) 1L, (double) 31L, (double) 961L, (double) 29791L, (double) 923521L, (double) 28629151L, (double) 887503681L, (double) 27512614111L, (double) 852891037441L, (double) 26439622160671L }, { (double) 1L, (double) 32L, (double) 1024L, (double) 32768L, (double) 1048576L, (double) 33554432L, (double) 1073741824L, (double) 34359738368L, (double) 1099511627776L, (double) 35184372088832L }, { (double) 1L, (double) 33L, (double) 1089L, (double) 35937L, (double) 1185921L, (double) 39135393L, (double) 1291467969L, (double) 42618442977L, (double) 1406408618241L, (double) 46411484401953L }, { (double) 1L, (double) 34L, (double) 1156L, (double) 39304L, (double) 1336336L, (double) 45435424L, (double) 1544804416L, (double) 52523350144L, (double) 1785793904896L }, { (double) 1L, (double) 35L, (double) 1225L, (double) 42875L, (double) 1500625L, (double) 52521875L, (double) 1838265625L, (double) 64339296875L, (double) 2251875390625L }, { (double) 1L, (double) 36L, (double) 1296L, (double) 46656L, (double) 1679616L, (double) 60466176L, (double) 2176782336L, (double) 78364164096L, (double) 2821109907456L } }; /** * Maximum allowed exponent for each radix. */ public static final long MAX_EXPONENT[] = { -1L, -1L, 184467440737095510L, 297528130221121794L, 368934881474191026L, 439208192231179794L, 485440633518672404L, 512409557603043094L, 576460752303423481L, 614891469123651714L, 614891469123651714L, 658812288346769694L, 658812288346769694L, 709490156681136594L, 709490156681136594L, 768614336404564644L, 768614336404564644L, 768614336404564644L, 768614336404564644L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 922337203685477574L, 922337203685477574L, 922337203685477574L, 922337203685477574L, 922337203685477574L, 922337203685477574L, 922337203685477574L, 922337203685477574L, 922337203685477574L, 1024819115206086194L, 1024819115206086194L, 1024819115206086194L }; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/Factor3NTTStrategy.java000066400000000000000000000135721461767713300276420ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.NTTStrategy; import org.apfloat.spi.Factor3NTTStepStrategy; import org.apfloat.spi.DataStorage; import org.apfloat.spi.Util; /** * A transform that implements a 3-point transform on * top of another Number Theoretic Transform that does * transforms of length 2n. * * @see Factor3NTTStepStrategy * * @since 1.7.0 * @version 1.8.3 * @author Mikko Tommila */ public class Factor3NTTStrategy implements NTTStrategy, Parallelizable { /** * Creates a new factor-3 transform strategy on top of an existing transform. * The underlying transform needs to be capable of only doing transforms of * length 2n. * * @param factor2Strategy The underlying transformation strategy, that can be capable of only doing radix-2 transforms. */ public Factor3NTTStrategy(NTTStrategy factor2Strategy) { this.factor2Strategy = factor2Strategy; ApfloatContext ctx = ApfloatContext.getContext(); this.stepStrategy = ctx.getBuilderFactory().getNTTBuilder().createFactor3NTTSteps(); } @Override public void transform(DataStorage dataStorage, int modulus) throws ApfloatRuntimeException { long length = dataStorage.getSize(), power2length = (length & -length); if (length > this.stepStrategy.getMaxTransformLength()) { throw new TransformLengthExceededException("Maximum transform length exceeded: " + length + " > " + this.stepStrategy.getMaxTransformLength()); } if (length == power2length) { // Transform length is a power of two this.factor2Strategy.transform(dataStorage, modulus); } else { // Transform length is three times a power of two assert (length == 3 * power2length); DataStorage dataStorage0 = dataStorage.subsequence(0, power2length), dataStorage1 = dataStorage.subsequence(power2length, power2length), dataStorage2 = dataStorage.subsequence(2 * power2length, power2length); // Transform the columns this.stepStrategy.transformColumns(dataStorage0, dataStorage1, dataStorage2, 0, power2length, power2length, length, false, modulus); // Transform the rows this.factor2Strategy.transform(dataStorage0, modulus); this.factor2Strategy.transform(dataStorage1, modulus); this.factor2Strategy.transform(dataStorage2, modulus); } } @Override public void inverseTransform(DataStorage dataStorage, int modulus, long totalTransformLength) throws ApfloatRuntimeException { long length = dataStorage.getSize(), power2length = (length & -length); if (Math.max(length, totalTransformLength) > this.stepStrategy.getMaxTransformLength()) { throw new TransformLengthExceededException("Maximum transform length exceeded: " + Math.max(length, totalTransformLength) + " > " + this.stepStrategy.getMaxTransformLength()); } if (length == power2length) { // Transform length is a power of two this.factor2Strategy.inverseTransform(dataStorage, modulus, totalTransformLength); } else { // Transform length is three times a power of two assert (length == 3 * power2length); DataStorage dataStorage0 = dataStorage.subsequence(0, power2length), dataStorage1 = dataStorage.subsequence(power2length, power2length), dataStorage2 = dataStorage.subsequence(2 * power2length, power2length); // Transform the rows this.factor2Strategy.inverseTransform(dataStorage0, modulus, totalTransformLength); this.factor2Strategy.inverseTransform(dataStorage1, modulus, totalTransformLength); this.factor2Strategy.inverseTransform(dataStorage2, modulus, totalTransformLength); // Transform the columns this.stepStrategy.transformColumns(dataStorage0, dataStorage1, dataStorage2, 0, power2length, power2length, length, true, modulus); } } @Override public long getTransformLength(long size) { // Calculates the needed transform length, that is // a power of two, or three times a power of two return Util.round23up(size); } /** * The factor-3 NTT steps. */ protected Factor3NTTStepStrategy stepStrategy; private NTTStrategy factor2Strategy; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/FloatBaseMath.java000066400000000000000000000226601461767713300267000ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.Serializable; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import static org.apfloat.internal.FloatRadixConstants.*; /** * Mathematical operations on numbers in a base. * Implementation for the float type. * * @version 1.8.2 * @author Mikko Tommila */ public class FloatBaseMath implements Serializable { /** * Creates a base math using the specified radix. * * @param radix The radix that will be used. */ public FloatBaseMath(int radix) { this.radix = radix; } /** * Addition in some base. Adds the data words * of src1 and src2 and stores the result to * dst. src2 may be null, in * which case it is ignored (only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] + src2[i]. * * @param src1 First source data sequence. Can be null, in which case it's ignored. * @param src2 Second source data sequence. Can be null, in which case it's ignored. * @param carry Input carry bit. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the addition of the last (leftmost) word in the accessed sequence. */ public float baseAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, float carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); boolean sameDst = (src1 == dst || src2 == dst); float base = BASE[this.radix]; for (long i = 0; i < size; i++) { double result = (double) (src1 == null ? 0 : src1.getFloat()) + (double) carry + (double) (src2 == null ? 0 : src2.getFloat()); carry = (result >= base ? 1 : 0); result -= (result >= base ? base : 0); dst.setFloat((float) result); if (src1 != null) src1.next(); if (src2 != null) src2.next(); if (!sameDst) dst.next(); } return carry; } /** * Subtraction in some base. Subtracts the data words * of src1 and src2 and stores the result to * dst. src1 and src2 may be * null, in which case they are ignored (the values are assumed * to be zero and only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] - src2[i]. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param carry Input carry bit. This is subtracted from the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the subtraction of the last (leftmost) word in the accessed sequence. The value is 1 if the carry is set, and 0 otherwise. */ public float baseSubtract(DataStorage.Iterator src1, DataStorage.Iterator src2, float carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); assert (src2 != dst); float base = BASE[this.radix]; for (long i = 0; i < size; i++) { float result = (src1 == null ? 0 : src1.getFloat()) - carry - (src2 == null ? 0 : src2.getFloat()); carry = (result < 0 ? 1 : 0); result += (result < 0 ? base : 0); dst.setFloat(result); if (src1 != null && src1 != dst) src1.next(); if (src2 != null) src2.next(); dst.next(); } return carry; } /** * Multiplication and addition in some base. Multiplies the data words * of src1 by src3 and adds the result to the * words in src2, and stores the result to dst. * src2 may be null, in which case it is ignored * (the values are assumed to be zero).

* * Assumes that the result from the addition doesn't overflow the upper * result word (to larger than the base). This is the case e.g. when using * this method to perform an arbitrary precision multiplication.

* * Essentially calculates dst[i] = src1[i] * src3 + src2[i]. * * @param src1 First source data sequence. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param src3 Multiplicand. All elements of src1 are multiplied by this value. * @param carry Input carry word. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry word. Propagated carry word from the multiplication and addition of the last (leftmost) word in the accessed sequence. */ public float baseMultiplyAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, float src3, float carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != src2); assert (src1 != dst); double base = BASE[this.radix]; for (long i = 0; i < size; i++) { double tmp = (double) src1.getFloat() * (double) src3 + (double) (src2 == null ? 0 : src2.getFloat()) + (double) carry; carry = (float) (int) (tmp / base); dst.setFloat((float) (tmp - (double) carry * base)); // = tmp % base src1.next(); if (src2 != null && src2 != dst) src2.next(); dst.next(); } return carry; } /** * Division in some base. Divides the data words * of src1 by src2 and stores the result to * dst. src1 may be null, * in which case it is ignored (the values are assumed to be * zero and only the carry division is propagated).

* * Essentially calculates dst[i] = src1[i] / src2. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Divisor. All elements of src1 are divided by this value. * @param carry Input carry word. Used as the upper word for the division of the first input element. This should be the remainder word returned from the previous block processed. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Remainder word of the propagated division of the last (rightmost) word in the accessed sequence. */ public float baseDivide(DataStorage.Iterator src1, float src2, float carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != dst); double base = BASE[this.radix], divisor = src2; for (long i = 0; i < size; i++) { double tmp = (double) carry * base + (double) (src1 == null ? 0 : src1.getFloat()); float result = (float) (int) (tmp / divisor); carry = (float) (tmp - (double) result * divisor); // = tmp % src2 dst.setFloat(result); if (src1 != null) src1.next(); dst.next(); } return carry; } private static final long serialVersionUID = -2321698097908304307L; private int radix; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/FloatCRTMath.java000066400000000000000000000143401461767713300264520ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import static org.apfloat.internal.FloatModConstants.*; import static org.apfloat.internal.FloatRadixConstants.*; /** * Basic arithmetic for calculating the Chinese Remainder * Theorem. Works for the float type. * * @version 1.6 * @author Mikko Tommila */ public class FloatCRTMath extends FloatBaseMath { /** * Creates a carry-CRT math using the specified radix. * * @param radix The radix that will be used. */ public FloatCRTMath(int radix) { super(radix); this.base = BASE[radix]; } /** * Multiplies two words by one word to produce a result of three words. * Most significant word is stored first. * * @param src Source array, first multiplicand. * @param factor Second multiplicand. * @param dst Destination array. */ public final void multiply(float[] src, float factor, float[] dst) { double tmp = (double) src[1] * (double) factor; float carry = (float) (int) (tmp * INVERSE_MAX_POWER_OF_TWO_BASE); dst[2] = (float) (tmp - carry * MAX_POWER_OF_TWO_BASE); // = tmp % MAX_POWER_OF_TWO_BASE tmp = (double) src[0] * (double) factor + carry; carry = (float) (int) (tmp * INVERSE_MAX_POWER_OF_TWO_BASE); dst[1] = (float) (tmp - carry * MAX_POWER_OF_TWO_BASE); // = tmp % MAX_POWER_OF_TWO_BASE dst[0] = carry; } /** * Compares three words. Most significant word is stored first. * * @param src1 First operand. * @param src2 Second operand. * * @return Less than zero if src1 < src2, greater than zero if src1 > src2 and zero if src1 == src2. */ public final float compare(float[] src1, float[] src2) { float result = src1[0] - src2[0]; if (result != 0) { return result; } result = src1[1] - src2[1]; if (result != 0) { return result; } return src1[2] - src2[2]; } /** * Adds three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. * * @return Overflow carry bit. */ public final float add(float[] src, float[] srcDst) { double result = (double) srcDst[2] + (double) src[2]; float carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[2] = (float) result; result = (double) srcDst[1] + (double) src[1] + carry; carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[1] = (float) result; result = (double) srcDst[0] + (double) src[0] + carry; carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[0] = (float) result; return carry; } /** * Subtracts three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. */ public final void subtract(float[] src, float[] srcDst) { float result = srcDst[2] - src[2], carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[2] = result; result = srcDst[1] - src[1] - carry; carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[1] = result; result = srcDst[0] - src[0] - carry; // carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[0] = result; } /** * Divides three words by the base to produce two words. Most significant word is stored first. * * @param srcDst Source and destination of the operation. * * @return Remainder of the division. */ public final float divide(float[] srcDst) { double tmp = (double) srcDst[0] * MAX_POWER_OF_TWO_BASE + srcDst[1]; float result = (float) (int) (tmp / this.base), carry = (float) (tmp - result * this.base); // = tmp % this.base srcDst[0] = 0; srcDst[1] = result; tmp = (double) carry * MAX_POWER_OF_TWO_BASE + srcDst[2]; result = (float) (int) (tmp / this.base); carry = (float) (tmp - result * this.base); // = tmp % this.base srcDst[2] = result; return carry; } private static final long serialVersionUID = 2778445457339436642L; private static final double INVERSE_MAX_POWER_OF_TWO_BASE = 1.0 / MAX_POWER_OF_TWO_BASE; private double base; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/FloatConstants.java000066400000000000000000000031511461767713300271620ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants needed for various algorithms for the float type. * * @since 1.4 * @version 1.4 * @author Mikko Tommila */ public interface FloatConstants { /** * Relative cost of Karatsuba multiplication. */ public static final float KARATSUBA_COST_FACTOR = 6.1f; /** * Relative cost of NTT multiplication. */ public static final float NTT_COST_FACTOR = 7.4f; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/FloatElementaryModMath.java000066400000000000000000000123111461767713300305630ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Elementary modulo arithmetic functions for float data. * Note that although a floating-point data type is used, the data * will always be integers.

* * Since the moduli are close to 224 some attention must be paid * to avoiding overflow in modular addition and subtraction. This can be * done easily e.g. by casting the operands to double. Note * that an IEEE float has a mantissa with a precision of 24 bits (1 + 23).

* * Modular multiplication is more complicated, and since it is usually * the single most time consuming operation in the whole program execution, * the very core of the Number Theoretic Transform (NTT), it should be * carefully optimized.

* * Some obvious (but not very efficient) algorithms for multiplying two * floats and taking the remainder would be to call * Math.IEEEremainder(), or cast the operands to * long, e.g.

* * (float) ((long) a * (long) b % (long) modulus)

* * Since the modulus is practically constant, it should be more efficient * to calculate (once) the inverse of the modulus, and then subsequently * multiply by the inverse modulus instead of dividing by the modulus.

* * The algorithm used in this implementation casts the operands to * double, performs the multiplication, multiplies by the * inverse modulus, then takes the integer part. Getting the integer * part is typically a lot faster by casting to int compared * to e.g. calling Math.floor(). An int, holding * 32 bits, can easily contain the result of the cast, which will have a * maximum of 24 bits.

* * Overflow is not a problem, since a double can hold 53 bits * precisely in the mantissa – more than doubly what a float * can. Note that multiplying by the inverse modulus is also trivial, when * the inverse modulus has more than twice accurate bits than what are in * each of the multiplicands. Since the modulus is assumed to be prime, there * can be no situations where multiplication by the inverse modulus would * have a near-integer result that would be rounded incorrectly, e.g. as in * 0.333... * 3 = 0.999.... * * @version 1.0 * @author Mikko Tommila */ public class FloatElementaryModMath { /** * Default constructor. */ public FloatElementaryModMath() { } /** * Modular multiplication. * * @param a First operand. * @param b Second operand. * * @return a * b % modulus */ public final float modMultiply(float a, float b) { double r = (double) a * (double) b; return (float) (r - (double) this.modulus * (double) (int) (this.inverseModulus * r)); } /** * Modular addition. * * @param a First operand. * @param b Second operand. * * @return (a + b) % modulus */ public final float modAdd(float a, float b) { double r = (double) a + (double) b; return (float) (r >= (double) this.modulus ? r - (double) this.modulus : r); } /** * Modular subtraction. The result is always >= 0. * * @param a First operand. * @param b Second operand. * * @return (a - b + modulus) % modulus */ public final float modSubtract(float a, float b) { float r = a - b; return (r < 0.0f ? r + this.modulus : r); } /** * Get the modulus. * * @return The modulus. */ public final float getModulus() { return this.modulus; } /** * Set the modulus. * * @param modulus The modulus. */ public final void setModulus(float modulus) { this.inverseModulus = 1.0 / (double) modulus; this.modulus = modulus; } private float modulus; private double inverseModulus; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/FloatModConstants.java000066400000000000000000000042751461767713300276320ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants needed for various modular arithmetic operations for the float type. * * @version 1.0 * @author Mikko Tommila */ public interface FloatModConstants { /** * Moduli to be used in number theoretic transforms. * Allows transform lengths upto 3*217. */ public static final float MODULUS[] = { 16515073.0f, 14942209.0f, 14155777.0f }; /** * Primitive roots for the corresponding moduli. */ public static final float PRIMITIVE_ROOT[] = { 5.0f, 11.0f, 7.0f }; /** * Maximum transform length for the moduli. */ public static final long MAX_TRANSFORM_LENGTH = 393216; /** * Maximum bits in a power-of-two base that fits in a float. */ public static final int MAX_POWER_OF_TWO_BITS = 24; /** * Maximum power-of-two base that fits in a float. */ public static final float MAX_POWER_OF_TWO_BASE = (float) (1 << MAX_POWER_OF_TWO_BITS); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/FloatRadixConstants.java000066400000000000000000000153151461767713300301570ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants related to different radixes for the float data type. * * @version 1.0 * @author Mikko Tommila */ public interface FloatRadixConstants { /** * Bases for radixes 2, ..., 36. The base is the radix to the maximum power * so that the base is less than all moduli used. */ public static final float BASE[] = { (float) -1L, (float) -1L, (float) 8388608L, (float) 4782969L, (float) 4194304L, (float) 9765625L, (float) 10077696L, (float) 5764801L, (float) 2097152L, (float) 4782969L, (float) 10000000L, (float) 1771561L, (float) 2985984L, (float) 4826809L, (float) 7529536L, (float) 11390625L, (float) 1048576L, (float) 1419857L, (float) 1889568L, (float) 2476099L, (float) 3200000L, (float) 4084101L, (float) 5153632L, (float) 6436343L, (float) 7962624L, (float) 9765625L, (float) 11881376L, (float) 531441L, (float) 614656L, (float) 707281L, (float) 810000L, (float) 923521L, (float) 1048576L, (float) 1185921L, (float) 1336336L, (float) 1500625L, (float) 1679616L }; /** * The power of the radix in each base. */ public static final int BASE_DIGITS[] = { -1, -1, 23, 14, 11, 10, 9, 8, 7, 7, 7, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4 }; /** * The minimum number in each radix to have the specified amount of digits. */ public static final float MINIMUM_FOR_DIGITS[][] = { null, null, { (float) 1L, (float) 2L, (float) 4L, (float) 8L, (float) 16L, (float) 32L, (float) 64L, (float) 128L, (float) 256L, (float) 512L, (float) 1024L, (float) 2048L, (float) 4096L, (float) 8192L, (float) 16384L, (float) 32768L, (float) 65536L, (float) 131072L, (float) 262144L, (float) 524288L, (float) 1048576L, (float) 2097152L, (float) 4194304L }, { (float) 1L, (float) 3L, (float) 9L, (float) 27L, (float) 81L, (float) 243L, (float) 729L, (float) 2187L, (float) 6561L, (float) 19683L, (float) 59049L, (float) 177147L, (float) 531441L, (float) 1594323L }, { (float) 1L, (float) 4L, (float) 16L, (float) 64L, (float) 256L, (float) 1024L, (float) 4096L, (float) 16384L, (float) 65536L, (float) 262144L, (float) 1048576L }, { (float) 1L, (float) 5L, (float) 25L, (float) 125L, (float) 625L, (float) 3125L, (float) 15625L, (float) 78125L, (float) 390625L, (float) 1953125L }, { (float) 1L, (float) 6L, (float) 36L, (float) 216L, (float) 1296L, (float) 7776L, (float) 46656L, (float) 279936L, (float) 1679616L }, { (float) 1L, (float) 7L, (float) 49L, (float) 343L, (float) 2401L, (float) 16807L, (float) 117649L, (float) 823543L }, { (float) 1L, (float) 8L, (float) 64L, (float) 512L, (float) 4096L, (float) 32768L, (float) 262144L }, { (float) 1L, (float) 9L, (float) 81L, (float) 729L, (float) 6561L, (float) 59049L, (float) 531441L }, { (float) 1L, (float) 10L, (float) 100L, (float) 1000L, (float) 10000L, (float) 100000L, (float) 1000000L }, { (float) 1L, (float) 11L, (float) 121L, (float) 1331L, (float) 14641L, (float) 161051L }, { (float) 1L, (float) 12L, (float) 144L, (float) 1728L, (float) 20736L, (float) 248832L }, { (float) 1L, (float) 13L, (float) 169L, (float) 2197L, (float) 28561L, (float) 371293L }, { (float) 1L, (float) 14L, (float) 196L, (float) 2744L, (float) 38416L, (float) 537824L }, { (float) 1L, (float) 15L, (float) 225L, (float) 3375L, (float) 50625L, (float) 759375L }, { (float) 1L, (float) 16L, (float) 256L, (float) 4096L, (float) 65536L }, { (float) 1L, (float) 17L, (float) 289L, (float) 4913L, (float) 83521L }, { (float) 1L, (float) 18L, (float) 324L, (float) 5832L, (float) 104976L }, { (float) 1L, (float) 19L, (float) 361L, (float) 6859L, (float) 130321L }, { (float) 1L, (float) 20L, (float) 400L, (float) 8000L, (float) 160000L }, { (float) 1L, (float) 21L, (float) 441L, (float) 9261L, (float) 194481L }, { (float) 1L, (float) 22L, (float) 484L, (float) 10648L, (float) 234256L }, { (float) 1L, (float) 23L, (float) 529L, (float) 12167L, (float) 279841L }, { (float) 1L, (float) 24L, (float) 576L, (float) 13824L, (float) 331776L }, { (float) 1L, (float) 25L, (float) 625L, (float) 15625L, (float) 390625L }, { (float) 1L, (float) 26L, (float) 676L, (float) 17576L, (float) 456976L }, { (float) 1L, (float) 27L, (float) 729L, (float) 19683L }, { (float) 1L, (float) 28L, (float) 784L, (float) 21952L }, { (float) 1L, (float) 29L, (float) 841L, (float) 24389L }, { (float) 1L, (float) 30L, (float) 900L, (float) 27000L }, { (float) 1L, (float) 31L, (float) 961L, (float) 29791L }, { (float) 1L, (float) 32L, (float) 1024L, (float) 32768L }, { (float) 1L, (float) 33L, (float) 1089L, (float) 35937L }, { (float) 1L, (float) 34L, (float) 1156L, (float) 39304L }, { (float) 1L, (float) 35L, (float) 1225L, (float) 42875L }, { (float) 1L, (float) 36L, (float) 1296L, (float) 46656L } }; /** * Maximum allowed exponent for each radix. */ public static final long MAX_EXPONENT[] = { -1L, -1L, 401016175515425029L, 658812288346769694L, 838488366986797794L, 922337203685477574L, 1024819115206086194L, 1152921504606846969L, 1317624576693539395L, 1317624576693539395L, 1317624576693539395L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1844674407370955155L, 1844674407370955155L, 1844674407370955155L, 1844674407370955155L, 1844674407370955155L, 1844674407370955155L, 1844674407370955155L, 1844674407370955155L, 1844674407370955155L, 1844674407370955155L, 1844674407370955155L, 2305843009213693945L, 2305843009213693945L, 2305843009213693945L, 2305843009213693945L, 2305843009213693945L, 2305843009213693945L, 2305843009213693945L, 2305843009213693945L, 2305843009213693945L, 2305843009213693945L }; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/ImplementationMismatchException.java000066400000000000000000000045071461767713300325600ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Exception indicating a different implementation of the apfloat SPI * being used in two operands of a calculation.

* * @since 1.5 * @version 1.5 * @author Mikko Tommila */ public class ImplementationMismatchException extends ApfloatInternalException { /** * Constructs a new apfloat implementation mismatch exception with an empty detail message. */ public ImplementationMismatchException() { } /** * Constructs a new apfloat implementation mismatch exception with the specified detail message. * * @param message The detail message. */ public ImplementationMismatchException(String message) { super(message); } /** * Constructs a new apfloat implementation mismatch exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public ImplementationMismatchException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/IntBaseMath.java000066400000000000000000000224561461767713300263700ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.Serializable; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import static org.apfloat.internal.IntRadixConstants.*; /** * Mathematical operations on numbers in a base. * Implementation for the int type. * * @version 1.8.2 * @author Mikko Tommila */ public class IntBaseMath implements Serializable { /** * Creates a base math using the specified radix. * * @param radix The radix that will be used. */ public IntBaseMath(int radix) { this.radix = radix; } /** * Addition in some base. Adds the data words * of src1 and src2 and stores the result to * dst. src2 may be null, in * which case it is ignored (only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] + src2[i]. * * @param src1 First source data sequence. Can be null, in which case it's ignored. * @param src2 Second source data sequence. Can be null, in which case it's ignored. * @param carry Input carry bit. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the addition of the last (leftmost) word in the accessed sequence. */ public int baseAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, int carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); boolean sameDst = (src1 == dst || src2 == dst); int base = BASE[this.radix]; for (long i = 0; i < size; i++) { int result = (src1 == null ? 0 : src1.getInt()) + carry + (src2 == null ? 0 : src2.getInt()); carry = (result >= base | result < 0 ? 1 : 0); // Detect overflow (optimization: | is often faster than || here) result -= (result >= base | result < 0 ? base : 0); dst.setInt(result); if (src1 != null) src1.next(); if (src2 != null) src2.next(); if (!sameDst) dst.next(); } return carry; } /** * Subtraction in some base. Subtracts the data words * of src1 and src2 and stores the result to * dst. src1 and src2 may be * null, in which case they are ignored (the values are assumed * to be zero and only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] - src2[i]. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param carry Input carry bit. This is subtracted from the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the subtraction of the last (leftmost) word in the accessed sequence. The value is 1 if the carry is set, and 0 otherwise. */ public int baseSubtract(DataStorage.Iterator src1, DataStorage.Iterator src2, int carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); assert (src2 != dst); int base = BASE[this.radix]; for (long i = 0; i < size; i++) { int result = (src1 == null ? 0 : src1.getInt()) - carry - (src2 == null ? 0 : src2.getInt()); carry = (result < 0 ? 1 : 0); result += (result < 0 ? base : 0); dst.setInt(result); if (src1 != null && src1 != dst) src1.next(); if (src2 != null) src2.next(); dst.next(); } return carry; } /** * Multiplication and addition in some base. Multiplies the data words * of src1 by src3 and adds the result to the * words in src2, and stores the result to dst. * src2 may be null, in which case it is ignored * (the values are assumed to be zero).

* * Assumes that the result from the addition doesn't overflow the upper * result word (to larger than the base). This is the case e.g. when using * this method to perform an arbitrary precision multiplication.

* * Essentially calculates dst[i] = src1[i] * src3 + src2[i]. * * @param src1 First source data sequence. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param src3 Multiplicand. All elements of src1 are multiplied by this value. * @param carry Input carry word. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry word. Propagated carry word from the multiplication and addition of the last (leftmost) word in the accessed sequence. */ public int baseMultiplyAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, int src3, int carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != src2); assert (src1 != dst); int base = BASE[this.radix]; for (long i = 0; i < size; i++) { long tmp = (long) src1.getInt() * (long) src3 + (src2 == null ? 0 : src2.getInt()) + carry; carry = (int) (tmp / base); dst.setInt((int) tmp - carry * base); // = tmp % base src1.next(); if (src2 != null && src2 != dst) src2.next(); dst.next(); } return carry; } /** * Division in some base. Divides the data words * of src1 by src2 and stores the result to * dst. src1 may be null, * in which case it is ignored (the values are assumed to be * zero and only the carry division is propagated).

* * Essentially calculates dst[i] = src1[i] / src2. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Divisor. All elements of src1 are divided by this value. * @param carry Input carry word. Used as the upper word for the division of the first input element. This should be the remainder word returned from the previous block processed. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Remainder word of the propagated division of the last (rightmost) word in the accessed sequence. */ public int baseDivide(DataStorage.Iterator src1, int src2, int carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != dst); int base = BASE[this.radix]; for (long i = 0; i < size; i++) { long tmp = (long) carry * (long) base + (src1 == null ? 0 : src1.getInt()); int result = (int) (tmp / src2); carry = (int) tmp - result * src2; // = tmp % src2 dst.setInt(result); if (src1 != null) src1.next(); dst.next(); } return carry; } private static final long serialVersionUID = 2173589976837534455L; private int radix; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/IntCRTMath.java000066400000000000000000000135241461767713300261420ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import static org.apfloat.internal.IntModConstants.*; import static org.apfloat.internal.IntRadixConstants.*; /** * Basic arithmetic for calculating the Chinese Remainder * Theorem. Works for the int type. * * @version 1.6 * @author Mikko Tommila */ public class IntCRTMath extends IntBaseMath { /** * Creates a carry-CRT math using the specified radix. * * @param radix The radix that will be used. */ public IntCRTMath(int radix) { super(radix); this.base = BASE[radix]; } /** * Multiplies two words by one word to produce a result of three words. * Most significant word is stored first. * * @param src Source array, first multiplicand. * @param factor Second multiplicand. * @param dst Destination array. */ public final void multiply(int[] src, int factor, int[] dst) { long tmp = (long) src[1] * (long) factor; int carry = (int) (tmp >>> MAX_POWER_OF_TWO_BITS); dst[2] = (int) tmp & BASE_MASK; // = tmp % MAX_POWER_OF_TWO_BASE tmp = (long) src[0] * (long) factor + carry; carry = (int) (tmp >>> MAX_POWER_OF_TWO_BITS); dst[1] = (int) tmp & BASE_MASK; // = tmp % MAX_POWER_OF_TWO_BASE dst[0] = carry; } /** * Compares three words. Most significant word is stored first. * * @param src1 First operand. * @param src2 Second operand. * * @return Less than zero if src1 < src2, greater than zero if src1 > src2 and zero if src1 == src2. */ public final int compare(int[] src1, int[] src2) { int result = src1[0] - src2[0]; if (result != 0) { return result; } result = src1[1] - src2[1]; if (result != 0) { return result; } return src1[2] - src2[2]; } /** * Adds three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. * * @return Overflow carry bit. */ public final int add(int[] src, int[] srcDst) { int result = srcDst[2] + src[2], carry = (result < 0 ? 1 : 0); result = (result < 0 ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[2] = result; result = srcDst[1] + src[1] + carry; carry = (result < 0 ? 1 : 0); result = (result < 0 ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[1] = result; result = srcDst[0] + src[0] + carry; carry = (result < 0 ? 1 : 0); result = (result < 0 ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[0] = result; return carry; } /** * Subtracts three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. */ public final void subtract(int[] src, int[] srcDst) { int result = srcDst[2] - src[2], carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[2] = result; result = srcDst[1] - src[1] - carry; carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[1] = result; result = srcDst[0] - src[0] - carry; // carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[0] = result; } /** * Divides three words by the base to produce two words. Most significant word is stored first. * * @param srcDst Source and destination of the operation. * * @return Remainder of the division. */ public final int divide(int[] srcDst) { long tmp = ((long) srcDst[0] << MAX_POWER_OF_TWO_BITS) + srcDst[1]; int result = (int) (tmp / this.base), carry = (int) tmp - result * this.base; // = tmp % this.base srcDst[0] = 0; srcDst[1] = result; tmp = ((long) carry << MAX_POWER_OF_TWO_BITS) + srcDst[2]; result = (int) (tmp / this.base); carry = (int) tmp - result * this.base; // = tmp % this.base srcDst[2] = result; return carry; } private static final long serialVersionUID = 6698972116690441263L; private static final int BASE_MASK = (1 << MAX_POWER_OF_TWO_BITS) - 1; private int base; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/IntConstants.java000066400000000000000000000031451461767713300266520ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants needed for various algorithms for the int type. * * @since 1.4 * @version 1.4 * @author Mikko Tommila */ public interface IntConstants { /** * Relative cost of Karatsuba multiplication. */ public static final float KARATSUBA_COST_FACTOR = 4.8f; /** * Relative cost of NTT multiplication. */ public static final float NTT_COST_FACTOR = 4.1f; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/IntElementaryModMath.java000066400000000000000000000126751461767713300302650ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Elementary modulo arithmetic functions for int data.

* * Modular addition and subtraction are trivial, when the modulus is less * than 231 and overflow can be detected easily.

* * Modular multiplication is more complicated, and since it is usually * the single most time consuming operation in the whole program execution, * the very core of the Number Theoretic Transform (NTT), it should be * carefully optimized.

* * The obvious (but not very efficient) algorithm for multiplying two * ints and taking the remainder is

* * (int) ((long) a * b % modulus)

* * The first observation is that since the modulus is practically * constant, it should be more efficient to calculate (once) the inverse * of the modulus, and then subsequently multiply by the inverse modulus * instead of dividing by the modulus.

* * The second observation is that to get the remainder of the division, * we don't necessarily need the actual result of the division (we just * want the remainder). So, we should discard the topmost 32 bits of the * full 64-bit result whenever possible, to save a few operations.

* * The basic approach is to get some approximation of a * b / modulus. * The approximation should be within +1 or -1 of the correct result. Then * calculate a * b - approximateDivision * modulus to get * the remainder. This calculation needs to use only the lowest 32 bits. As * the modulus is less than 231 it is easy to detect the case * when the approximate division was off by one (and the remainder is * ±modulus off).

* * There are different algorithms to calculate the approximate division * a * b / modulus. This implementation simply converts all * the operands to double and performs the multiplications. * This requires that converting between integer types and floating point * types is efficient. On some platforms this may not be true; in that * case it can be more efficient to perform the multiplications using * 64-bit integer arithmetic.

* * To simplify the operations, we calculate the inverse modulus as * 1.0 / (modulus + 0.5). Since the modulus is assumed to be * prime, and a double has more bits for precision than an * int, the approximate result of a * b / modulus * will always be either correct or one too small (but never one too big). * * @version 1.0.2 * @author Mikko Tommila */ public class IntElementaryModMath { /** * Default constructor. */ public IntElementaryModMath() { } /** * Modular multiplication. * * @param a First operand. * @param b Second operand. * * @return a * b % modulus */ public final int modMultiply(int a, int b) { int r1 = a * b - (int) (this.inverseModulus * (double) a * (double) b) * this.modulus, r2 = r1 - this.modulus; return (r2 < 0 ? r1 : r2); } /** * Modular addition. * * @param a First operand. * @param b Second operand. * * @return (a + b) % modulus */ public final int modAdd(int a, int b) { int r1 = a + b, r2 = r1 - this.modulus; return (r2 < 0 ? r1 : r2); } /** * Modular subtraction. The result is always >= 0. * * @param a First operand. * @param b Second operand. * * @return (a - b + modulus) % modulus */ public final int modSubtract(int a, int b) { int r1 = a - b, r2 = r1 + this.modulus; return (r1 < 0 ? r2 : r1); } /** * Get the modulus. * * @return The modulus. */ public final int getModulus() { return this.modulus; } /** * Set the modulus. * * @param modulus The modulus. */ public final void setModulus(int modulus) { this.inverseModulus = 1.0 / (modulus + 0.5); // Round down this.modulus = modulus; } private int modulus; private double inverseModulus; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/IntModConstants.java000066400000000000000000000042361461767713300273140ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants needed for various modular arithmetic operations for the int type. * * @version 1.0 * @author Mikko Tommila */ public interface IntModConstants { /** * Moduli to be used in number theoretic transforms. * Allows transform lengths upto 3*224. */ public static final int MODULUS[] = { 2113929217, 2013265921, 1811939329 }; /** * Primitive roots for the corresponding moduli. */ public static final int PRIMITIVE_ROOT[] = { 5, 31, 13 }; /** * Maximum transform length for the moduli. */ public static final long MAX_TRANSFORM_LENGTH = 50331648; /** * Maximum bits in a power-of-two base that fits in an int. */ public static final int MAX_POWER_OF_TWO_BITS = 31; /** * Maximum power-of-two base that fits in an int. */ public static final int MAX_POWER_OF_TWO_BASE = 1 << MAX_POWER_OF_TWO_BITS; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/IntRadixConstants.java000066400000000000000000000167421461767713300276510ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants related to different radixes for the int data type. * * @version 1.0 * @author Mikko Tommila */ public interface IntRadixConstants { /** * Bases for radixes 2, ..., 36. The base is the radix to the maximum power * so that the base is less than all moduli used. */ public static final int BASE[] = { (int) -1L, (int) -1L, (int) 1073741824L, (int) 1162261467L, (int) 1073741824L, (int) 1220703125L, (int) 362797056L, (int) 282475249L, (int) 1073741824L, (int) 387420489L, (int) 1000000000L, (int) 214358881L, (int) 429981696L, (int) 815730721L, (int) 1475789056L, (int) 170859375L, (int) 268435456L, (int) 410338673L, (int) 612220032L, (int) 893871739L, (int) 1280000000L, (int) 1801088541L, (int) 113379904L, (int) 148035889L, (int) 191102976L, (int) 244140625L, (int) 308915776L, (int) 387420489L, (int) 481890304L, (int) 594823321L, (int) 729000000L, (int) 887503681L, (int) 1073741824L, (int) 1291467969L, (int) 1544804416L, (int) 52521875L, (int) 60466176L }; /** * The power of the radix in each base. */ public static final int BASE_DIGITS[] = { -1, -1, 30, 19, 15, 13, 11, 10, 10, 9, 9, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5 }; /** * The minimum number in each radix to have the specified amount of digits. */ public static final int MINIMUM_FOR_DIGITS[][] = { null, null, { (int) 1L, (int) 2L, (int) 4L, (int) 8L, (int) 16L, (int) 32L, (int) 64L, (int) 128L, (int) 256L, (int) 512L, (int) 1024L, (int) 2048L, (int) 4096L, (int) 8192L, (int) 16384L, (int) 32768L, (int) 65536L, (int) 131072L, (int) 262144L, (int) 524288L, (int) 1048576L, (int) 2097152L, (int) 4194304L, (int) 8388608L, (int) 16777216L, (int) 33554432L, (int) 67108864L, (int) 134217728L, (int) 268435456L, (int) 536870912L }, { (int) 1L, (int) 3L, (int) 9L, (int) 27L, (int) 81L, (int) 243L, (int) 729L, (int) 2187L, (int) 6561L, (int) 19683L, (int) 59049L, (int) 177147L, (int) 531441L, (int) 1594323L, (int) 4782969L, (int) 14348907L, (int) 43046721L, (int) 129140163L, (int) 387420489L }, { (int) 1L, (int) 4L, (int) 16L, (int) 64L, (int) 256L, (int) 1024L, (int) 4096L, (int) 16384L, (int) 65536L, (int) 262144L, (int) 1048576L, (int) 4194304L, (int) 16777216L, (int) 67108864L, (int) 268435456L }, { (int) 1L, (int) 5L, (int) 25L, (int) 125L, (int) 625L, (int) 3125L, (int) 15625L, (int) 78125L, (int) 390625L, (int) 1953125L, (int) 9765625L, (int) 48828125L, (int) 244140625L }, { (int) 1L, (int) 6L, (int) 36L, (int) 216L, (int) 1296L, (int) 7776L, (int) 46656L, (int) 279936L, (int) 1679616L, (int) 10077696L, (int) 60466176L }, { (int) 1L, (int) 7L, (int) 49L, (int) 343L, (int) 2401L, (int) 16807L, (int) 117649L, (int) 823543L, (int) 5764801L, (int) 40353607L }, { (int) 1L, (int) 8L, (int) 64L, (int) 512L, (int) 4096L, (int) 32768L, (int) 262144L, (int) 2097152L, (int) 16777216L, (int) 134217728L }, { (int) 1L, (int) 9L, (int) 81L, (int) 729L, (int) 6561L, (int) 59049L, (int) 531441L, (int) 4782969L, (int) 43046721L }, { (int) 1L, (int) 10L, (int) 100L, (int) 1000L, (int) 10000L, (int) 100000L, (int) 1000000L, (int) 10000000L, (int) 100000000L }, { (int) 1L, (int) 11L, (int) 121L, (int) 1331L, (int) 14641L, (int) 161051L, (int) 1771561L, (int) 19487171L }, { (int) 1L, (int) 12L, (int) 144L, (int) 1728L, (int) 20736L, (int) 248832L, (int) 2985984L, (int) 35831808L }, { (int) 1L, (int) 13L, (int) 169L, (int) 2197L, (int) 28561L, (int) 371293L, (int) 4826809L, (int) 62748517L }, { (int) 1L, (int) 14L, (int) 196L, (int) 2744L, (int) 38416L, (int) 537824L, (int) 7529536L, (int) 105413504L }, { (int) 1L, (int) 15L, (int) 225L, (int) 3375L, (int) 50625L, (int) 759375L, (int) 11390625L }, { (int) 1L, (int) 16L, (int) 256L, (int) 4096L, (int) 65536L, (int) 1048576L, (int) 16777216L }, { (int) 1L, (int) 17L, (int) 289L, (int) 4913L, (int) 83521L, (int) 1419857L, (int) 24137569L }, { (int) 1L, (int) 18L, (int) 324L, (int) 5832L, (int) 104976L, (int) 1889568L, (int) 34012224L }, { (int) 1L, (int) 19L, (int) 361L, (int) 6859L, (int) 130321L, (int) 2476099L, (int) 47045881L }, { (int) 1L, (int) 20L, (int) 400L, (int) 8000L, (int) 160000L, (int) 3200000L, (int) 64000000L }, { (int) 1L, (int) 21L, (int) 441L, (int) 9261L, (int) 194481L, (int) 4084101L, (int) 85766121L }, { (int) 1L, (int) 22L, (int) 484L, (int) 10648L, (int) 234256L, (int) 5153632L }, { (int) 1L, (int) 23L, (int) 529L, (int) 12167L, (int) 279841L, (int) 6436343L }, { (int) 1L, (int) 24L, (int) 576L, (int) 13824L, (int) 331776L, (int) 7962624L }, { (int) 1L, (int) 25L, (int) 625L, (int) 15625L, (int) 390625L, (int) 9765625L }, { (int) 1L, (int) 26L, (int) 676L, (int) 17576L, (int) 456976L, (int) 11881376L }, { (int) 1L, (int) 27L, (int) 729L, (int) 19683L, (int) 531441L, (int) 14348907L }, { (int) 1L, (int) 28L, (int) 784L, (int) 21952L, (int) 614656L, (int) 17210368L }, { (int) 1L, (int) 29L, (int) 841L, (int) 24389L, (int) 707281L, (int) 20511149L }, { (int) 1L, (int) 30L, (int) 900L, (int) 27000L, (int) 810000L, (int) 24300000L }, { (int) 1L, (int) 31L, (int) 961L, (int) 29791L, (int) 923521L, (int) 28629151L }, { (int) 1L, (int) 32L, (int) 1024L, (int) 32768L, (int) 1048576L, (int) 33554432L }, { (int) 1L, (int) 33L, (int) 1089L, (int) 35937L, (int) 1185921L, (int) 39135393L }, { (int) 1L, (int) 34L, (int) 1156L, (int) 39304L, (int) 1336336L, (int) 45435424L }, { (int) 1L, (int) 35L, (int) 1225L, (int) 42875L, (int) 1500625L }, { (int) 1L, (int) 36L, (int) 1296L, (int) 46656L, (int) 1679616L } }; /** * Maximum allowed exponent for each radix. */ public static final long MAX_EXPONENT[] = { -1L, -1L, 307445734561825854L, 485440633518672404L, 614891469123651714L, 709490156681136594L, 838488366986797794L, 922337203685477574L, 922337203685477574L, 1024819115206086194L, 1024819115206086194L, 1152921504606846969L, 1152921504606846969L, 1152921504606846969L, 1152921504606846969L, 1317624576693539395L, 1317624576693539395L, 1317624576693539395L, 1317624576693539395L, 1317624576693539395L, 1317624576693539395L, 1317624576693539395L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1537228672809129295L, 1844674407370955155L, 1844674407370955155L }; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/LongBaseMath.java000066400000000000000000000247751461767713300265430ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.Serializable; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import static org.apfloat.internal.LongRadixConstants.*; /** * Mathematical operations on numbers in a base. * Implementation for the long type. * * @version 1.8.2 * @author Mikko Tommila */ public class LongBaseMath implements Serializable { /** * Creates a base math using the specified radix. * * @param radix The radix that will be used. */ public LongBaseMath(int radix) { this.radix = radix; this.inverseBase = 1.0 / BASE[radix]; } /** * Addition in some base. Adds the data words * of src1 and src2 and stores the result to * dst. src2 may be null, in * which case it is ignored (only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] + src2[i]. * * @param src1 First source data sequence. Can be null, in which case it's ignored. * @param src2 Second source data sequence. Can be null, in which case it's ignored. * @param carry Input carry bit. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the addition of the last (leftmost) word in the accessed sequence. */ public long baseAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, long carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); boolean sameDst = (src1 == dst || src2 == dst); long base = BASE[this.radix]; for (long i = 0; i < size; i++) { long result = (src1 == null ? 0 : src1.getLong()) + carry + (src2 == null ? 0 : src2.getLong()); carry = (result >= base ? 1 : 0); result -= (result >= base ? base : 0); dst.setLong(result); if (src1 != null) src1.next(); if (src2 != null) src2.next(); if (!sameDst) dst.next(); } return carry; } /** * Subtraction in some base. Subtracts the data words * of src1 and src2 and stores the result to * dst. src1 and src2 may be * null, in which case they are ignored (the values are assumed * to be zero and only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] - src2[i]. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param carry Input carry bit. This is subtracted from the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the subtraction of the last (leftmost) word in the accessed sequence. The value is 1 if the carry is set, and 0 otherwise. */ public long baseSubtract(DataStorage.Iterator src1, DataStorage.Iterator src2, long carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); assert (src2 != dst); long base = BASE[this.radix]; for (long i = 0; i < size; i++) { long result = (src1 == null ? 0 : src1.getLong()) - carry - (src2 == null ? 0 : src2.getLong()); carry = (result < 0 ? 1 : 0); result += (result < 0 ? base : 0); dst.setLong(result); if (src1 != null && src1 != dst) src1.next(); if (src2 != null) src2.next(); dst.next(); } return carry; } /** * Multiplication and addition in some base. Multiplies the data words * of src1 by src3 and adds the result to the * words in src2, and stores the result to dst. * src2 may be null, in which case it is ignored * (the values are assumed to be zero).

* * Assumes that the result from the addition doesn't overflow the upper * result word (to larger than the base). This is the case e.g. when using * this method to perform an arbitrary precision multiplication.

* * Essentially calculates dst[i] = src1[i] * src3 + src2[i]. * * @param src1 First source data sequence. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param src3 Multiplicand. All elements of src1 are multiplied by this value. * @param carry Input carry word. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry word. Propagated carry word from the multiplication and addition of the last (leftmost) word in the accessed sequence. */ public long baseMultiplyAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, long src3, long carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != src2); assert (src1 != dst); long base = BASE[this.radix]; for (long i = 0; i < size; i++) { long a = src1.getLong(), b = src3; carry += (src2 == null ? 0 : src2.getLong()); long tmp = a * b + carry; carry = (long) (((double) a * (double) b + (double) carry) * this.inverseBase); tmp -= carry * base; int tmp2 = (int) ((double) tmp * this.inverseBase); carry += tmp2; tmp -= tmp2 * base; carry += (tmp >= base ? 1 : 0); tmp -= (tmp >= base ? base : 0); carry += (tmp >= base ? 1 : 0); tmp -= (tmp >= base ? base : 0); carry -= (tmp < 0 ? 1 : 0); tmp += (tmp < 0 ? base : 0); carry -= (tmp < 0 ? 1 : 0); tmp += (tmp < 0 ? base : 0); dst.setLong(tmp); // = a * b % base src1.next(); if (src2 != null && src2 != dst) src2.next(); dst.next(); } return carry; } /** * Division in some base. Divides the data words * of src1 by src2 and stores the result to * dst. src1 may be null, * in which case it is ignored (the values are assumed to be * zero and only the carry division is propagated).

* * Essentially calculates dst[i] = src1[i] / src2. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Divisor. All elements of src1 are divided by this value. * @param carry Input carry word. Used as the upper word for the division of the first input element. This should be the remainder word returned from the previous block processed. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Remainder word of the propagated division of the last (rightmost) word in the accessed sequence. */ public long baseDivide(DataStorage.Iterator src1, long src2, long carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != dst); long base = BASE[this.radix]; double inverseDivisor = 1.0 / src2; for (long i = 0; i < size; i++) { long a = (src1 == null ? 0 : src1.getLong()), tmp = carry * base + a, result = (long) (((double) carry * (double) base + (double) a) * inverseDivisor); carry = tmp - result * src2; int tmp2 = (int) ((double) carry * inverseDivisor); result += tmp2; carry -= tmp2 * src2; result += (carry >= src2 ? 1 : 0); carry -= (carry >= src2 ? src2 : 0); result += (carry >= src2 ? 1 : 0); carry -= (carry >= src2 ? src2 : 0); result -= (carry < 0 ? 1 : 0); carry += (carry < 0 ? src2 : 0); result -= (carry < 0 ? 1 : 0); carry += (carry < 0 ? src2 : 0); dst.setLong(result); // = carry * base % src2 if (src1 != null) src1.next(); dst.next(); } return carry; } private static final long serialVersionUID = -6469225916787810664L; private int radix; private double inverseBase; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/LongCRTMath.java000066400000000000000000000171401461767713300263050ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import static org.apfloat.internal.LongModConstants.*; import static org.apfloat.internal.LongRadixConstants.*; /** * Basic arithmetic for calculating the Chinese Remainder * Theorem. Works for the long type. * * @version 1.6 * @author Mikko Tommila */ public class LongCRTMath extends LongBaseMath { /** * Creates a carry-CRT math using the specified radix. * * @param radix The radix that will be used. */ public LongCRTMath(int radix) { super(radix); this.base = BASE[radix]; this.inverseBase = 1.0 / BASE[radix]; } /** * Multiplies two words by one word to produce a result of three words. * Most significant word is stored first. * * @param src Source array, first multiplicand. * @param factor Second multiplicand. * @param dst Destination array. */ public final void multiply(long[] src, long factor, long[] dst) { long tmp = src[1] * factor, carry = (long) ((double) src[1] * (double) factor * INVERSE_MAX_POWER_OF_TWO_BASE); carry += tmp - (carry << MAX_POWER_OF_TWO_BITS) >> MAX_POWER_OF_TWO_BITS; dst[2] = tmp & BASE_MASK; // = tmp % MAX_POWER_OF_TWO_BASE tmp = src[0] * factor + carry; carry = (long) (((double) src[0] * (double) factor + (double) carry) * INVERSE_MAX_POWER_OF_TWO_BASE); carry += tmp - (carry << MAX_POWER_OF_TWO_BITS) >> MAX_POWER_OF_TWO_BITS; dst[1] = tmp & BASE_MASK; // = tmp % MAX_POWER_OF_TWO_BASE dst[0] = carry; } /** * Compares three words. Most significant word is stored first. * * @param src1 First operand. * @param src2 Second operand. * * @return Less than zero if src1 < src2, greater than zero if src1 > src2 and zero if src1 == src2. */ public final long compare(long[] src1, long[] src2) { long result = src1[0] - src2[0]; if (result != 0) { return result; } result = src1[1] - src2[1]; if (result != 0) { return result; } return src1[2] - src2[2]; } /** * Adds three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. * * @return Overflow carry bit. */ public final long add(long[] src, long[] srcDst) { long result = srcDst[2] + src[2], carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[2] = result; result = srcDst[1] + src[1] + carry; carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[1] = result; result = srcDst[0] + src[0] + carry; carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[0] = result; return carry; } /** * Subtracts three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. */ public final void subtract(long[] src, long[] srcDst) { long result = srcDst[2] - src[2], carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[2] = result; result = srcDst[1] - src[1] - carry; carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[1] = result; result = srcDst[0] - src[0] - carry; // carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[0] = result; } /** * Divides three words by the base to produce two words. Most significant word is stored first. * * @param srcDst Source and destination of the operation. * * @return Remainder of the division. */ public final long divide(long[] srcDst) { long tmp = (srcDst[0] << MAX_POWER_OF_TWO_BITS) + srcDst[1], result = (long) (((double) srcDst[0] * (double) MAX_POWER_OF_TWO_BASE + (double) srcDst[1]) * this.inverseBase), carry = tmp - result * this.base; // = tmp % divisor int tmp2 = (int) ((double) carry * this.inverseBase); result += tmp2; carry -= tmp2 * this.base; if (carry >= this.base) { carry -= this.base; result++; } if (carry >= this.base) { carry -= this.base; result++; } if (carry < 0) { carry += this.base; result--; } if (carry < 0) { carry += this.base; result--; } srcDst[0] = 0; srcDst[1] = result; tmp = (carry << MAX_POWER_OF_TWO_BITS) + srcDst[2]; result = (long) (((double) carry * (double) MAX_POWER_OF_TWO_BASE + (double) srcDst[2]) * this.inverseBase); carry = tmp - result * this.base; // = tmp % divisor tmp2 = (int) ((double) carry * this.inverseBase); result += tmp2; carry -= tmp2 * this.base; if (carry >= this.base) { carry -= this.base; result++; } if (carry >= this.base) { carry -= this.base; result++; } if (carry < 0) { carry += this.base; result--; } if (carry < 0) { carry += this.base; result--; } srcDst[2] = result; return carry; } private static final long serialVersionUID = 7400961005627736773L; private static final long BASE_MASK = (1L << MAX_POWER_OF_TWO_BITS) - 1; private static final double INVERSE_MAX_POWER_OF_TWO_BASE = 1.0 / MAX_POWER_OF_TWO_BASE; private long base; private double inverseBase; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/LongConstants.java000066400000000000000000000031471461767713300270210ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants needed for various algorithms for the long type. * * @since 1.4 * @version 1.4 * @author Mikko Tommila */ public interface LongConstants { /** * Relative cost of Karatsuba multiplication. */ public static final float KARATSUBA_COST_FACTOR = 4.3f; /** * Relative cost of NTT multiplication. */ public static final float NTT_COST_FACTOR = 8.3f; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/LongElementaryModMath.java000066400000000000000000000142761461767713300304310ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Elementary modulo arithmetic functions for long data.

* * Modular addition and subtraction are trivial, when the modulus is less * than 263 and overflow can be detected easily.

* * Modular multiplication is more complicated, and since it is usually * the single most time consuming operation in the whole program execution, * the very core of the Number Theoretic Transform (NTT), it should be * carefully optimized.

* * The algorithm for multiplying two longs and taking the * remainder is not entirely obvious. The basic problem is to get the * full 128-bit result of multiplying two 64-bit integers. It would be * possible to do this by splitting the arguments to high and low 32-bit * words and performing four multiplications. The performance of this * solution would be not very good.

* * Another approach is to use longs only for getting the lowest * 64 bits of the result. Casting the operands to double and * multiplying as floating-point numbers, we can get the highest (roughly) 52 * bits of the result. However since only 116 bits can be acquired this * way, it would be possible to only use 58 bits in each of the multiplication * operands (not the full 64 or 63 bits). Furthermore, round-off errors in * the floating-point multiplications, as allowed by the IEEE specification, * actually prevent getting even 52 of the top bits accurately, and actually * only 57 bits can be used in the multiplication operands. This is the * approach chosen in this implementation.

* * The first observation is that since the modulus is practically * constant, it should be more efficient to calculate (once) the inverse * of the modulus, and then subsequently multiply by the inverse modulus * instead of dividing by the modulus.

* * The second observation is that to get the remainder of the division, * we don't necessarily need the actual result of the division (we just * want the remainder). So, we should discard the topmost 50 bits of the * full 114-bit result whenever possible, to save a few operations.

* * The basic approach is to get an approximation of a * b / modulus * (using floating-point operands, that is doubles). The approximation * should be within +1 or -1 of the correct result. We first calculate * a * b - approximateDivision * modulus to get the initial remainder. * This calculation can use the lowest 64 bits only and is done using longs. * It is enough to use a double to do the approximate division, as it eliminates * at least 51 bits from the top of the 114-bit multiplication result, leaving at * most 63 bits in the remainder. The calculation result - approximateDivision * modulus * must then be done once more to reduce the remainder since the original multiplication operands * are only 57-bit numbers. The second reduction reduces the results to the correct value ±modulus. * It is then easy to detect the case when the approximate division was off by one (and the * remainder is ±modulus off) as the final step of the algorithm. * * @version 1.0 * @author Mikko Tommila */ public class LongElementaryModMath { /** * Default constructor. */ public LongElementaryModMath() { } /** * Modular multiplication. * * @param a First operand. * @param b Second operand. * * @return a * b % modulus */ public final long modMultiply(long a, long b) { long r = a * b - this.modulus * (long) ((double) a * (double) b * this.inverseModulus); r -= this.modulus * (int) ((double) r * this.inverseModulus); r = (r >= this.modulus ? r - this.modulus : r); r = (r < 0 ? r + this.modulus : r); return r; } /** * Modular addition. * * @param a First operand. * @param b Second operand. * * @return (a + b) % modulus */ public final long modAdd(long a, long b) { long r = a + b; return (r >= this.modulus ? r - this.modulus : r); } /** * Modular subtraction. The result is always >= 0. * * @param a First operand. * @param b Second operand. * * @return (a - b + modulus) % modulus */ public final long modSubtract(long a, long b) { long r = a - b; return (r < 0 ? r + this.modulus : r); } /** * Get the modulus. * * @return The modulus. */ public final long getModulus() { return this.modulus; } /** * Set the modulus. * * @param modulus The modulus. */ public final void setModulus(long modulus) { this.inverseModulus = 1.0 / modulus; this.modulus = modulus; } private long modulus; private double inverseModulus; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/LongModConstants.java000066400000000000000000000043071461767713300274600ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants needed for various modular arithmetic operations for the long type. * * @version 1.0 * @author Mikko Tommila */ public interface LongModConstants { /** * Moduli to be used in number theoretic transforms. * Allows transform lengths upto 3*247. */ public static final long MODULUS[] = { 136796838681378817L, 127508164449927169L, 119063915148607489L }; /** * Primitive roots for the corresponding moduli. */ public static final long PRIMITIVE_ROOT[] = { 5, 14, 26 }; /** * Maximum transform length for the moduli. */ public static final long MAX_TRANSFORM_LENGTH = 422212465065984L; /** * Maximum bits in a power-of-two base that fits in a long. */ public static final int MAX_POWER_OF_TWO_BITS = 57; /** * Maximum power-of-two base that fits in a long. */ public static final long MAX_POWER_OF_TWO_BASE = 1L << MAX_POWER_OF_TWO_BITS; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/LongRadixConstants.java000066400000000000000000000335541461767713300300160ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Constants related to different radixes for the long data type. * * @version 1.0 * @author Mikko Tommila */ public interface LongRadixConstants { /** * Bases for radixes 2, ..., 36. The base is the radix to the maximum power * so that the base is less than all moduli used. */ public static final long BASE[] = { (long) -1L, (long) -1L, (long) 72057594037927936L, (long) 50031545098999707L, (long) 72057594037927936L, (long) 59604644775390625L, (long) 21936950640377856L, (long) 79792266297612001L, (long) 18014398509481984L, (long) 16677181699666569L, (long) 100000000000000000L, (long) 45949729863572161L, (long) 15407021574586368L, (long) 51185893014090757L, (long) 11112006825558016L, (long) 29192926025390625L, (long) 72057594037927936L, (long) 9904578032905937L, (long) 20822964865671168L, (long) 42052983462257059L, (long) 81920000000000000L, (long) 7355827511386641L, (long) 12855002631049216L, (long) 21914624432020321L, (long) 36520347436056576L, (long) 59604644775390625L, (long) 95428956661682176L, (long) 5559060566555523L, (long) 8293509467471872L, (long) 12200509765705829L, (long) 17714700000000000L, (long) 25408476896404831L, (long) 36028797018963968L, (long) 50542106513726817L, (long) 70188843638032384L, (long) 96549157373046875L, (long) 3656158440062976L }; /** * The power of the radix in each base. */ public static final int BASE_DIGITS[] = { -1, -1, 56, 35, 28, 24, 21, 20, 18, 17, 17, 16, 15, 15, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, 11, 10 }; /** * The minimum number in each radix to have the specified amount of digits. */ public static final long MINIMUM_FOR_DIGITS[][] = { null, null, { (long) 1L, (long) 2L, (long) 4L, (long) 8L, (long) 16L, (long) 32L, (long) 64L, (long) 128L, (long) 256L, (long) 512L, (long) 1024L, (long) 2048L, (long) 4096L, (long) 8192L, (long) 16384L, (long) 32768L, (long) 65536L, (long) 131072L, (long) 262144L, (long) 524288L, (long) 1048576L, (long) 2097152L, (long) 4194304L, (long) 8388608L, (long) 16777216L, (long) 33554432L, (long) 67108864L, (long) 134217728L, (long) 268435456L, (long) 536870912L, (long) 1073741824L, (long) 2147483648L, (long) 4294967296L, (long) 8589934592L, (long) 17179869184L, (long) 34359738368L, (long) 68719476736L, (long) 137438953472L, (long) 274877906944L, (long) 549755813888L, (long) 1099511627776L, (long) 2199023255552L, (long) 4398046511104L, (long) 8796093022208L, (long) 17592186044416L, (long) 35184372088832L, (long) 70368744177664L, (long) 140737488355328L, (long) 281474976710656L, (long) 562949953421312L, (long) 1125899906842624L, (long) 2251799813685248L, (long) 4503599627370496L, (long) 9007199254740992L, (long) 18014398509481984L, (long) 36028797018963968L }, { (long) 1L, (long) 3L, (long) 9L, (long) 27L, (long) 81L, (long) 243L, (long) 729L, (long) 2187L, (long) 6561L, (long) 19683L, (long) 59049L, (long) 177147L, (long) 531441L, (long) 1594323L, (long) 4782969L, (long) 14348907L, (long) 43046721L, (long) 129140163L, (long) 387420489L, (long) 1162261467L, (long) 3486784401L, (long) 10460353203L, (long) 31381059609L, (long) 94143178827L, (long) 282429536481L, (long) 847288609443L, (long) 2541865828329L, (long) 7625597484987L, (long) 22876792454961L, (long) 68630377364883L, (long) 205891132094649L, (long) 617673396283947L, (long) 1853020188851841L, (long) 5559060566555523L, (long) 16677181699666569L }, { (long) 1L, (long) 4L, (long) 16L, (long) 64L, (long) 256L, (long) 1024L, (long) 4096L, (long) 16384L, (long) 65536L, (long) 262144L, (long) 1048576L, (long) 4194304L, (long) 16777216L, (long) 67108864L, (long) 268435456L, (long) 1073741824L, (long) 4294967296L, (long) 17179869184L, (long) 68719476736L, (long) 274877906944L, (long) 1099511627776L, (long) 4398046511104L, (long) 17592186044416L, (long) 70368744177664L, (long) 281474976710656L, (long) 1125899906842624L, (long) 4503599627370496L, (long) 18014398509481984L }, { (long) 1L, (long) 5L, (long) 25L, (long) 125L, (long) 625L, (long) 3125L, (long) 15625L, (long) 78125L, (long) 390625L, (long) 1953125L, (long) 9765625L, (long) 48828125L, (long) 244140625L, (long) 1220703125L, (long) 6103515625L, (long) 30517578125L, (long) 152587890625L, (long) 762939453125L, (long) 3814697265625L, (long) 19073486328125L, (long) 95367431640625L, (long) 476837158203125L, (long) 2384185791015625L, (long) 11920928955078125L }, { (long) 1L, (long) 6L, (long) 36L, (long) 216L, (long) 1296L, (long) 7776L, (long) 46656L, (long) 279936L, (long) 1679616L, (long) 10077696L, (long) 60466176L, (long) 362797056L, (long) 2176782336L, (long) 13060694016L, (long) 78364164096L, (long) 470184984576L, (long) 2821109907456L, (long) 16926659444736L, (long) 101559956668416L, (long) 609359740010496L, (long) 3656158440062976L }, { (long) 1L, (long) 7L, (long) 49L, (long) 343L, (long) 2401L, (long) 16807L, (long) 117649L, (long) 823543L, (long) 5764801L, (long) 40353607L, (long) 282475249L, (long) 1977326743L, (long) 13841287201L, (long) 96889010407L, (long) 678223072849L, (long) 4747561509943L, (long) 33232930569601L, (long) 232630513987207L, (long) 1628413597910449L, (long) 11398895185373143L }, { (long) 1L, (long) 8L, (long) 64L, (long) 512L, (long) 4096L, (long) 32768L, (long) 262144L, (long) 2097152L, (long) 16777216L, (long) 134217728L, (long) 1073741824L, (long) 8589934592L, (long) 68719476736L, (long) 549755813888L, (long) 4398046511104L, (long) 35184372088832L, (long) 281474976710656L, (long) 2251799813685248L }, { (long) 1L, (long) 9L, (long) 81L, (long) 729L, (long) 6561L, (long) 59049L, (long) 531441L, (long) 4782969L, (long) 43046721L, (long) 387420489L, (long) 3486784401L, (long) 31381059609L, (long) 282429536481L, (long) 2541865828329L, (long) 22876792454961L, (long) 205891132094649L, (long) 1853020188851841L }, { (long) 1L, (long) 10L, (long) 100L, (long) 1000L, (long) 10000L, (long) 100000L, (long) 1000000L, (long) 10000000L, (long) 100000000L, (long) 1000000000L, (long) 10000000000L, (long) 100000000000L, (long) 1000000000000L, (long) 10000000000000L, (long) 100000000000000L, (long) 1000000000000000L, (long) 10000000000000000L }, { (long) 1L, (long) 11L, (long) 121L, (long) 1331L, (long) 14641L, (long) 161051L, (long) 1771561L, (long) 19487171L, (long) 214358881L, (long) 2357947691L, (long) 25937424601L, (long) 285311670611L, (long) 3138428376721L, (long) 34522712143931L, (long) 379749833583241L, (long) 4177248169415651L }, { (long) 1L, (long) 12L, (long) 144L, (long) 1728L, (long) 20736L, (long) 248832L, (long) 2985984L, (long) 35831808L, (long) 429981696L, (long) 5159780352L, (long) 61917364224L, (long) 743008370688L, (long) 8916100448256L, (long) 106993205379072L, (long) 1283918464548864L }, { (long) 1L, (long) 13L, (long) 169L, (long) 2197L, (long) 28561L, (long) 371293L, (long) 4826809L, (long) 62748517L, (long) 815730721L, (long) 10604499373L, (long) 137858491849L, (long) 1792160394037L, (long) 23298085122481L, (long) 302875106592253L, (long) 3937376385699289L }, { (long) 1L, (long) 14L, (long) 196L, (long) 2744L, (long) 38416L, (long) 537824L, (long) 7529536L, (long) 105413504L, (long) 1475789056L, (long) 20661046784L, (long) 289254654976L, (long) 4049565169664L, (long) 56693912375296L, (long) 793714773254144L }, { (long) 1L, (long) 15L, (long) 225L, (long) 3375L, (long) 50625L, (long) 759375L, (long) 11390625L, (long) 170859375L, (long) 2562890625L, (long) 38443359375L, (long) 576650390625L, (long) 8649755859375L, (long) 129746337890625L, (long) 1946195068359375L }, { (long) 1L, (long) 16L, (long) 256L, (long) 4096L, (long) 65536L, (long) 1048576L, (long) 16777216L, (long) 268435456L, (long) 4294967296L, (long) 68719476736L, (long) 1099511627776L, (long) 17592186044416L, (long) 281474976710656L, (long) 4503599627370496L }, { (long) 1L, (long) 17L, (long) 289L, (long) 4913L, (long) 83521L, (long) 1419857L, (long) 24137569L, (long) 410338673L, (long) 6975757441L, (long) 118587876497L, (long) 2015993900449L, (long) 34271896307633L, (long) 582622237229761L }, { (long) 1L, (long) 18L, (long) 324L, (long) 5832L, (long) 104976L, (long) 1889568L, (long) 34012224L, (long) 612220032L, (long) 11019960576L, (long) 198359290368L, (long) 3570467226624L, (long) 64268410079232L, (long) 1156831381426176L }, { (long) 1L, (long) 19L, (long) 361L, (long) 6859L, (long) 130321L, (long) 2476099L, (long) 47045881L, (long) 893871739L, (long) 16983563041L, (long) 322687697779L, (long) 6131066257801L, (long) 116490258898219L, (long) 2213314919066161L }, { (long) 1L, (long) 20L, (long) 400L, (long) 8000L, (long) 160000L, (long) 3200000L, (long) 64000000L, (long) 1280000000L, (long) 25600000000L, (long) 512000000000L, (long) 10240000000000L, (long) 204800000000000L, (long) 4096000000000000L }, { (long) 1L, (long) 21L, (long) 441L, (long) 9261L, (long) 194481L, (long) 4084101L, (long) 85766121L, (long) 1801088541L, (long) 37822859361L, (long) 794280046581L, (long) 16679880978201L, (long) 350277500542221L }, { (long) 1L, (long) 22L, (long) 484L, (long) 10648L, (long) 234256L, (long) 5153632L, (long) 113379904L, (long) 2494357888L, (long) 54875873536L, (long) 1207269217792L, (long) 26559922791424L, (long) 584318301411328L }, { (long) 1L, (long) 23L, (long) 529L, (long) 12167L, (long) 279841L, (long) 6436343L, (long) 148035889L, (long) 3404825447L, (long) 78310985281L, (long) 1801152661463L, (long) 41426511213649L, (long) 952809757913927L }, { (long) 1L, (long) 24L, (long) 576L, (long) 13824L, (long) 331776L, (long) 7962624L, (long) 191102976L, (long) 4586471424L, (long) 110075314176L, (long) 2641807540224L, (long) 63403380965376L, (long) 1521681143169024L }, { (long) 1L, (long) 25L, (long) 625L, (long) 15625L, (long) 390625L, (long) 9765625L, (long) 244140625L, (long) 6103515625L, (long) 152587890625L, (long) 3814697265625L, (long) 95367431640625L, (long) 2384185791015625L }, { (long) 1L, (long) 26L, (long) 676L, (long) 17576L, (long) 456976L, (long) 11881376L, (long) 308915776L, (long) 8031810176L, (long) 208827064576L, (long) 5429503678976L, (long) 141167095653376L, (long) 3670344486987776L }, { (long) 1L, (long) 27L, (long) 729L, (long) 19683L, (long) 531441L, (long) 14348907L, (long) 387420489L, (long) 10460353203L, (long) 282429536481L, (long) 7625597484987L, (long) 205891132094649L }, { (long) 1L, (long) 28L, (long) 784L, (long) 21952L, (long) 614656L, (long) 17210368L, (long) 481890304L, (long) 13492928512L, (long) 377801998336L, (long) 10578455953408L, (long) 296196766695424L }, { (long) 1L, (long) 29L, (long) 841L, (long) 24389L, (long) 707281L, (long) 20511149L, (long) 594823321L, (long) 17249876309L, (long) 500246412961L, (long) 14507145975869L, (long) 420707233300201L }, { (long) 1L, (long) 30L, (long) 900L, (long) 27000L, (long) 810000L, (long) 24300000L, (long) 729000000L, (long) 21870000000L, (long) 656100000000L, (long) 19683000000000L, (long) 590490000000000L }, { (long) 1L, (long) 31L, (long) 961L, (long) 29791L, (long) 923521L, (long) 28629151L, (long) 887503681L, (long) 27512614111L, (long) 852891037441L, (long) 26439622160671L, (long) 819628286980801L }, { (long) 1L, (long) 32L, (long) 1024L, (long) 32768L, (long) 1048576L, (long) 33554432L, (long) 1073741824L, (long) 34359738368L, (long) 1099511627776L, (long) 35184372088832L, (long) 1125899906842624L }, { (long) 1L, (long) 33L, (long) 1089L, (long) 35937L, (long) 1185921L, (long) 39135393L, (long) 1291467969L, (long) 42618442977L, (long) 1406408618241L, (long) 46411484401953L, (long) 1531578985264449L }, { (long) 1L, (long) 34L, (long) 1156L, (long) 39304L, (long) 1336336L, (long) 45435424L, (long) 1544804416L, (long) 52523350144L, (long) 1785793904896L, (long) 60716992766464L, (long) 2064377754059776L }, { (long) 1L, (long) 35L, (long) 1225L, (long) 42875L, (long) 1500625L, (long) 52521875L, (long) 1838265625L, (long) 64339296875L, (long) 2251875390625L, (long) 78815638671875L, (long) 2758547353515625L }, { (long) 1L, (long) 36L, (long) 1296L, (long) 46656L, (long) 1679616L, (long) 60466176L, (long) 2176782336L, (long) 78364164096L, (long) 2821109907456L, (long) 101559956668416L } }; /** * Maximum allowed exponent for each radix. */ public static final long MAX_EXPONENT[] = { -1L, -1L, 164703072086692419L, 263524915338707874L, 329406144173384844L, 384307168202282319L, 439208192231179794L, 461168601842738784L, 512409557603043094L, 542551296285575041L, 542551296285575041L, 576460752303423481L, 614891469123651714L, 614891469123651714L, 658812288346769694L, 658812288346769694L, 658812288346769694L, 709490156681136594L, 709490156681136594L, 709490156681136594L, 709490156681136594L, 768614336404564644L, 768614336404564644L, 768614336404564644L, 768614336404564644L, 768614336404564644L, 768614336404564644L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 838488366986797794L, 922337203685477574L }; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/MessagePasser.java000066400000000000000000000064551461767713300267740ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Map; import java.util.HashMap; import org.apfloat.ApfloatInterruptedException; import org.apfloat.ApfloatRuntimeException; /** * Message passing helper class for parallel codes. * The message passer can hold one message for each receiver. * This class is safe for concurrent use from multiple threads. * * @param The receiver type for this message passer. * @param The message type for this message passer. * * @since 1.6 * @version 1.14.0 * @author Mikko Tommila */ public class MessagePasser { private Map messages; /** * Default constructor. */ public MessagePasser() { this.messages = new HashMap<>(); } /** * Send a message. * * @param receiver The receiver. * @param message The message. Must not be null. */ public synchronized void sendMessage(K receiver, V message) { assert (message != null); assert (!this.messages.containsKey(receiver)); this.messages.put(receiver, message); notifyAll(); } /** * Get a message if one is available. This method will not block. * * @param receiver The receiver. * * @return The message, or null if none is available. */ public synchronized V getMessage(K receiver) { V message = this.messages.remove(receiver); return message; } /** * Receive a message. This method will block until a message is available. * * @param receiver The receiver. * * @return The message. */ public synchronized V receiveMessage(K receiver) throws ApfloatRuntimeException { V message; while ((message = this.messages.remove(receiver)) == null) { try { wait(); } catch (InterruptedException ie) { throw new ApfloatInterruptedException("Wait for received message interrupted", ie); } } return message; } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/ParallelExecutionBuilder.java000066400000000000000000000033121461767713300311460ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.ExecutionBuilder; import org.apfloat.spi.ExecutionStrategy; /** * Returns an execution strategy using the {@link ParallelRunner}. * * @since 1.9.0 * @version 1.9.0 * @author Mikko Tommila */ public class ParallelExecutionBuilder implements ExecutionBuilder { @Override public ExecutionStrategy createExecution() { return ParallelExecutionBuilder.executionStrategy; } private static ExecutionStrategy executionStrategy = new ParallelExecutionStrategy(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/ParallelExecutionStrategy.java000066400000000000000000000031031461767713300313600ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.concurrent.Future; import org.apfloat.spi.ExecutionStrategy; /** * Execution strategy using the {@link ParallelRunner}. * * @since 1.9.0 * @version 1.9.0 * @author Mikko Tommila */ public class ParallelExecutionStrategy implements ExecutionStrategy { @Override public void wait(Future future) { ParallelRunner.wait(future); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/ParallelRunnable.java000066400000000000000000000147641461767713300274570ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.concurrent.atomic.AtomicLong; import org.apfloat.ApfloatContext; import org.apfloat.spi.Util; /** * Abstract class for a Runnable that can be run in parallel by * multiple threads. Internally, the ParallelRunnable splits the * work to many small batches, which are run one at a time, and can be run in * parallel by multiple threads. The ParallelRunnable isn't * completed until all batches are completed, i.e. the {@link #run()} method * only returns when all batches are completed. * * @since 1.1 * @version 1.14.0 * @author Mikko Tommila */ public abstract class ParallelRunnable implements Runnable { /** * Subclass constructor. * * @param length The length of the work to be run. */ protected ParallelRunnable(long length) { // Set the batch size to be some balanced value with respect to the batch size and the number of batches this.preferredBatchSize = Util.sqrt4down(length); this.length = length; this.started = new AtomicLong(); this.completed = new AtomicLong(); } /** * Repeatedly get a batch of work and run it, until all batches are * completed. This method can (and should) be called from multiple * threads in parallel. */ @Override public final void run() { // Run batches as long as there are any available while (runBatch()); // Wait until all batches are completed (the above only says all batches were started) // Note that accessing this atomic variable also ensures that memory writes in other // threads have happened-before we get here and see that the task is completed while (isWorkToBeCompleted()) { ApfloatContext.checkInterrupted(); Thread.yield(); // Do not waste time } } /** * Run one batch if available. Returns true if a batch was * actually acquired and run, false if all batches were * already started and none could be run. This method can be used by any * thread to steal and complete a minimal amount of work.

* * Note that if a batch could not be run, it does not mean that all of * the batches are already completed - some could still be running. * * @return If a batch was actually run. */ public final boolean runBatch() { ApfloatContext.checkInterrupted(); boolean isRun = false; if (isWorkToBeStarted()) { long batchSize = Math.max(MINIMUM_BATCH_SIZE, getPreferredBatchSize()); long startValue = this.started.getAndAdd(batchSize); long length = Math.min(batchSize, this.length - startValue); if (length > 0) { Runnable runnable = getRunnable(startValue, length); runnable.run(); // This ensures that all memory writes in the Runnable happen-before other threads can see that the batch was completed this.completed.addAndGet(length); isRun = true; } } return isRun; } /** * Returns if there is still enough work left to start a new batch. * * @return If a new batch could be started to still perform some work. * * @since 1.9.0 */ public boolean isWorkToBeStarted() { return this.started.get() < this.length; } /** * Returns if there is some work that may be currently processed but not yet finished. * * @return If there is still some work left that is not completed yet. * * @since 1.9.0 */ public boolean isWorkToBeCompleted() { return this.completed.get() < this.length; } /** * Get the Runnable object for strides which fit in an int. * * @param startValue The starting value for the stride. * @param length The length of the stride. * * @return The Runnable object for the specified stride. */ protected Runnable getRunnable(int startValue, int length) { throw new UnsupportedOperationException("Not implemented"); } /** * Get the Runnable object for strides which fit only in a long. * * @param startValue The starting value for the stride. * @param length The length of the stride. * * @return The Runnable object for the specified stride. */ protected Runnable getRunnable(long startValue, long length) { if (startValue <= Integer.MAX_VALUE - length) // Avoid overflow { return getRunnable((int) startValue, (int) length); } else { throw new UnsupportedOperationException("Not implemented"); } } /** * Get the preferred batch size. * * @return The preferred batch size. * * @since 1.7.0 */ protected long getPreferredBatchSize() { return this.preferredBatchSize; } private static final int MINIMUM_BATCH_SIZE = 16; private long length; private long preferredBatchSize; private AtomicLong started; private AtomicLong completed; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/ParallelRunner.java000066400000000000000000000121771461767713300271560ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.ArrayList; import java.util.List; import java.util.Queue; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.FutureTask; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatInterruptedException; import org.apfloat.ApfloatRuntimeException; /** * Class for running ParallelRunnable objects in parallel using * multiple threads.

* * The ParallelRunner assumes that the current {@link ApfloatContext} returns an * ExecutorService that is limited to a number of threads that is * one less than the number of processors. This way, when also the current thread * runs batches from the ParallelRunnable, CPU utilization should be * maximized but only so that no more threads are actively executing than the * number of processors. * * @since 1.1 * @version 1.14.0 * @author Mikko Tommila */ public class ParallelRunner { private ParallelRunner() { } /** * Run a ParallelRunnable object in parallel using multiple threads. * The method assumes that the ExecutorService returned from * {@link ApfloatContext#getExecutorService()} is limited to using one * thread less than the number of processors. This maximizes CPU usage, * When the ParallelRunnable is also run from the current thread. * * @param parallelRunnable The ParallelRunnable to be run. */ public static void runParallel(ParallelRunnable parallelRunnable) throws ApfloatRuntimeException { ParallelRunner.tasks.add(parallelRunnable); try { runTasks(parallelRunnable); } finally { ParallelRunner.tasks.remove(parallelRunnable); } } /** * While waiting for a Future to be completed, steal a minimal * amount of work from any running task and run it. * * @param future The Future to wait for. */ public static void wait(Future future) { Runnable stealer = () -> { while (!future.isDone()) { // Try and get any running task ParallelRunnable parallelRunnable = ParallelRunner.tasks.peek(); if (parallelRunnable != null) { // Steal a minimal amount of work while we wait parallelRunnable.runBatch(); } else { // Actually idle - give up the rest of the CPU time slice Thread.yield(); } } }; runTasks(stealer); } private static void runTasks(Runnable runnable) { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); List> futures = new ArrayList<>(); if (numberOfProcessors > 1) { ExecutorService executorService = ctx.getExecutorService(); for (int i = 0; i < numberOfProcessors - 1; i++) { // Process the task also in other threads FutureTask futureTask = new FutureTask<>(runnable, null); executorService.execute(futureTask); futures.add(futureTask); } } // Also process the task in the current thread, until it is finished try { runnable.run(); } catch (ApfloatInterruptedException aie) { futures.forEach(future -> future.cancel(true)); throw aie; } } // Implemented as a List because the assumption is that the number of concurrent tasks is very small private static Queue tasks = new ConcurrentLinkedQueue<>(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/ParallelThreeNTTConvolutionStrategy.java000066400000000000000000000116571461767713300333270ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import org.apfloat.ApfloatContext; import org.apfloat.spi.NTTStrategy; /** * Convolution using three Number Theoretic Transforms * and the CRT to get the final result, using multiple threads in parallel.

* * This algorithm is parallelized so that all operations are done in parallel * using multiple threads, if the number of processors is greater than one * in {@link ApfloatContext#getNumberOfProcessors()}.

* * If the data block to be transformed is larger than the shared memory threshold setting * in the current ApfloatContext, this class will synchronize all data access on * the shared memory lock retrieved from {@link ApfloatContext#getSharedMemoryLock()}.

* * All access to this class must be externally synchronized. * * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class ParallelThreeNTTConvolutionStrategy extends ThreeNTTConvolutionStrategy { private static class LockFuture extends FutureTask { public LockFuture(Lock lock) { super(VOID_CALLABLE); this.thread = Thread.currentThread(); // Store the calling thread as the lock (and unlock) is thread-specific this.lock = lock; } @Override public synchronized boolean isDone() { if (!this.done && Thread.currentThread().equals(this.thread)) // Only the thread making the wait(Future) call should lock the lock, as it will unlock it also { this.done = this.lock.tryLock(); } return this.done; } private static final Callable VOID_CALLABLE = () -> null; private Thread thread; private Lock lock; private boolean done; } /** * Creates a new convoluter that uses the specified * transform for transforming the data. * * @param radix The radix to be used. * @param nttStrategy The transform to be used. */ public ParallelThreeNTTConvolutionStrategy(int radix, NTTStrategy nttStrategy) { super(radix, nttStrategy); } @Override protected void lock(long length) { assert(this.key == null); if (super.nttStrategy instanceof Parallelizable && super.carryCRTStrategy instanceof Parallelizable && super.stepStrategy instanceof Parallelizable) { ApfloatContext ctx = ApfloatContext.getContext(); if (length > ctx.getSharedMemoryTreshold() / ctx.getBuilderFactory().getElementSize()) { // Data size is big: synchronize on shared memory lock this.key = ctx.getSharedMemoryLock(); if (this.key != null) { Lock lock; synchronized (ParallelThreeNTTConvolutionStrategy.locks) { lock = ParallelThreeNTTConvolutionStrategy.locks.computeIfAbsent(this.key, k -> new ReentrantLock()); } ctx.wait(new LockFuture(lock)); } } } } @Override protected void unlock() { if (this.key != null) { synchronized (ParallelThreeNTTConvolutionStrategy.locks) { ParallelThreeNTTConvolutionStrategy.locks.get(this.key).unlock(); } } } private static Map locks = new WeakHashMap<>(); private Object key; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/Parallelizable.java000066400000000000000000000025701461767713300271470ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Any task that can use a {@link ParallelRunner} to execute operations in parallel. * * @since 1.7.0 * @version 1.8.0 * @author Mikko Tommila */ public interface Parallelizable { } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/RadixMismatchException.java000066400000000000000000000051161461767713300306370ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Exception indicating a different radix being used in two operands * of a calculation.

* * While it's possible to convert numbers to different radixes using the * toRadix() methods, this is highly inefficient. If numbers * of different radixes need to be used in a calculation, they should be * explicitly converted to matching radixes before attempting the calculation. * Otherwise this exception should be thrown. * * @since 1.5 * @version 1.5 * @author Mikko Tommila */ public class RadixMismatchException extends ApfloatInternalException { /** * Constructs a new apfloat radix mismatch exception with an empty detail message. */ public RadixMismatchException() { } /** * Constructs a new apfloat radix mismatch exception with the specified detail message. * * @param message The detail message. */ public RadixMismatchException(String message) { super(message); } /** * Constructs a new apfloat radix mismatch exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public RadixMismatchException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/Scramble.java000066400000000000000000000063421461767713300257550ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.Util; /** * Functions to perform bit-reverse ordering of data. * * @version 1.0 * @author Mikko Tommila */ public class Scramble { private Scramble() { } /** * Permute the bits of a number to reverse order.

* * For example, if n is 5 and the transform * length is 256, the permutation is (in binary)

* * 00000101 → 10100000 * * @param n The number whose bits to reverse. * @param length The FFT transform length for which the bit reversal to perform. * * @return The bits of n reversed. */ public static int permute(int n, int length) { assert (length == (length & -length)); int p = 1; while (p < length) { p += p + (n & 1); n >>= 1; } return p - length; } /** * Create a table of indexes for scrambling an array for FFT.

* * The returned table contains pairs of indexes that should be swapped * to scramble an array. For example, for transform length 8 the * returned table contains { 1, 4, 3, 6 } to indicate * that the array elements [1] and [4] should be swapped, and the elements * [3] and [6] should be swapped. * * @param length The FFT transform length for which the scrambling table is created. * * @return An array of pairs of indexes that indicate, which array elements should be swapped to scramble the array. */ public static int[] createScrambleTable(int length) { assert (length == (length & -length)); int[] scrambleTable = new int[length - Util.sqrt4up(length)]; for (int i = 0, k = 0; i < length; i++) { int j = permute(i, length); if (j < i) { scrambleTable[k] = i; scrambleTable[k + 1] = j; k += 2; } } return scrambleTable; } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/SixStepFNTStrategy.java000066400000000000000000000264711461767713300277240ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.MatrixStrategy; /** * Fast Number Theoretic Transform that uses a "six-step" * algorithm to calculate a long transform more efficiently on * cache-based memory architectures.

* * When the data to be transformed is considered to be an * n1 x n2 matrix of data, instead of a linear array, * the six steps are as follows: * *

    *
  1. Transpose the matrix.
  2. *
  3. Transform the rows.
  4. *
  5. Transpose the matrix.
  6. *
  7. Multiply each matrix element by wi j (where w is the n:th root of unity).
  8. *
  9. Transform the rows.
  10. *
  11. Transpose the matrix.
  12. *
*

* * In a convolution algorithm the last transposition step can be omitted * to increase performance, as well as the first transposition step in * the inverse transform. The convolution's element-by-element multiplication * is not sensitive to the order in which the elements are. * Also scrambling the data can be omitted.

* * All access to this class must be externally synchronized. * * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class SixStepFNTStrategy extends AbstractStepFNTStrategy { /** * Default constructor. */ public SixStepFNTStrategy() { ApfloatContext ctx = ApfloatContext.getContext(); this.matrixStrategy = ctx.getBuilderFactory().getMatrixBuilder().createMatrix(); } @Override protected void transform(DataStorage dataStorage, int n1, int n2, long length, int modulus) throws ApfloatRuntimeException { if (length > Integer.MAX_VALUE) { throw new ApfloatInternalException("Maximum array length exceeded: " + length); } assert (n2 >= n1); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ_WRITE, 0, (int) length)) { preTransform(arrayAccess); // Step 1: Transpose the data transposeInitial(arrayAccess, n1, n2, false); // Step 2: Do n2 transforms of length n1 transformFirst(arrayAccess, n1, n2, false, modulus); // Step 3: Transpose the data transposeMiddle(arrayAccess, n2, n1, false); // Step 4: Multiply each matrix element by w^(i*j) multiplyElements(arrayAccess, n1, n2, length, 1, false, modulus); // Step 5: Do n1 transforms of length n2 transformSecond(arrayAccess, n2, n1, false, modulus); // Step 6: Transpose the data - omitted as unnecessary transposeFinal(arrayAccess, n1, n2, false); postTransform(arrayAccess); } } @Override protected void inverseTransform(DataStorage dataStorage, int n1, int n2, long length, long totalTransformLength, int modulus) throws ApfloatRuntimeException { if (length > Integer.MAX_VALUE) { throw new ApfloatInternalException("Maximum array length exceeded: " + length); } assert (n2 >= n1); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ_WRITE, 0, (int) length)) { preTransform(arrayAccess); // Step 1: Transpose the data - omitted as unnecessary transposeFinal(arrayAccess, n2, n1, true); // Step 2: Do n1 transforms of length n2 transformSecond(arrayAccess, n2, n1, true, modulus); // Step 3: Multiply each matrix element by w^(i*j) / totalTransformLength multiplyElements(arrayAccess, n1, n2, length, totalTransformLength, true, modulus); // Step 4: Transpose the data transposeMiddle(arrayAccess, n1, n2, true); // Step 5: Do n2 transforms of length n1 transformFirst(arrayAccess, n1, n2, true, modulus); // Step 6: Transpose the data transposeInitial(arrayAccess, n2, n1, true); postTransform(arrayAccess); } } /** * Prepare the data for the (inverse) transform. * * @param arrayAccess The data to prepare. */ protected void preTransform(ArrayAccess arrayAccess) { // By default does nothing } /** * The initial transpose of the forward transform, or the final transpose * of the inverse transform, to transpose the columns of the matrix to be rows. * This step is needed in the six-step algorithm but is omitted in the four-step * algorithm. * * @param arrayAccess Accessor to the matrix data. This data will be transposed. * @param n1 Number of rows in the matrix. * @param n2 Number of columns in the matrix. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. */ protected void transposeInitial(ArrayAccess arrayAccess, int n1, int n2, boolean isInverse) { this.matrixStrategy.transpose(arrayAccess, n1, n2); } /** * The second transpose of either the forward or inverse transform. Normally * this step is always required as the four-step algorithm only transforms * columns of the matrix and the six-step algorithm transforms only rows. * * @param arrayAccess Accessor to the matrix data. This data will be transposed. * @param n1 Number of rows in the matrix. * @param n2 Number of columns in the matrix. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. */ protected void transposeMiddle(ArrayAccess arrayAccess, int n1, int n2, boolean isInverse) { this.matrixStrategy.transpose(arrayAccess, n1, n2); } /** * The final transpose of the forward transform, or the initial transpose * of the inverse transform. By default this method does nothing as the step is * always unnecessary when the data is only needed for convolution. * * @param arrayAccess Accessor to the matrix data. * @param n1 Number of rows in the matrix. * @param n2 Number of columns in the matrix. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. */ protected void transposeFinal(ArrayAccess arrayAccess, int n1, int n2, boolean isInverse) { // Omitted as unnecessary } /** * The first transform of the rows (or columns) of the data matrix. * In the default implementation the rows are transformed because in the * forward transform the matrix is transposed first. In the inverse transform * the matrix is initially in transposed form as it was left like that by the * forward transform.

* * By default the row transforms permute the data, leaving it in the correct * order so the element-by-element multiplication is simpler. * * @param arrayAccess The memory array to split and transform. * @param length Length of one transform (one row physically, by default). * @param count Number of transforms. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param modulus Index of the modulus. */ protected void transformFirst(ArrayAccess arrayAccess, int length, int count, boolean isInverse, int modulus) { super.stepStrategy.transformRows(arrayAccess, length, count, isInverse, true, modulus); } /** * The second transform of the rows (or columns) of the data matrix. * In the default implementation the rows are transformed because in the * forward transform the matrix is transposed first. In the inverse transform * the matrix is initially in transposed form as it was left like that by the * forward transform.

* * By default the row transforms do not permute the data, leaving it in * scrambled order, as this does not matter when the data is only used for * convolution. * * @param arrayAccess The memory array to split to rows and to transform. * @param length Length of one transform (one row). * @param count Number of rows. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param modulus Index of the modulus. */ protected void transformSecond(ArrayAccess arrayAccess, int length, int count, boolean isInverse, int modulus) { super.stepStrategy.transformRows(arrayAccess, length, count, isInverse, false, modulus); } /** * Multiply each matrix element by a power of the n:th root of unity. * * @param arrayAccess The memory array to multiply. * @param rows The number of rows in the arrayAccess to multiply. * @param columns The number of columns in the matrix (= n2). * @param length The length of data in the matrix being transformed. * @param totalTransformLength The total transform length, for the scaling factor. Used only for the inverse case. * @param isInverse If the multiplication is done for the inverse transform or not. * @param modulus Index of the modulus. */ protected void multiplyElements(ArrayAccess arrayAccess, int rows, int columns, long length, long totalTransformLength, boolean isInverse, int modulus) { super.stepStrategy.multiplyElements(arrayAccess, 0, 0, rows, columns, length, totalTransformLength, isInverse, modulus); } /** * Finish processing the data after the (inverse) transform. * * @param arrayAccess The data to finish. */ protected void postTransform(ArrayAccess arrayAccess) { // By default does nothing } /** * The matrix strategy. */ protected MatrixStrategy matrixStrategy; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/StepCarryCRTStrategy.java000066400000000000000000000230071461767713300302320ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.BuilderFactory; import org.apfloat.spi.CarryCRTStrategy; import org.apfloat.spi.CarryCRTStepStrategy; import org.apfloat.spi.DataStorageBuilder; import org.apfloat.spi.DataStorage; /** * Class for performing the final step of a three-modulus * Number Theoretic Transform based convolution. Works with blocks of data.

* * The algorithm is parallelized for multiprocessor computers, * if the data fits in memory.

* * The parallelization works so that the carry-CRT is done in * blocks in parallel. As a final step, a second pass is done * through the data set to propagate the carries from one block * to the next.

* * All access to this class must be externally synchronized. * * @see CarryCRTStepStrategy * * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class StepCarryCRTStrategy implements CarryCRTStrategy, Parallelizable { // Runnable for calculating the carry-CRT in blocks, then get the carry of the previous block, add it, and provide carry to the next block private class CarryCRTRunnable implements Runnable { public CarryCRTRunnable(DataStorage resultMod0, DataStorage resultMod1, DataStorage resultMod2, DataStorage dataStorage, long size, long resultSize, long offset, long length, MessagePasser messagePasser, CarryCRTStepStrategy stepStrategy) { this.resultMod0 = resultMod0; this.resultMod1 = resultMod1; this.resultMod2 = resultMod2; this.dataStorage = dataStorage; this.size = size; this.resultSize = resultSize; this.offset = offset; this.length = length; this.messagePasser = messagePasser; this.stepStrategy = stepStrategy; } @Override public void run() { T results = this.stepStrategy.crt(this.resultMod0, this.resultMod1, this.resultMod2, this.dataStorage, this.size, this.resultSize, this.offset, this.length); // Finishing step - get the carry from the previous block and propagate it through the data if (this.offset > 0) { T previousResults = this.messagePasser.receiveMessage(this.offset); results = this.stepStrategy.carry(this.dataStorage, this.size, this.resultSize, this.offset, this.length, results, previousResults); } // Finally, send the carry to the next block this.messagePasser.sendMessage(this.offset + this.length, results); // Last block sanity check if (this.offset + this.length == this.size) { assert (results != null); assert (java.lang.reflect.Array.getLength(results) == 2); assert (((Number) java.lang.reflect.Array.get(results, 0)).longValue() == 0); assert (((Number) java.lang.reflect.Array.get(results, 1)).longValue() == 0); } } private DataStorage resultMod0, resultMod1, resultMod2, dataStorage; private long size, resultSize, offset, length; private MessagePasser messagePasser; private CarryCRTStepStrategy stepStrategy; } /** * Creates a carry-CRT object using the specified radix. * * @param radix The radix that will be used. */ public StepCarryCRTStrategy(int radix) { this.radix = radix; } /** * Calculate the final result of a three-NTT convolution.

* * Performs a Chinese Remainder Theorem (CRT) on each element * of the three result data sets to get the result of each element * modulo the product of the three moduli. Then it calculates the carries * to get the final result.

* * Note that the return value's initial word may be zero or non-zero, * depending on how large the result is.

* * Assumes that MODULUS[0] > MODULUS[1] > MODULUS[2]. * * @param resultMod0 The result modulo MODULUS[0]. * @param resultMod1 The result modulo MODULUS[1]. * @param resultMod2 The result modulo MODULUS[2]. * @param resultSize The number of elements needed in the final result. * * @return The final result with the CRT performed and the carries calculated. */ @Override public DataStorage carryCRT(DataStorage resultMod0, DataStorage resultMod1, DataStorage resultMod2, long resultSize) throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); BuilderFactory builderFactory = ctx.getBuilderFactory(); Class elementArrayType = builderFactory.getElementArrayType(); return doCarryCRT(elementArrayType, resultMod0, resultMod1, resultMod2, resultSize); } private DataStorage doCarryCRT(Class elementArrayType, DataStorage resultMod0, DataStorage resultMod1, DataStorage resultMod2, long resultSize) throws ApfloatRuntimeException { long size = Math.min(resultSize + 2, resultMod0.getSize()); // Some extra precision if not full result is required ApfloatContext ctx = ApfloatContext.getContext(); BuilderFactory builderFactory = ctx.getBuilderFactory(); DataStorageBuilder dataStorageBuilder = builderFactory.getDataStorageBuilder(); DataStorage dataStorage = dataStorageBuilder.createDataStorage(resultSize * builderFactory.getElementSize()); dataStorage.setSize(resultSize); ParallelRunnable parallelRunnable = createCarryCRTParallelRunnable(elementArrayType, resultMod0, resultMod1, resultMod2, dataStorage, size, resultSize); if (size <= Integer.MAX_VALUE && // Only if the size fits in an integer, but with memory arrays it should resultMod0.isCached() && // Only if the data storage supports efficient parallel random access resultMod1.isCached() && resultMod2.isCached() && dataStorage.isCached()) { ParallelRunner.runParallel(parallelRunnable); } else { parallelRunnable.getRunnable(0, size).run(); // Just run in current thread without parallelization } return dataStorage; } /** * Create a ParallelRunnable object for doing the carry-CRT in parallel. * * @param The element array type used. * @param elementArrayType The element array type used. * @param resultMod0 The result modulo MODULUS[0]. * @param resultMod1 The result modulo MODULUS[1]. * @param resultMod2 The result modulo MODULUS[2]. * @param dataStorage The destination data storage of the computation. * @param size The number of elements in the whole data set. * @param resultSize The number of elements needed in the final result. * * @return An suitable object for performing the carry-CRT in parallel. */ protected ParallelRunnable createCarryCRTParallelRunnable(Class elementArrayType, DataStorage resultMod0, DataStorage resultMod1, DataStorage resultMod2, DataStorage dataStorage, long size, long resultSize) { ApfloatContext ctx = ApfloatContext.getContext(); BuilderFactory builderFactory = ctx.getBuilderFactory(); MessagePasser messagePasser = new MessagePasser<>(); CarryCRTStepStrategy stepStrategy = builderFactory.getCarryCRTBuilder(elementArrayType).createCarryCRTSteps(this.radix); ParallelRunnable parallelRunnable = new ParallelRunnable(size) { @Override public Runnable getRunnable(long offset, long length) { return new CarryCRTRunnable<>(resultMod0, resultMod1, resultMod2, dataStorage, size, resultSize, offset, length, messagePasser, stepStrategy); } }; return parallelRunnable; } private int radix; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/ThreeNTTConvolutionStrategy.java000066400000000000000000000205501461767713300316420ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.BuilderFactory; import org.apfloat.spi.CarryCRTStrategy; import org.apfloat.spi.ConvolutionStrategy; import org.apfloat.spi.NTTStrategy; import org.apfloat.spi.NTTConvolutionStepStrategy; import org.apfloat.spi.DataStorageBuilder; import org.apfloat.spi.DataStorage; /** * Convolution using three Number Theoretic Transforms * and the Chinese Remainder Theorem to get the final result.

* * Multiplication can be done in linear time in the transform domain, where * the multiplication is simply an element-by-element multiplication.

* * All access to this class must be externally synchronized. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public class ThreeNTTConvolutionStrategy implements ConvolutionStrategy { /** * Creates a new convoluter that uses the specified * transform for transforming the data. * * @param radix The radix to be used. * @param nttStrategy The transform to be used. */ public ThreeNTTConvolutionStrategy(int radix, NTTStrategy nttStrategy) { ApfloatContext ctx = ApfloatContext.getContext(); BuilderFactory builderFactory = ctx.getBuilderFactory(); this.nttStrategy = nttStrategy; this.carryCRTStrategy = builderFactory.getCarryCRTBuilder(builderFactory.getElementArrayType()).createCarryCRT(radix); this.stepStrategy = builderFactory.getNTTBuilder().createNTTConvolutionSteps(); } @Override public DataStorage convolute(DataStorage x, DataStorage y, long resultSize) throws ApfloatRuntimeException { if (x == y) { return autoConvolute(x, resultSize); } long length = this.nttStrategy.getTransformLength(x.getSize() + y.getSize()); DataStorage result; lock(length); try { DataStorage resultMod0 = convoluteOne(x, y, length, 0, false), resultMod1 = convoluteOne(x, y, length, 1, false), resultMod2 = convoluteOne(x, y, length, 2, true); result = this.carryCRTStrategy.carryCRT(resultMod0, resultMod1, resultMod2, resultSize); } finally { unlock(); } return result; } /** * Performs a convolution modulo one modulus, of the specified transform length. * * @param x First data set. * @param y Second data set. * @param length Length of the transformation. * @param modulus Which modulus to use. * @param cached If the result data should be kept cached in memory when possible. * * @return The result of the convolution for one modulus. */ protected DataStorage convoluteOne(DataStorage x, DataStorage y, long length, int modulus, boolean cached) throws ApfloatRuntimeException { DataStorage tmpY = createCachedDataStorage(length); tmpY.copyFrom(y, length); // Using a cached data storage here can avoid an extra write this.nttStrategy.transform(tmpY, modulus); tmpY = createDataStorage(tmpY); DataStorage tmpX = createCachedDataStorage(length); tmpX.copyFrom(x, length); this.nttStrategy.transform(tmpX, modulus); this.stepStrategy.multiplyInPlace(tmpX, tmpY, modulus); this.nttStrategy.inverseTransform(tmpX, modulus, length); tmpX = (cached ? tmpX : createDataStorage(tmpX)); return tmpX; } /** * Convolutes a data set with itself. * * @param x The data set. * @param resultSize Number of elements needed in the result data. * * @return The convolved data. */ protected DataStorage autoConvolute(DataStorage x, long resultSize) throws ApfloatRuntimeException { long length = this.nttStrategy.getTransformLength(x.getSize() * 2); DataStorage result; lock(length); try { DataStorage resultMod0 = autoConvoluteOne(x, length, 0, false), resultMod1 = autoConvoluteOne(x, length, 1, false), resultMod2 = autoConvoluteOne(x, length, 2, true); result = this.carryCRTStrategy.carryCRT(resultMod0, resultMod1, resultMod2, resultSize); } finally { unlock(); } return result; } /** * Performs an autoconvolution modulo one modulus, of the specified transform length. * * @param x The data set. * @param length Length of the transformation. * @param modulus Which modulus to use. * @param cached If the result data should be kept cached in memory when possible. * * @return The result of the convolution for one modulus. */ protected DataStorage autoConvoluteOne(DataStorage x, long length, int modulus, boolean cached) throws ApfloatRuntimeException { DataStorage tmp = createCachedDataStorage(length); tmp.copyFrom(x, length); this.nttStrategy.transform(tmp, modulus); this.stepStrategy.squareInPlace(tmp, modulus); this.nttStrategy.inverseTransform(tmp, modulus, length); tmp = (cached ? tmp : createDataStorage(tmp)); return tmp; } /** * Lock the execution against a synchronization lock. * * @param length The length of the data being processed for determining the type of lock to use. */ protected void lock(long length) { } /** * Remove the synchronization lock. */ protected void unlock() { } /** * Create a cached (if possible) data storage for the specified number of elements. * * @param size The number of elements. * * @return The data storage. */ protected DataStorage createCachedDataStorage(long size) throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); return dataStorageBuilder.createCachedDataStorage(size * ctx.getBuilderFactory().getElementSize()); } /** * Create a cached data storage from the (possibly) cached data storage. * * @param dataStorage The data storage, which may be cached. * * @return The data storage, which isn't cached. */ protected DataStorage createDataStorage(DataStorage dataStorage) throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); return dataStorageBuilder.createDataStorage(dataStorage); } /** * The transform to use. */ protected NTTStrategy nttStrategy; /** * The carry-CRT to use. */ protected CarryCRTStrategy carryCRTStrategy; /** * The convolution steps to use. */ protected NTTConvolutionStepStrategy stepStrategy; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/TransformLengthExceededException.java000066400000000000000000000051231461767713300326440ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Exception indicating that the "size" of the numbers used in a * multiplication is too large. The "size" is equivalent to the number * of significant digits in the mantissa of the number, excluding any * leading or trailing zeros.

* * This exception indicates a mathematical limitation. The exact * maximum transform length depends on the apfloat implementation. * * @since 1.5 * @version 1.5 * @author Mikko Tommila */ public class TransformLengthExceededException extends ApfloatInternalException { /** * Constructs a new apfloat transform length exceeded exception with an empty detail message. */ public TransformLengthExceededException() { } /** * Constructs a new apfloat transform length exceeded exception with the specified detail message. * * @param message The detail message. */ public TransformLengthExceededException(String message) { super(message); } /** * Constructs a new apfloat transform length exceeded exception with the specified detail message and cause. * * @param message The detail message. * @param cause Originating cause of the exception. */ public TransformLengthExceededException(String message, Throwable cause) { super(message, cause); } private static final long serialVersionUID = -7022924635011038776L; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/TwoPassFNTStrategy.java000066400000000000000000000274461461767713300277300ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.Util; /** * Fast Number Theoretic Transform that uses a "two-pass" * algorithm to calculate a very long transform on data that * resides on a mass storage device. The storage medium should * preferably be a solid state disk for good performance; * on normal hard disks performance is usually inadequate.

* * The "two-pass" algorithm only needs to do two passes through * the data set. In comparison, a basic FFT algorithm of length 2n * needs to do n passes through the data set. Although the * algorithm is fairly optimal in terms of amount of data transferred * between the mass storage and main memory, the mass storage access is * not linear but done in small incontinuous pieces, so due to disk * seek times the performance can be quite lousy.

* * When the data to be transformed is considered to be an * n1 x n2 matrix of data, instead of a linear array, * the two passes go as follows: * *

    *
  1. Do n2 transforms of length n1 by transforming the matrix columns. * Do this by fetching n1 x b blocks in memory so that the * blocks are as large as possible but fit in main memory.
  2. *
  3. Then do n1 transforms of length n2 by transforming the matrix rows. * Do this also by fetching b x n2 blocks in memory so that the blocks just * fit in the available memory.
  4. *
*

* * The algorithm requires reading blocks of b elements from the mass storage device. * The smaller the amount of memory compared to the transform length is, the smaller * is b also. Reading very short blocks of data from hard disks can be prohibitively * slow.

* * When reading the column data to be transformed, the data can be transposed to * rows by reading the b-length blocks to proper locations in memory and then * transposing the b x b blocks.

* * In a convolution algorithm the data elements can remain in any order after * the transform, as long as the inverse transform can transform it back. * The convolution's element-by-element multiplication is not sensitive * to the order in which the elements are.

* * All access to this class must be externally synchronized. * * @see DataStorage#getTransposedArray(int,int,int,int) * * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class TwoPassFNTStrategy extends AbstractStepFNTStrategy { /** * Default constructor. */ public TwoPassFNTStrategy() { } @Override protected void transform(DataStorage dataStorage, int n1, int n2, long length, int modulus) throws ApfloatRuntimeException { assert (n2 >= n1); int maxBlockSize = getMaxMemoryBlockSize(length), // Maximum memory array size that can be allocated b; if (n1 > maxBlockSize || n2 > maxBlockSize) { throw new ApfloatInternalException("Not enough memory available to fit one row or column of matrix to memory; n1=" + n1 + ", n2=" + n2 + ", available=" + maxBlockSize); } b = maxBlockSize / n1; for (int i = 0; i < n2; i += b) { // Read the data in n1 x b blocks, transposed try (ArrayAccess arrayAccess = getColumns(dataStorage, i, b, n1)) { // Do b transforms of size n1 transformColumns(arrayAccess, n1, b, false, modulus); } } b = maxBlockSize / n2; for (int i = 0; i < n1; i += b) { // Read the data in b x n2 blocks try (ArrayAccess arrayAccess = getRows(dataStorage, i, b, n2)) { // Multiply each matrix element by w^(i*j) multiplyElements(arrayAccess, i, 0, b, n2, length, 1, false, modulus); // Do b transforms of size n2 transformRows(arrayAccess, n2, b, false, modulus); } } } @Override protected void inverseTransform(DataStorage dataStorage, int n1, int n2, long length, long totalTransformLength, int modulus) throws ApfloatRuntimeException { assert (n2 >= n1); int maxBlockSize = getMaxMemoryBlockSize(length), // Maximum memory array size that can be allocated b; if (n1 > maxBlockSize || n2 > maxBlockSize) { throw new ApfloatInternalException("Not enough memory available to fit one row or column of matrix to memory; n1=" + n1 + ", n2=" + n2 + ", available=" + maxBlockSize); } b = maxBlockSize / n2; for (int i = 0; i < n1; i += b) { // Read the data in b x n2 blocks try (ArrayAccess arrayAccess = getRows(dataStorage, i, b, n2)) { // Do b transforms of size n2 transformRows(arrayAccess, n2, b, true, modulus); // Multiply each matrix element by w^(i*j) / n multiplyElements(arrayAccess, i, 0, b, n2, length, totalTransformLength, true, modulus); } } b = maxBlockSize / n1; for (int i = 0; i < n2; i += b) { // Read the data in n1 x b blocks, transposed try (ArrayAccess arrayAccess = getColumns(dataStorage, i, b, n1)) { // Do b transforms of size n1 transformColumns(arrayAccess, n1, b, true, modulus); } } } /** * Get a block of column data. The data may be transposed, depending on the implementation. * * @param dataStorage The data storage. * @param startColumn The starting column where data is read. * @param columns The number of columns of data to read. * @param rows The number of rows of data to read. This should be equivalent to n1, number of rows in the matrix. * * @return Access to an array of size columns x rows containing the data. */ protected ArrayAccess getColumns(DataStorage dataStorage, int startColumn, int columns, int rows) { return dataStorage.getTransposedArray(DataStorage.READ_WRITE, startColumn, columns, rows); } /** * Get a block of row data. The data may be transposed, depending on the implementation. * * @param dataStorage The data storage. * @param startRow The starting row where data is read. * @param rows The number of rows of data to read. * @param columns The number of columns of data to read. This should be equivalent to n2, number of columns in the matrix. * * @return Access to an array of size columns x rows containing the data. */ protected ArrayAccess getRows(DataStorage dataStorage, int startRow, int rows, int columns) { return dataStorage.getArray(DataStorage.READ_WRITE, startRow * columns, rows * columns); } /** * Multiply each matrix element (i, j) by wi * j / totalTransformLength. * The matrix size is n1 x n2. * * @param arrayAccess The memory array to multiply. * @param startRow Which row in the whole matrix the starting row in the arrayAccess is. * @param startColumn Which column in the whole matrix the starting column in the arrayAccess is. * @param rows The number of rows in the arrayAccess to multiply. * @param columns The number of columns in the matrix (= n2). * @param length The length of data in the matrix being transformed. * @param totalTransformLength The total transform length, for the scaling factor. Used only for the inverse case. * @param isInverse If the multiplication is done for the inverse transform or not. * @param modulus Index of the modulus. */ protected void multiplyElements(ArrayAccess arrayAccess, int startRow, int startColumn, int rows, int columns, long length, long totalTransformLength, boolean isInverse, int modulus) { super.stepStrategy.multiplyElements(arrayAccess, startRow, startColumn, rows, columns, length, totalTransformLength, isInverse, modulus); } /** * Transform the columns of the data matrix. * The data may be in transposed format, depending on the implementation.

* * By default the column transforms permute the data, leaving it in the correct * order so the element-by-element multiplication is simpler. * * @param arrayAccess The memory array to split to columns and to transform. * @param length Length of one transform (one columns). * @param count Number of columns. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param modulus Index of the modulus. */ protected void transformColumns(ArrayAccess arrayAccess, int length, int count, boolean isInverse, int modulus) { super.stepStrategy.transformRows(arrayAccess, length, count, isInverse, true, modulus); } /** * Transform the rows of the data matrix. * The data may be in transposed format, depending on the implementation.

* * By default the row transforms do not permute the data, leaving it in * scrambled order, as this does not matter when the data is only used for * convolution. * * @param arrayAccess The memory array to split to rows and to transform. * @param length Length of one transform (one row). * @param count Number of rows. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param modulus Index of the modulus. */ protected void transformRows(ArrayAccess arrayAccess, int length, int count, boolean isInverse, int modulus) { super.stepStrategy.transformRows(arrayAccess, length, count, isInverse, false, modulus); } private int getMaxMemoryBlockSize(long length) { ApfloatContext ctx = ApfloatContext.getContext(); long maxMemoryBlockSize = Util.round2down(Math.min(ctx.getMaxMemoryBlockSize(), Integer.MAX_VALUE)) / ctx.getBuilderFactory().getElementSize(); int maxBlockSize = (int) Math.min(length, maxMemoryBlockSize); return maxBlockSize; } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/doc-files/000077500000000000000000000000001461767713300252225ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/doc-files/biginteger-comparison.gif000066400000000000000000000141671461767713300322110ustar00rootroot00000000000000GIF87a I@ ` @ @@@`@@@@@` `@``````` @` @` @` @`@ @@@`@@@@@ @ @@ @` @ @ @ @ @@@ @@@@@`@@@@@@@@@@`@ `@@`@``@`@`@`@`@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@@ @@@`@@@@@ @` @ ` @ @@@`@@@@@` `@``````` @` @`ࠀ @` @` @` @ ` @ @@@`@@@@@` `@``````` @` @` @`𠠤!, I H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPδ=T cկHI̺u()[M*+݌cv ]Y*b_W`klrw3kW]Z-8?RޙZ{Z𤼺j{oVVmw2X$d?\ 0_7 㸵;ܸwB:ݸr+_Aa;]twq_{Ov9 yQ'rGPnR'rur%ȡi$RnUbv5[qUl"fj b}(WD~[:*cy5XYU!dk}dH mXkqW1yU[!X=)g.Rb{E_Up%aYjU!ainnI?Wѥ?WQ՝)稓\h[BvjjܢLjaFi2`ɥX,\Bj(fNˬZ ~v[Rd]%Y gg=掅E웈垛ۣK\ fu a.j&)6ܣU;{qv<wb<.ʕ)Z6,uV fM*~%&oϯl1x׻TZqUg*/@-kG[׷5]Cc{hkZNsdU:L출k/eA7;-UCh.JZ0^<00qf%}[JPC~s1ylҢR/ IBL"F:򑐌$'IJZ̤&7Nz (GIJ a*WV>E8L,&˸斵t.b#[ڒe-bҗ /IA,La feJ+8IrL:vAh~ V/y X!N.S*oD;NH FR<^v'pl0M^Lg !o8V>sxAc= ɐ^ B7s d& 4UMՐ1f7nwnyZybM~۱g$7rᤧgN8yr# 9Gr;+0.7:̟N2|lM.зq؆iLktJj{;tSbܺK7JnD5Nt"pMj𽈇~DWъw0/7OrzE漁hC]eWEvV;L0#rN:B{3EzkFCx‡Q'Ac@qHǞbñdDUkWٌ89~]z:rڠJiT'ieSԢw//OSsllO䧣i:ٝgz')|ZEښ(s{EZ+A2uGWT#U4qdw7FyX$~C'jLFu:AwR7}ȬyEMITjʺ\ć#yߺEFBz:ON6N#INʕtFɃOEF Ѯ]xJEQkx噰Xd EC|1n. rt2!%ec$R+7U G2;gfC BˀTh(NqGP YUkWGYۅ^'J``;]cK.bgiMan]pֆCuW*t嘂4,^w;~[=4v`E9I_[H[2>k={4PɵvL{qI[ɶIK:Oa&ڳ-;mHUa';m21bQJ7fDٙz}+JD'ȻK*ዩ㛼/qd{Ϥkq$G+ )[HakSLv3j#L,J&wk 8S-|T-x¥T&0<:bB.}V (n+} S@~]Mxh~viU~OSnq8k0&>Syd[G'8xu@B?D_FD`Q"!B&|~ =4!S-| /kA^VB&òJeCA1 9C|R>R+b"|(';X'w|OS5?RPM!s~O}_W6B\! =v672(O.lC/,S/1(?ZTн4(,_˨%*3O.y!)1 5,= jA?T{(|oO@ DPB >QD;apfloat-1.14.0/apfloat/src/main/java/org/apfloat/internal/doc-files/implementation-classes.gif000066400000000000000000000076341461767713300324030ustar00rootroot00000000000000GIF89a83f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f!,8 H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]PJJիX^mʵRJzK6Xg˪]k3Ql] hݹx+޿+:8 1D֍2Ɏ3A̖C.9-ƌQYucȩv<ۖKͻޝ}C;Aϸ8q?vztʳe.ѻo9v2z?~Ye?~g߀di6[lÕGa9F]H7eȒXmhb_bO$0L3hGOi<(ލ@)JARB*H6S䔷F啖2?~0嗀uO*Ri\䝩fYԔ)pzGdigSީQZ枀@ujOMm4袐(eFjK|xФjH:jIjC*+BjkzQk kjƆl.ˬ> i*Jm^-ng nn -;IhN i?v.Sn/GvS6u (!Y.,2:Q_oRmi LW|242Dċq\p-gv3IEt( 8& L5Vw3tLPo)'Z@L%5M7vAm1 e @~Ѝ6O~KdWMŝX[duYGq'^:O,8mM^ySwNJ1:MysGV\pM7ߟ7a-诿9Az WoZ7[mC/|P xwi|㯓[ f79)J2X3?'@N׼3&n#IP|' f-D(ۙ~<%̑ y 㾳oWÞ|C/F*H)ZX$χ d$'F1hbq(FsrKH|䥋B c"DKR {)@{fd%.ґ$ 3 8B ! )@Nr Ixo4P)1)\8CM*WOuK/'SI<4 YL^ {&CD)Z,+N7C*= y]9N`2OZu.zFpl;{:<͢N30!2Qa4&cgF;Q bGǷ&!<O6rӞ" W*T["*R_ԥN=Q+R5TVꦲUKM*X%ֱf Wz*UOn}*W8[&^9E׽~]KVR=& b,d$ c3'r6FB+m5,jDricK%v@m}r[̶G-p#⦸o $22}.b+],U-vDꥻu"7.uOk3jV1i}{帗Y)zҋfĿ{DWT&}{`Rv+`_c-`=`"%*<壞$^ +ˌ~)8XEvMb{{rOkd$7^UIe-NρuaWq?FX^8c59BO3*(' T;[)2h YHN}4ZRvW @7Ѣ?{D5ZUJ4>(`H->:0T*TڬdV[_]@jj`k5Oά:"Mِ$ #l 6ӳ*dCvٝ㶊}YӵUwQeVʻڑwT)-vC+ߥw\}Uߑ2Z>-Vj!8EA,?{qH|lǒC\Nvɻq<+JŴ )5zCk|;_5ܣcޔw\a:S&JLcZe&FnuF)i6Q{Rv.4p>*)w_'ȝmLܞ|OF$5vUy닕2Lt8g*eG<~]07\\߉Y'b9xpmRPgD' B|#Ϙ d;(1[iuŎ<>dMd3S)8̿ muFTxKqNar}tegg|S/7bu Ӈq#7kF 7{'fcMde}Je0T7!cc4t~.K(4cN'<7G0dF(bd' Xϗ({քbgs7g=FF=c&}J4n(k 8rPIOԷa{wxgBgU us8 h}wvLj~'zu^5X6e9w^XZ'X(TFq.$$ǂY6tB%&6mXtvkFNj'(n(-Z,%Ӹ`h,VbmhYhS獽*X+&UAJ˨]阋*xȏzBBC!r%BAqA@p?!kB>aj=‘Zx?67xbms+޹ۖsx 9x8ז~c~^yc{Ҧ?[7](G?=ڞDywxv-Hzܭ^nx{|8 kZK}향4M.fb]w-Wᚙ)xuH0_ 7B:| ?/pc B G=k%,Q^a {=DC.^n$?1r sթ5Nvc|x@Q^u<1Ư{dgW҈W0VJ;!GJ x+A/xq'(G:L%=7k"H0lIN[xt6; ?Ĥ$)Am|# 8Ihr ^2IӍeoIc2ĥ)A6֒'2MYf7\e/]MYXg5eV^2[tf.-O~Ӛ}=}g'%WnSD&չHz̝)Bj5Sm3YF$qIyt'Oy:TnӦ?D(>?&Ԇ~<StF$MNֶ5 oZݥte&:[ݹTsȅ2NSt {Kڻ.tEWzKЦf}0&Pk`UGZ/%q`}ޕic\[cS|`0)gwαY|Ƹr|`Е+^0~7<+[ t[9Z $g2x&t~ZZ9@l 5ҏvRIv ኶rZi&PO͉mis8SWѰvh5\YdqEuWvVinʶvskp6}ыӐFu;aR.hf\t}:[,Pun5cLp&w4YO+LZp'-wϳM4rry7 sxY!Y`IS%xGڕSrW>8e^:9h ]3/=ukUnt'MB>hNp1Gݾ>@UV)/꜊}h;~N;(6;ng4Λd<BƋ9e,ߧ^Um}QK;nכf]޹׿m짹fAzqOmg]{7[ꍯ=OvUrO*>~)o5կ_OUU3۾=+WzGwx&|XvKdW'bH}Jk}ڗ{igYՁHWaA/%h%L%6lĂ_}85C+ljzTFauABxgDm"MBqDRXtcQ5ʩ}/zJ7W{EIʑ(S {>Eb!AYa@un᭬!A3tӇ\27$_:گ 4%epFacZAvqs!Aa؈ؔض~Z1>j):+;MQsw& !1['-{=kA;CE$KT TM, $}?Ա CEG+? ot<1sq6׳z}]vq=^Ҍ؎_@Ӑ}٘ٚ ׋(]L=]M\+M̪NfM/lԭ!֔ۏ>AK4)e-}ՂY3nٯ~Բj=l}]-݊޴ۇo<m]]L̒M$ ">^I%-n^!#N%'.)+N#--MF+޻<.9ݞ BS}|Xmƭ׽HQ: ީEQ>k]F`m:QO~ݺ-uqr} 9^n~跌:>M(ۧj! *ۦAHԃ"q ԼDcndf^-7%S^\NP.n2,Ѳ2r>¸M k̒nzntn|Ү1BpC> O!)ARaH oʨ{"oi)o͜ڮ^> ̸K,/.ɞ]M];9O:~k3>@1ۻ:M_?a~ei1LvxO2F~{_i'$?<^4aۘ2}mt>E/RTPo|8Jo]?^D,\sǠ:tvng|VJkOߟ+ Tw o4Gt]p/ K  <>!5-^ĘQF)vRH%I~4RJ"QK5;ҴSgL;}TP=EhRMu.uU(T V5kĭ :kP,X"1mUh۾u\r{c^}%{p`F,pb67o^:)su6Xϒm(2dI#6}mjYOn]ulǴU϶wn޻y}@vY9ѩzRwW >x˗~Gi7~ԛp~lp( @RpAsP:#< J+9 ?1DG$DOD1EWd. °EgFo1GwGcl HRYHW2HBӜTR *d)I,rK=_$I~;4Q\6z8:$6!/?PҹLQ4oGG#TRHLW@f)ڴK:KRVKXkzZջOU)&B"b!=vdU[vfi|vhhZjIl(ʐ7\q%\sEw)Zw߅7^y祷^{땩nfPj7`&`F`Z-?~MU-&4nc=xEMP+@ar]flr;m̈́Q6d RI~]*FshôKjXSeY^l׬VRmnt[֭W16޾OmM<<;/]k˛ɯ70q?=tG'¹ܻn7+=vgvoϺr^uG-w3g  e*4OEۚ~*8A߾b|uz ,VN͂=3Uwtvny WHπY0gyNVsI0mnOQ^>q˃V]GtyXo r8ލPV1_O%U"%Le$YQ^VTQppw hO3E, ԸF6эo# 3q=6g GBҐDd"r.z}j=QRET &I q?X@Q S-kn(2lG%?+7G⪁ نK PN1Qޭ@4Il G݄aLYRS_ě9#8wFPiɔyF'AK|57N:S{XP6ԡh *a>v)-Qvԣ'bdKBC.H:)\hLq~b vR{KjȈ&mJ:TըGEjRT6թOjT:ULH:@es2e[F-icb)TV5 kA/էڔ]ţW槭:kYF˶*eZYZ5s jQ`MYlB+~=:ܕZk_e?z0 ֶmnu[ y$ly0׸Enr Nw6F6xr:wm`=x];vI/.f]W,s]swKUu)Ηl_NS `X/kaW߀ͫΪĶg(::b7)0Z/\gޘ?r5$&T%7O2G|)OPĺpIYsy["¤93mҬ5H{<WY Oh壉FWi6 niЀ=B9gE>9G@Y\N)W Қ.ޥ ղtae[&f<^C3vƳתaMXh섭J}I& t|f]1Dв.ݸQZW9vC@k_:۟)ND|/;xw{ XFqgWxmlZ8=vMi?<}$ /{9cd򗃎6ywrt? j::=& N^F[sm?,Qu.:V b~#K}w+{9lh׹=fwD'C;{qڨ/ڛ.z3_֜Gxl/T-d.-p+2#)xTk ;:83;{1x+#=@@AyB7A9HA??]ӑ< ; l.<@| 4#D?AB* [+Q- /$Bw[{B:>;[;$&&,:d44CAVS?6ME`$b4F$ExgKFPY 0j, k l̤g|'+(L[34t)˾6övDi;53ڶC?GRGv$@lA4p8,O,:JI,CϊM5IEH|@ O NҫIaEy<`Ji1KE˃N2P+Nc,PLEU=edE =o<=C3,3BёQ!PNNsEdS6E G4RsLH'}ߤ^Ͳ9]?ad@$S13"U PBhP(Ծ8ԶHTL T3]*KLMN,EeR5չHMK=UVmYU:MU?][(tRU  _E b.td@,4I#SB,a)*;4\4j2Nh}Vi+Y}>Rڨ-?th(t$fׁ9Vt%RxH_Ju]˲]7vۅtI1&2. Yc3v7ca-[i b$b9>^+=T J;fc_TD߽a*F՝ڋc&md0;ռy} KLγ:^˻}GPv7ͪ-6P VSC.$& aVTAs;Eben[T֥MF8kl4Gcmq&gf^}MUraf%Q?x?| =g}f^V3fGMH<J&o_=dn~ZYY儖[hEfXU KcxQU.oeO_]6[ohhו~'wƈ#FfszI\FirꪶjcihZ밆6軲-jI@+g=kyg]>qi 1r)Ctnl Κ֑E^I }^NGfauWdS&QFkLt˅{W OP6펎Inhնd.IѮ;454Xc X%Iˍf(W\+K/JVfl4ӌ8mtyNd^l4|KNM۟f >zρppLifx :ΖI I7۾NᾙŎm`FPVoF˶i.Qi5&j;  j%mvd[i!GgNY)n,ꝼʓ17~0OW9:;coV>Oq.W2jp<'BE@i s7V<0FꕎA JGM?~vjom:%ofQWОe wlsr18gkT?tY? (u&?UnRQhY'KuvghOduߞΏ:-W4A{nu j>)hxwܣ^s0D7x^v)>/?Twdw}7%)tWyapBٱt.a>^uq#rVr~O/uwoWuv-)my+q#?iDeywq'VGW\ڟy'|{/pzW3 LoN/˗to0 wk?|vh}O.rfaP/kO5.srg3\=zrX1ŌY疷u[8'ʽOޥ<ӫ˾qO/7Z}^g_\=J75x׃ MUXڧajrxHrH^~cfcAhiZٍ֜N!~HԐ?fJE"i5)OE؉WURi9q emc^h~a&lpwti'|Xfn' :(zh ɩN*zfJ:)Zz)jOY)]&*z**)+hw…!r+pr(,jj2h+Pb,nZl~LaFR{ӶNj;鸵&-blr{i*SL!\]i嫥1[迣n.kK0an %q~*Rf n )rQv2)2-21<35|39|?S׋>_\5ele??(romB (jwzA҇/oqU?1pbuA}PfPv`Bjac\) ]+mx3BK0kVx4#ybh$2.0ODE@@Fұv#ohÖx{`TDGmUX"T&|$$#)ɸ%|ZgUg"2Ho$*SUraa&rI".ir2Qwx0ocXQ|%79]ƍqd/  Ce&ΛZgYu.exX7ZѱeEc&Ky2gYE#i%~vK{@@7RU>z>1"4rct;" E;.QQFi+sӝ򴧧JkVOԥ2d(Sɓs{z!Nխr^c'Z0~ʪIGRsCkMnȬdf\&_)׳v=(<שҵ=``Y+h9YYQuxig06 6ZvPe15HRMgךXmj-p+\=֨c-Jk;\7m}.t\*&fStr.x+񒷼'CX買hhXZְDlC Ԯ'fKI◶`-eFYҲ.6X&ɇ Z]$ֳhbؕZ+ew;&X\gb0qG8̭}/' )S4~37V/,1Zro\0^n3, ,sB<xAxy͇nXc3빡pyfN[ _&qi7G<L][xӆl73zԭ0m]^@lu_-eÚ@*~6'2B6;:.kCN'~7SڒkrF`__ת}KWY7z DŢ&QiF`8st~qwK]PmH<#/p[{^ CyۧMB̧Ua f^>?ZOkDăE^E4MU`g}'6{V觞|-*鷾6>,KsT{4y^.`џ9I ͘_@ B5]%I *Xv Ơ ΠLzz霪x_y Q n`_oUM*_`!!ñ^J< qa`jY . -^a2^f1d!U[ !"!!0"U" F"%VbX ua"!*b_jLV`l!ԡ'Οva RY!(~(z"$@V!/_0*\#•$B-Z+4&a*!˕3jaYec#)%Rvc<ޣN;nY3F0cIK#@d*c1?"c,"d4RABE^$_Cf5CZ_/b7>YFE\3b4~r! "#-aՔd=$յ#Hdb#Ҥ0mcQvHԥdP*b2n$-dev腤bi QgkSFd"Q%4V/>s6'1c^ {rLz'Exc}2jgb¤~gY'o~&m&.%Ng>(^Q%xRhw4g`~Rj*g\ާj&~Or~U-( (ihb(Z$V%mΦy!fongj(~b')fx29*)vʞBL)i1i鋂ک.)5Fb(憚*jFe&Sb)FjrzrNPZjޤoF!)r܍jvh*&V̲᪩f(Ji蔢fb:*b )ZB*yVRkfn}kVΪn;)ki[ *5띢+ƫn(7t:k(jd^*R:쮖hn+樷Bv~n*Rjy^dv%O>lBB*¡˚(I]&lFh2-vN--}l˲P"d~-ؚj6-6Dd!fkf,&k*"ٮJ]Jӱa"\V) -6*6NJmm&)ʭNVB2Sb"^g-M&:F:솭nޞ,k.o풡֮6R2Y#.!*hȲȢnnniޒirdVHgNn(vKNkji9..݊l+'bo'w~omGJoH0 ?RFE{ ޠ` ǰ 瞯n60 g)vpFln.0l0.0&pƯo،Z0JT 0moMl0w1^sqJ=q+jN`1r'-gǟ+ #%_rq+7r O2&(31 ?' r)2+ujr%j,-(q(.)W1o-&;"2.M22_*q!22/%{1/wh1k5^ap3ʰskGoVp&9gp5/2:kG+@G _?? B/`RSz]03Fot:t‘6Ae4$ï=-^z=0s/m"4bp7Or9s$KMwNgm3#*N4)t/I{?+/QEdUnU3185J31gWa\Yuu5G_G˴.ŔZT_/6ca`/3]C2O76eW8#1+Ĭd3W4[TVAO1M\4rRb5QõQs*s2dC53u3wro;sZvVowen;Gooi*h/v7r *9H4^NkS0䜷CI۸rR-5IcFI9'{Պy*{l$+;)?@*^ ;YNg[[hOqLKC da;ﵬz6yL8:gE߈OԒDzKu ?|:3>!968yw5g{Syq8?5vtp|ϛpы/UF.=Gb_8k]=g}RE=V X췟?+|վsܓ'ǒ>pK|[gًz"~+hbq:{|ڛ> :[cl/z? }Ʒ;13ߺŻ?@8`A&DB? !F8Ä)fԸcGA#QT9dŕ/aƔ9fM7qԹgO?:hQG$'SN.m5jUWNźV_;lYgѦUmۛP[v[w# T^Tty{sNl{|C4S*2|$Y9deSa^ʄQ C$fpLk,$R35pzaP/fuF+C>rPxPcSR˔$! hXJԊ|]WR׹*Q%}DPԤ5i2Kix* /em=OZsH)Rag.Qu(}tfPUn5CI:"R2+@Tj"Sӣʩ[ R;Puh7 iL+NծT4c8[3VDүCW ˎejCYJrӕTf~ntTl-Ԧ ^YOmjf]Eg~ahtل&e/yDvV_K.(:XWK5B>5y[]/V^Ηl+j5}`p\o/X (x\ծ`B{k^p]_%fv͓pt=Ya5^cqtP|b|x傽*Ȥb ~pulY sef`&xme)OU򕱜eMD/VeyqJUFnϙuΫɶf4mlgA*/9gzzon iIϙѐ֐cbDW0Agda/yϬ[iU!Smuὒz_aj.R±L ~sL;kfP:`MkmF)kemFp}f%m'oy3M o{];p;޾^>XH'ub$i\HgǛM$5ً6%LÜvvm.ԗ۫3sllMG|jQ#)5rS,+7ZϷdiZ>Ž3|@FwşG%¼n=u4˼s1g: ~&qՂx")>C?yVwI~M3݋czָokpկ\_ιǪFHs[|ʑ|֤&lA+ff~#i8c>ߦ+WOl?fs(*AoK6ǷTq-C4  k]p꯶ˮ P p0{Bʞ.*pbZ Y8J<0̍0SN,mP`b  %D okpg0HP0Ɉzμ.c/ p 0 P lذ0/2P0+ >12FxqC"r Mpn94|+]oG1*1V/t0j'eM׬+\g0{cyLg܀|ЂCEl1qɱ1qgkk ЂQpQ&ȶ!R2몑#;6)68:0xq->Q,kNRMJQ&#ls F!ݯ01 (=1lk:Pqtx"_ 9"7P)ώۦ*A'O rR2-pZ ic-.C.OjdDJ9rQr_RvF!KJ&t1R )1,XЪP29s+"CB3*V>-J3-R3(VS4Zs003Υ5K6q3s41(3<ؒ)]h1v +S02H:W:r& l)|OX.k).*׭0i:9AڴD2A(0#6cP3F>w'}7yӸ&30;MbNϱtb$Tb'-:(>45B4& xJFtZTA 'Jr 003ׅFńS:ӏNGJ- Gm4HGJ0AK7oA"%}vT4IkIc4%ts,t'ڔ= MKNτN8 UDoY\>tPoe?m4+, @@SH@Tێ8$t4LP4QѬ8k)OORuSXJ3zO&Pb.?OUvVq=g6525<-Vtn䓜K'R[/N-B U&]o]%&5+O\(ċ.J{Ա_}GO ZQV6.5va`/Z+.vQ_32CcidCdsH461HHVVeKAYu!`50BUUGYy'eI9VUaFb0lr(b's6/fftc3W90Q6 ^wV^%_Sk0M=Lm]k"Euoo6|ZV$U1 6UZiHk%W" -iuvrsnf%(tYtr!sMf!3tvquY~FWn5iOkvcpm\)Δxw/>tMxpJ,s&ǖnyu+gv6,v(u+6w6|%ϣPz3lW)-vW׏㳰Ka( ?nXO7(Цv78gx^]:mzVB㿨BՖD  ǰGUԱW޹-r5=2Sz5Ҫ![8'R wµBK#Zעby"c&'8zy[oVz^w:!q"pgǛ'zVWvyCp`DQԗq7ۻi|Ҩao-7O[[N֮1|G\Ju,m4Ի&hëůƃxkViv["{*qڐŁZYx<|<ŏF}|=^Fk;>$z3~wk{Q}Hf{}k^]#KM{^;;}}u_qݺݥ׫O~q;ޙ݁Qr~C4~\LJEBE~?^gv9뽝ʳ .<59=Aig?!_)̞58V^YG~No[i>;w٣~wuu_TaRX^~7g|ʼno77d36lx蜿j<?y? <0… :|!# XŒ9b#CGH ʕ,[ L2$;μ3gD:{СD_=4)ťJ:uԩRY`V[v*)رd^J b\`[4*۶qze/޸}O݋#aDֱɔ+[9JȚ;{ z2g?:u%V:6ayg_uڂs߶]bĉ.<̛?<钏O;u~W>[6ɚ -&nuǽ~)-/~O߀ug XY jV`%x|vo !{~zi|Qr=M(O4h֋8cS7ZQA66~?ƤoK:ibxK{HIYH&jTd*ש9iベIlF{P{VfVk)(%|RfYۖ.yIOvF:#5XFg֩tVi*u^thpsjr۫*#ʤQ_ *f*fT.*,Wâ,YFZTTiKնuKn枋n)eq6 ^o p;bK|2:LJ,Z,0Hgz $ḥrD1k:s5‹) ͗2̦ВQ3m-sLtQیB֌3\{SX0;5-i]#dC__dS]I7S7jw;{8 ݭxLwZ97^_ ~Dy袏Nz:&inj= {N{ߎ{{; N|4w֪È`ϧ;|r~|SՓ}8wzs2/O/!ٟ_d_-&꿲$ƫl睾/eJ p|9vr+qu\!W&0ba\6T\T.dvCRCTS gtKlVICDqdAL"hU1\lQ((l%,Q*[8"rS#z0QLSG Gwc%gg4#/G鱑(5PzY '=$dtT-J .IWJFt$ny\Rb)]RrdVL=QC6oJf͹/rnTd)G`+КކV}s? Lx^ҝ?&@GPH+PyЈJtqDilJѠY (+ĠJ/b%RD/)uHE*Gf)!eSJ4`bOӃq%%*F6:TOU ի&DLEsLd5KjKeJKjIp<RS+hPZ@?j\`mY(&G: ;UekIa5ǖUן E͟sЦQ-dͲ29RgI399vEPU]oKD9l[wGMPqt\~%W`Ss/:T"vuѵ (@6Iܼu\-yϋduӫUF񪤳KJɪ걩")hRF.I.VeĂ0j,< 䢆Rbd-MӾVbc<cUzFmobUx (8L-{[ВؽB~U.c'sʆ.aILř:sQ͕!m!yF{L!Cr2 D+z[mh7qz- Lkz80KbZgO3VJ zG>ש׹bPK-M݈̋d+{n hK{Ԯlk{ pڵ`EM {򼈭ƧK7j,~H'Tɽ+1W RC~n8G,p̝A8q9;9NǛq h.?;ءHw]]vӾEnW.ԤnŞoty1 E7a=s\{Wly~򨏑$KG/on#|/hǏ5CBqW'4sO%k5_.:[_YIHj]<}a)#)IDnzRC]XuwG8}xyl|94)q騜yɜGש}jӹ(Ĕ)S>DLɋYirٜI-aFId yI yTnuݴ?*O נx-)R+X_/I T,Y)*}w=b3$Ǐg*Q*'iwMJQ9%ʡ[_ڎ3y5ڙ1JV'CFO4)ė9rt*؞\ȳbPjd*A~yU 5`B&*:Fڒ)}3Ǜ*P7U~RyVe+%`qhdW(kdg'J9 9Zj(^Q({^`8xicyyWEݸ~hE%_1.:Bq Ѯ;nubI)]1|F5+Z`jڏfz|ʭ'nU ˱]X j7:['aRT]8H15EF53=ڂeY&__JꠑO:G.\鰧y[ɫ"کɢWiTpW굎ɰDUB[fj{z rtH28qFEDjK`iZڱ˹/Ѹ[[@ !)๩ $}TGayJܿZ<:]Y+ՒzַUhl={kmM7=t9/[)c[_- Ԍ̣{~,Mrm =tJK),Kjz3N28-=Ǭ}2.5_5m]قW̌2 ރ ̇-T1L.ޥ߷+=נ}Z=،ylε뛌ϋl<-g|> סݐ[]ڂ٬")i6N>'܍9ICGQktҢܗ​1Y KWΉ}Q_.;:0Kkmn ;=߼lAr~uILx<.Q<ⅭND^̧m ^L˭iwm3n7䩽 U|,=S.Ƌ.Ɋ.Ό@\eaƝ Bm k><&fc׍~PZnʷʬNyegbQ]fHnw-풎^~Ϲ^PG^d,N~>lϋɚN3IMWv]NOUoS.>(O,2U ^?Rn n*p8_u?#<>}?dy{{G/&AO-(e? O#o.6'oo"OotYƜOiC,"S22Rdr:;>.*2r //5nXA .\HC%N0"Ċ5ncG!E$cI)Uˋ0eR<9͎5qiPgOA %ZtOID˦O'6ʓTW.MkϮ_Ŧ3hY Ѧepm۶oΕ(]aݩ_|.|_ĉ/fcȑ%O\e̙6g͡E&]iԩUfk1fKt`bq)'Xω3 뤫JGI I~T޺7&LR Ps+OADAIB<#0t" :F̏APMŠLdqSB C.ƺh9ӈ~4I!%'t)4F‚r챥 [rL24L4TsM6CR7gK15İ0]lsO>O@tВjU%N%1P=Y5[E@P?6wTPMKV\Wֵg,ѨMkUmQV%cW VbO5ϭ1}]~ImV!x="ER' 1~n_zVPcIb%b3xc;4 ?6dSVyeY.yAz1fp6Kxg޳f?NTcNڢf^ ՠMj9mE5ZĖEsk}iN l ]) [~PG.FLn]醖mnd+꺕X񹨲q52᫜9\~s@G6I7Nqihɻ}vkvܟ{T܃~x7~}u'2׋8Q>)Ey5T/D!ʀ}Yøe?ڨyׂZ? u(R׵^ ɗּOP| + ΀G(A.!\!B3|pNj(V&!ėzb e;OKdbD%"Rt ^E,fQ[bBX>`L.jK>W:1Fr, EFap'S 9/쐸:a/< YHRX%u#Fru (XH?yR@k$T INPdf͉I<+ bGS4l 12&cZ&Y&d'4S\b"52%;]d2j.* Y]Ҁ7aϬlK EE6^Wm.lØ^WoX~Pbpj а>&fZOv@،-`7Ns[RvL- eQV5b*c֗3źQhazK1pE㢖ըoIs1,hເ,b&kZevmd'<ɿss|#OYUkg@ZЃ&+d)DslӑҤb`z8 kBъM kLM&dɌ5q\a f֒lMWoLkB2ujlGWu&- HFӀl-K^sW5onx[϶5=o|[淲={s\VWb + _ -e斍[eڶS+mPQիuű1Gv[^+ḁ̈̄rTS"5Fs݁ٿ%tkK%g՚_vg~v]an]s{ [:YjVԭ''߷/w y 9v[@<\c7yv;[s%Dstu칮'5d8"g9n|g_^Rc'͟c[=q7 ժ}ox1&vA~Q9+)K=#߻6 ><7Tt3-h"6<\ %@=@ݻXӼ<<&R [SQ:ٿ;;47uj';?'|B(Aڧ~2B-B.B 9;iB@CPC BpÄñ`CC;C8BCj=X@sAg=l12D@[jG4=ȋAJDcDJ<6@3BtTD;=DGF\PQ02p䛾7S;` =.p=09HBflFg|AeLFhFkFlܽ>Lma|CKbqs<(co ñǒS?9E <ὣCDZAK{B d6Rc!|"~MϒH*q#e!)HKPk%!G3 5hFN*3N\ަLlcpftN0Qd&wIRdYN Ɠ+Ǵ6Dra T5ZPC4DZ撏hVDY43oBV3&YPu)%K*haIU^Q&C+)alW{SUlEY3סqF4AZDg0(X#JLQsˀ˧WPcH0p< <+)n %Y긁.c];Y/[Qn[ڛJohk2GEv_MoY` _PdT_tx-㢅˜0 <EF ^Ȃ` ĔrpU`91PVaX Pi9JAM{.$*g^V2~ .GɌS1?9oL(v6@qAC5V3_\;4|^M2D5Ԍ2<` (*N"mҍ yM38nj΋kQ_z<؃2H&a{1%TD3;q~CwxA%AX9HNK"fu(zg( THgO#uR]t> nPWX>L\c7F$7u'hVG%U# "xjgXoA>('5^׉_x}wR}NH3wG_H_3x8dw#Wf؋e nԊnzׅh7fu!XP8ķ9yB#fyx臽ō=B1A{mď0W:X8A1\bǸ% Ipȑ?+)x(}yb(,;zظWuRْI.ip'!ɐ YiV\ *B9LKٕbYFW I.g8!|%7Xa^m(i=FZMcј瘇ĸ zs1)9XQ\WF8yhIBVfi[YSOe]ٛY[]ZRUV78W*XWXtYYzQćx8S8Q5U8HSQ^)m~DqSZjD/9 ri)gXK9HTT{4:de8ٟHhTTcO8فyvU)lF֤R]ĝP&0wɓДYXxRN1B:|@E@9M:pOHəyE< ʘ~iJ9ɠHXY$Z頃cr8aXm 9AHf:w]꧟6:#J1Ȗna|I*s1oyʞecVcpڨi'ɧ=Ǧ% zj vycZjLg}[ajxʩ ]h:jڮ[Z`IN*kjAhznĊZ)ᖰ|yٗJJZI{wZ vMiJ3kpʬ{+k<4@ -QH;;-R_ I!.az!۴}JB/&͚zBKmE5-WCOcZb);&lnKKy@ӳSezzɟm^k7$GB@I@Q.A^a,Aڪ1DYÂɚk} )SJHȻ|Xj8>h;,TO8]9rK;Wv{V8*kYn۠۱w&Y)|{~+;O sh[q+ ˪t1B2{ھ:;$̴'\…*k—{ 35w7|VŸ 8 hl |LKiD|";SlBܳ"^`bZLP"fo,@j0l-<#y|}u**FѕfMl&Qal%6Aّ]e6ƧWƫwGݐSMǞ}}Aބ\k~;<F vMqxM!QͿܒ݄ӽỳ}lj-4{|ߧB^@M>N$~MVUKmUu[n|ۇ۲L!~Eo(* ;β]BV6geSI.%AET}}Y{9D.>h2`~娞ׅ.>DB-ީ>庹~k)A1^>hM?>跾3+:Ns^kK~O<.=ь~ߨK^mYM^|zVH5|Qml^J} ̾ߍi>N0R,LG ?4򁪭i1M/&N?% >,N|J˯!DW$ [-X!c+^VX/&nb;)b??O3J*kWLmʔTfsy[v[{Gj7b7>ƒM0hǟ_~)= 4%iAd=胋,$?C?1D;:Qڐ<$1Fg<ܒ/[qfq""Dk \ J鄌+Ѩ\ D K,L.rӲ8uCs:<S9|?Ϩ2aԓ H#hR,Q:KN5]TJG%n|S<]UX55VYgSU;mFYeOh[Hc. gk73 YN'ޙeR:%uavUg޺c8F6)コiWy3J$b.8c{>vڼۛc+Tͫ,mfk~j8l.K,kAp[0|:M s-4tk?ttBKʙV\xOW{qQ;jmXw|}kTCqvpg\{y6F~Yo[yIlwF8@Y}ǜ*Ff#`%/{ŸgE`BH2*ث   y;u$\ B4eؖ!.eY~$%ibj'DVhFZ&g9DzFRq3fT7pnLx\4A:qZ8tƇȏd 8 юDdd[D8GPF&-MA2(´EPU #M$KW+? -ȳVJZ 8`P6R`iL^R5\f#Yc6ɖfh m,i^z\f}Hv:&Oe`tg>iM{걟<'i( o$c*(Zt= QbQ*QsSeAImcJW ;7 hcJ9̰mGC:eE]٨Nn7 9nBhR:FEk^׿vg | _kz$!bJu޲)W{FtbI3g&cTՓ1t[:hWsR:>Go&uLpr<-qj7պW6=x}q9!%9J9.ipEMr.֍gef^yO^~0grN'[Ȗrଋ_/'P{~sߚۮ]KYQ͟׾wک/{?*Ny:t,4k_j|Sr:mfO/ngywCwQ^w[o·/>/_4^0gVuڥ2+~>Ǫ_ ?oJ[SϿ0CS<Ҭĩ=t ۽ˬ 49;6<=1!=;h 3RS $( 83D9x>N8+AVJAL;=K=o;BAJBKB%<-?24TC#DC;(>z5YC˜S\;HDS)8"?C6ɤ/C B,TDCD9RiI'lÆ7,CTTUdVtWX$B~P0DD=E6ħD`j3pDC>HASzF\FFE+F"|k\CkG/ PlF]F;r Gw,Z{DFFgB/LY|҈mКؠN,G UEYsͤwEЭ-$2[ڄѡSETRW}WjW=Q=קQѩ]Y QGZ؛٘\TۈGy-ےUe˪r[u-\ғ]ܼXOvʵX \MKESWE5[[l\}\@׬}V5YݽɅX}R-]uXΨZUMZ]/E\e5^ϭT]L^<^-_%WXK!K ]qQr_U_߯]ݳU{]ZE:UEY&.F؂Z`d> P B%6FVfML``sa.[ a The org.apfloat.internal package contains four different implementations of the apfloat SPI, each based on a different primitive element type:

  • {@link org.apfloat.internal.LongBuilderFactory}, based on element type long: This is the default implementation used by apfloat. It uses the 64-bit long integer as the elementary type for all data storage and manipulation. It usually is faster than the int version on 64-bit JVMs, which is mostly the case today. In some places it uses also double arithmetic, so the processor should be able to perform double-precision floating point operations as well as convert between double and long, for decent performance. For example, on x86-64 and SPARC the 64-bit long version is faster than the 32-bit int version. You can use the long implementation on 32-bit platforms too, however the performance per element is less than half of the int version, even if roughly twice as much data is processed per element. The upside is that this implementation can do much bigger calculations: up to about 3.5 * 1015 digits in radix 10.
  • {@link org.apfloat.internal.IntBuilderFactory}, based on element type int: It works well for 32-bit platforms that perform integer operations fast (including integer multiplication), and can multiply doubles and convert between double and int with adequate performance. This applies to most workstations today (Intel x86 processors and compatibles, in particular processors with SSE2 support, and most RISC architectures). You can do calculations up to roughly 226 million digits (in radix 10) with this implementation, which should be enough for most purposes.
  • {@link org.apfloat.internal.DoubleBuilderFactory}, based on element type double: This implementation exists generally only as a curiosity. It will typically perform worse than the long version, and it's only able to do calculations with about 1/20 of its maximum digit length. The only situation where using the double version might make sense is on a platform that performs floating-point arithmetic well, but performs integer arithmetic extremely badly. Finding such a platform today might be difficult, so generally it's advisable to use the long version instead, if you have a 64-bit platform or need the most extreme precision.
  • {@link org.apfloat.internal.FloatBuilderFactory}, based on element type float: This version is also only a curiosity. The main downside is that it can only perform calculations up to about 1.3 million radix-10 digits. The per-digit performance is also typically less than that of the int version. Unless you have a computer that performs floating-point arithmetic extraordinarily well compared to integer arithmetic, it's always advisable to use the long or int version instead.
For example, the relative performance of the above implementations on some CPUs is as follows (bigger percentage means better performance):
Relative performance of implementations
TypePentium 4Athlon XPAthlon 64 (32-bit)Athlon 64 (64-bit)UltraSPARC II
Int100%100%100%100%100%
Long40%76%59%95%132%
Double45%63%59%94%120%
Float40%43%46%42%82%

(Test was done with apfloat 1.1 using Sun's Java 5.0 server VM calculating π to one million digits with no disk storage.)

Compared to the java.math.BigInteger class with different digit sizes, the apfloat relative performance with the same CPUs is as follows:

Apfloat and BigInteger comparison

(Test was done with apfloat 1.1 using Sun's Java 5.0 server VM calculating 3n and converting the result to decimal.)

This benchmark suggests that for small numbers – less than roughly 200 decimal digits in size – the BigInteger / BigDecimal classes are probably faster, even by an order of magnitude. Using apfloats is only beneficial for numbers that have at least a couple hundred digits, or of course if some mathematical functions are needed that are not available for BigIntegers or BigDecimals. The results can be easily explained by the smaller overhead that BigIntegers have due to their simpler implementation. When the size of the mantissa grows, the O(n log n) complexity of apfloat's FFT-based multiplication makes apfloat considerably faster than the steady O(n2) implementation of the BigInteger class. For numbers with millions of digits, multiplication using BigIntegers would be simply unfeasible, whereas for apfloat it would not be a problem at all.

All of the above apfloat implementations have the following features (some of the links point to the int version, but all four versions have similar classes):

  • Depending on the size, numbers can be stored in memory ({@link org.apfloat.internal.IntMemoryDataStorage}) or on disk ({@link org.apfloat.internal.IntDiskDataStorage}).
  • Multiplication can be done in an optimized way if one multiplicand has size 1 ({@link org.apfloat.internal.IntShortConvolutionStrategy}), using a simple O(n2) long multiplication algorithm for small numbers, with low overhead ({@link org.apfloat.internal.IntMediumConvolutionStrategy}), using the Karatsuba multiplication algorithm for slightly larger numbers, with some more overhead ({@link org.apfloat.internal.IntKaratsubaConvolutionStrategy}), or using a Number Theoretic Transform (NTT) done using three different moduli, and the final result calculated using the Chinese Remainder Theorem ({@link org.apfloat.internal.ThreeNTTConvolutionStrategy}), for big numbers.
  • Different NTT algorithms for different transform lengths: basic fast NTT ({@link org.apfloat.internal.IntTableFNTStrategy}) when the entire transform fits in the processor cache, "six-step" NTT when the transform fits in the main memory ({@link org.apfloat.internal.SixStepFNTStrategy}), and a disk-based "two-pass" NTT strategy when the whole transform doesn't fit in the available memory ({@link org.apfloat.internal.TwoPassFNTStrategy}).
The apfloat implementation-specific exceptions being thrown by the apfloat library all extend the base class {@link org.apfloat.internal.ApfloatInternalException}. This exception, or various subclasses can be thrown in different situations, for example:
  • Backing storage failure. For example, if a number is stored on disk, an IOException can be thrown in any of the disk operations, if e.g. a file can't be created, or written to if the disk is full.
  • Operands have different radixes. This is a limitation allowed by the specification.
  • Other internal limitation, e.g. the maximum transform length mathematically possible for the implementation, is exceeded.
Note in particular that numbers, which take a lot of space are stored on disk in temporary files. These files have by default the extension *.ap and they are by default created in the current working directory. When the objects are garbage collected, the temporary files are deleted. However, garbage collection may not work perfectly at all times, and in general there are no guarantees that it will happen at all. So, depending on the program being executed, it may be beneficial to explicitly call System.gc() at some point to ensure that unused temporary files are deleted. However, VM vendors generally warn against doing this too often, since it may seriously degrade performance. So, figuring out how to optimally call it may be difficult. If the file deletion fails for some reason, some temporary files may be left on disk after the program exits. These files can be safely removed after the program has terminated.

Many parts of the program are parallelized i.e. are processed with multiple threads in parallel. Parallelization is done where it has been easy to implement and where it is efficient. E.g. the "six-step" NTT is parallelized, because the data is in matrix form in memory and it's easy and highly efficient to process the rows of the matrix in parallel. Other places where parallelization is implemented are the in-place multiplication of transform results and the carry-CRT operation. However in both of these algorithms the process is parallelized only if the data is in memory - if the data was stored on disk then the irregular disk seeking could make the parallel algorithm highly inefficient.

Many sections of the code are not parallelized, where it's obvious that parallelization would not bring any benefits. Examples of such cases are addition, subtraction and matrix transposition. While parallel algorithms for these operations could certainly be implemented, they would not bring any performance improvement. The bottleneck in these operations is memory or I/O bandwidth and not CPU processing time. The CPU processing in addition and subtraction is highly trivial; in matrix transposition it's outright nonexistent - the algorithm only moves data from one place to another. Even if all the data was stored in memory, the memory bandwidth would be the bottleneck. E.g. in addition, the algorithm only needs a few CPU cycles per element to be processed. However moving the data from main memory to CPU registers and back to main memory needs likely significantly more CPU cycles than the addition operation itself. Parallelization would therefore not improve efficiency at all - the total CPU load might appear to increase but when measured in wall-clock time the execution would not be any faster.

Since the core functionality of the apfloat implementation is based on the original C++ version of apfloat, no significant new algorithms have been added (although the architecture has been otherwise greatly beautified e.g. by separating the different implementations behind a SPI, and applying all kinds of patterns everywhere). Thus, there are no different implementations for e.g. using a floating-point FFT instead of a NTT, as the SPI ({@link org.apfloat.spi}) might suggest. However the default implementation does implement all the patterns suggested by the SPI – in fact the SPI was designed for the default implementation.

The class diagram for an example apfloat that is stored on disk is shown below. Note that all the aggregate classes can be shared by multiple objects that point to the same instance. For example, multiple Apfloats can point to the same ApfloatImpl, multiple ApfloatImpls can point to the same DataStorage etc. This sharing happens in various situations, e.g. by calling floor(), multiplying by one etc:

Implementation class diagram

The sequence diagram for creating a new apfloat that is stored on disk is as follows. Note that the FileStorage class is a private inner class of the DiskDataStorage class:

New Apfloat sequence diagram

The sequence diagram for multiplying two apfloats is as follows. In this case a NTT based convolution is used, and the resulting apfloat is stored in memory:

Multiplication sequence diagram

Most of the files in the apfloat implementations are generated from templates where a template tag is replaced by int/long/float/double or Int/Long/Float/Double. Also the byte size of the element type is templatized and replaced by 4/8/4/8. The only files that are individually implemented for each element type are:

*BaseMath.java
*CRTMath.java
*ElementaryModMath.java
*ModConstants.java
@see org.apfloat.spi */ package org.apfloat.internal; apfloat-1.14.0/apfloat/src/main/java/org/apfloat/package-info.java000066400000000000000000000137031461767713300247340ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** The apfloat Application Programming Interface (API).

All application code using apfloat generally needs to only call the classes in this package.

A sample apfloat program might look like this:

import org.apfloat.Apfloat;
import org.apfloat.ApfloatMath;

public class ApfloatTest
{
    public static void main(String[] args)
    {
        Apfloat x = new Apfloat(2, 1000);   // Value 2, precision 1000 digits

        Apfloat y = ApfloatMath.sqrt(x);    // Square root of 2, to 1000 digits

        System.out.println(y);
    }
}
As apfloats are immutable, they can be easily passed by reference. Also the mantissa data of numbers can be efficiently shared in various situations.

An inherent property of an {@link org.apfloat.Apfloat} is the radix. The radix is specified at the time an apfloat is created. Due to the way the default implementation works, there is no real performance difference in using radix 2 or some other radix in the internal calculations. While it's generally not possible to use numbers in different radixes in operations, it's possible to convert a number to a different radix using the {@link org.apfloat.Apfloat#toRadix(int)} method.

The rounding mode for apfloat calculations is undefined. Thus, it's not guaranteed that rounding happens to an optimal direction and more often than not it doesn't. This should be carefully considered when designing numerical algorithms. Round-off errors can accumulate faster than expected, and loss of precision (as returned by {@link org.apfloat.Apfloat#precision()}) can happen quickly. This bad behaviour is further accelerated by using a radix bigger than two, e.g. base 10, which is the default. Note that precision is defined as the number of digits in the number's radix. If numbers need to be rounded in a specific way then the {@link org.apfloat.ApfloatMath#round(Apfloat,long,RoundingMode)} method can be invoked explicitly.

Generally, the result of various mathematical operations is accurate to the second last digit in the resulting number. This means roughly that the last significant digit of the result can be inaccurate. For example, the number 12345, with precision 5, should be considered 12345 ± 10. This only applies to elementary mathematical operations. More complicated functions may have slightly larger errors due to error accumulation. This should generally not be a problem, as you should typically be using apfloats for calculations with a precision of thousands or millions of digits.

There is no concept of an infinity or Not-a-Number with apfloats. Whenever the result of an operation would be infinite or undefined, an exception is thrown (usually an ArithmeticException).

All of the apfloat-specific exceptions being thrown by the apfloat library extend the base class {@link org.apfloat.ApfloatRuntimeException}. This exception, or various subclasses can be thrown in different situations, for example:

  • {@link org.apfloat.InfiniteExpansionException} - The result of an operation would have infinite size. For example, new Apfloat(2).divide(new Apfloat(3)), in radix 10.
  • {@link org.apfloat.OverflowException} - Overflow. If the exponent is too large to fit in a long, the situation can't be handled. Also, there is no "infinity" apfloat value that could be returned as the result.
  • {@link org.apfloat.LossOfPrecisionException} - Total loss of precision. For example, ApfloatMath.sin(new Apfloat(1e100)). If the magnitude (100) is far greater than the precision (1) then the value of the sin() function can't be determined to any accuracy.
The exception is a RuntimeException, because it should "never happen", and in general the cases where it is thrown are irrecoverable with the current implementation. Also any of the situations mentioned above may be relaxed in the future, so this exception handling strategy should be more future-proof than others, even if it has its limitations currently.

The {@link org.apfloat.Apfloat} class is the basic building block of all the objects used in the apfloat package. An {@link org.apfloat.Apcomplex} simply consists of two apfloats, the real part and the imaginary part. An {@link org.apfloat.Apint} is implemented with an apfloat and all its operations just guarantee that the number never gets a fractional part. Last, an {@link org.apfloat.Aprational} is an aggregate of two apints, the numerator and the denominator. The relations of these classes are shown in a class diagram format below:

Class diagram */ package org.apfloat; import java.math.RoundingMode; apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/000077500000000000000000000000001461767713300223345ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/AdditionBuilder.java000066400000000000000000000034031461767713300262410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; /** * Interface of a factory for creating addition strategies. * The factory method pattern is used. * * @param The element type of the addition strategies. * * @see AdditionStrategy * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface AdditionBuilder { /** * Returns an addition strategy of suitable type for the specified radix. * * @param radix The radix that will be used. * * @return A suitable object for performing the addition. */ public AdditionStrategy createAddition(int radix); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/AdditionStrategy.java000066400000000000000000000152361461767713300264640ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; /** * Generic addition strategy. Also subtraction, "short" multiplication and * "short" division can be done. * * @param The element type of the addition strategy. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface AdditionStrategy { /** * Addition in some base. Adds the data words * of src1 and src2 and stores the result to * dst. src2 may be null, in * which case it is ignored (only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] + src2[i]. * * @param src1 First source data sequence. Can be null, in which case it's ignored. * @param src2 Second source data sequence. Can be null, in which case it's ignored. * @param carry Input carry bit. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the addition of the last (leftmost) word in the accessed sequence. */ public T add(DataStorage.Iterator src1, DataStorage.Iterator src2, T carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException; /** * Subtraction in some base. Subtracts the data words * of src1 and src2 and stores the result to * dst. src1 and src2 may be * null, in which case they are ignored (the values are assumed * to be zero and only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] - src2[i]. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param carry Input carry bit. This is subtracted from the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the subtraction of the last (leftmost) word in the accessed sequence. The value is 1 if the carry is set, and 0 otherwise. */ public T subtract(DataStorage.Iterator src1, DataStorage.Iterator src2, T carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException; /** * Multiplication and addition in some base. Multiplies the data words * of src1 by src3 and adds the result to the * words in src2, and stores the result to dst. * src2 may be null, in which case it is ignored * (the values are assumed to be zero).

* * Assumes that the result from the addition doesn't overflow the upper * result word (to larger than the base). This is the case e.g. when using * this method to perform an arbitrary precision multiplication.

* * Essentially calculates dst[i] = src1[i] * src3 + src2[i]. * * @param src1 First source data sequence. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param src3 Multiplicand. All elements of src1 are multiplied by this value. * @param carry Input carry word. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry word. Propagated carry word from the multiplication and addition of the last (leftmost) word in the accessed sequence. */ public T multiplyAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, T src3, T carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException; /** * Division in some base. Divides the data words * of src1 by src2 and stores the result to * dst. src1 may be null, * in which case it is ignored (the values are assumed to be * zero and only the carry division is propagated).

* * Essentially calculates dst[i] = src1[i] / src2. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Divisor. All elements of src1 are divided by this value. * @param carry Input carry word. Used as the upper word for the division of the first input element. This should be the remainder word returned from the previous block processed. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Remainder word of the propagated division of the last (rightmost) word in the accessed sequence. */ public T divide(DataStorage.Iterator src1, T src2, T carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException; /** * Returns the zero element. * * @return Zero of the correct element type. */ public T zero(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/ApfloatBuilder.java000066400000000000000000000101331461767713300260720ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import java.io.PushbackReader; import java.io.IOException; import org.apfloat.ApfloatRuntimeException; /** * An ApfloatBuilder contains factory methods to create * new instances of {@link ApfloatImpl} implementations. * * @version 1.0 * @author Mikko Tommila */ public interface ApfloatBuilder { /** * Create a new ApfloatImpl instance from a String. * * @param value The string to be parsed to a number. * @param precision The precision of the number (in digits of the radix). * @param radix The radix in which the number is created. * @param isInteger Specifies if the number to be parsed from the string is to be treated as an integer or not. * * @return A new ApfloatImpl. * * @exception NumberFormatException If the number is not valid. */ public ApfloatImpl createApfloat(String value, long precision, int radix, boolean isInteger) throws NumberFormatException, ApfloatRuntimeException; /** * Create a new ApfloatImpl instance from a long. * * @param value The value of the number. * @param precision The precision of the number (in digits of the radix). * @param radix The radix in which the number is created. * * @return A new ApfloatImpl. * * @exception NumberFormatException If the number is not valid. */ public ApfloatImpl createApfloat(long value, long precision, int radix) throws NumberFormatException, ApfloatRuntimeException; /** * Create a new ApfloatImpl instance from a double. * * @param value The value of the number. * @param precision The precision of the number (in digits of the radix). * @param radix The radix in which the number is created. * * @return A new ApfloatImpl. * * @exception NumberFormatException If the number is not valid. */ public ApfloatImpl createApfloat(double value, long precision, int radix) throws NumberFormatException, ApfloatRuntimeException; /** * Create a new ApfloatImpl instance reading from a stream. * * @param in The stream to read from. * @param precision The precision of the number (in digits of the radix). * @param radix The radix in which the number is created. * @param isInteger Specifies if the number to be parsed from the stream is to be treated as an integer or not. * * @return A new ApfloatImpl. * * @exception IOException If an I/O error occurs accessing the stream. * @exception NumberFormatException If the number is not valid. */ public ApfloatImpl createApfloat(PushbackReader in, long precision, int radix, boolean isInteger) throws IOException, NumberFormatException, ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/ApfloatImpl.java000066400000000000000000000217651461767713300254220ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import java.io.Serializable; import java.io.Writer; import java.io.IOException; import org.apfloat.ApfloatRuntimeException; /** * Interface for apfloat implementations. An ApfloatImpl implements all of the * low-level functionality that is needed behind the high-level apfloat API.

* * A class implementing ApfloatImpl is not required to accept any other ApfloatImpl * class as the argument than the same implementing class. * * @version 1.7.0 * @author Mikko Tommila */ public interface ApfloatImpl extends Serializable { /** * Add or subtract an ApfloatImpl to this object. * * @param x The number to be added or subtracted to this ApfloatImpl. * @param subtract true if the numbers are to be subtracted, false if added. * * @return this + x or this - x depending on the subtract argument. */ public ApfloatImpl addOrSubtract(ApfloatImpl x, boolean subtract) throws ApfloatRuntimeException; /** * Multiply this object by an ApfloatImpl. * * @param x The number to be multiplied by this ApfloatImpl. * * @return this * x. */ public ApfloatImpl multiply(ApfloatImpl x) throws ApfloatRuntimeException; /** * Returns if this ApfloatImpl is "short". Typically ApfloatImpl * is "short" if its mantissa fits in one machine word. If the apfloat is "short", * some algorithms can be performed faster.

* * The return value of this method is highly implementation dependent. * * @return true if the ApfloatImpl is "short", false if not. * * @see org.apfloat.Apfloat#isShort() */ public boolean isShort() throws ApfloatRuntimeException; /** * Divide this ApfloatImpl by an ApfloatImpl that is "short". * * @param x The number by which this ApfloatImpl is to be divided. * * @return this / x. */ public ApfloatImpl divideShort(ApfloatImpl x) throws ApfloatRuntimeException; /** * Returns this ApfloatImpl rounded towards zero. * * @return This ApfloatImpl rounded towards zero. */ public ApfloatImpl absFloor() throws ApfloatRuntimeException; /** * Returns this ApfloatImpl rounded away from zero. * * @return This ApfloatImpl rounded away from zero. */ public ApfloatImpl absCeil() throws ApfloatRuntimeException; /** * Returns the fractional part of this ApfloatImpl. * * @return The fractional part of this ApfloatImpl. * * @since 1.7.0 */ public ApfloatImpl frac() throws ApfloatRuntimeException; /** * Returns the radix of this ApfloatImpl. * * @return The radix of this ApfloatImpl. */ public int radix(); /** * Returns the precision of this ApfloatImpl. * * @return The precision of this ApfloatImpl. */ public long precision(); /** * Returns the size of the mantissa of this ApfloatImpl. * * @return The size of the mantissa of this ApfloatImpl. * * @since 1.2 */ public long size() throws ApfloatRuntimeException; /** * Returns this ApfloatImpl with the specified precision. * * @param precision The precision. * * @return This ApfloatImpl with the specified precision. */ public ApfloatImpl precision(long precision) throws ApfloatRuntimeException; /** * Returns the scale of this ApfloatImpl. * * @return The scale of this ApfloatImpl. * * @see org.apfloat.Apfloat#scale() */ public long scale() throws ApfloatRuntimeException; /** * Returns the signum of this ApfloatImpl. * * @return The signum of this ApfloatImpl. * * @see org.apfloat.Apfloat#signum() */ public int signum(); /** * Returns this ApfloatImpl negated. * * @return -this. */ public ApfloatImpl negate() throws ApfloatRuntimeException; /** * Returns the value of the this number as a double. * * If the number is greater than Double.MAX_VALUE, * then Double.POSITIVE_INFINITY is returned.

* * If the number is less than Double.MIN_VALUE, * then Double.NEGATIVE_INFINITY is returned.

* * If the number is very small in magnitude, underflow may * happen and zero is returned. * * @return The numeric value represented by this object after conversion to type double. */ public double doubleValue(); /** * Returns the value of the this number as a long. * The fractional part is truncated towards zero.

* * If the number is greater than Long.MAX_VALUE, * then Long.MAX_VALUE is returned.

* * If the number is less than Long.MIN_VALUE, * then Long.MIN_VALUE is returned. * * @return The numeric value represented by this object after conversion to type long. */ public long longValue(); /** * Tests if this number is equal to 1. * * @return true if this number is equal to one, otherwise false. */ public boolean isOne() throws ApfloatRuntimeException; /** * The number of equal digits in this ApfloatImpl and another number. * * @param x The number to compare with. * * @return The number of equal digits in this ApfloatImpl and x. * * @see org.apfloat.Apfloat#equalDigits(org.apfloat.Apfloat) */ public long equalDigits(ApfloatImpl x) throws ApfloatRuntimeException; /** * Compare this ApfloatImpl and another number. * * @param x The number to compare with. * * @return Zero, less than zero or greater than zero depending on the result of the comparison. * * @see org.apfloat.Apfloat#compareTo(org.apfloat.Apfloat) */ public int compareTo(ApfloatImpl x) throws ApfloatRuntimeException; /** * Returns the hash code for this ApfloatImpl. * * @return The hash code for this ApfloatImpl. */ @Override public int hashCode(); /** * Convert this ApfloatImpl to String. * * @param pretty Flag for formatting. * * @return String representation of this ApfloatImpl. * * @see org.apfloat.Apfloat#toString(boolean) */ public String toString(boolean pretty) throws ApfloatRuntimeException; /** * Print this ApfloatImpl to a stream. * * @param out The stream to write to. * @param pretty Flag for formatting. * * @exception IOException In case of I/O error writing to the stream. * * @see org.apfloat.Apfloat#writeTo(Writer,boolean) */ public void writeTo(Writer out, boolean pretty) throws IOException, ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/ArrayAccess.java000066400000000000000000000154711461767713300254070ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import java.io.Serializable; import org.apfloat.ApfloatRuntimeException; /** * The ArrayAccess class simulates a C language pointer. * With one ArrayAccess object you can point to a location within an * array. You can easily add or subtract a value to this "pointer", thus * essentially emulating C pointer arithmetic. An ArrayAccess * provides an array, the starting index within that array and the length of * accessible data within the array, all in one convenient package.

* * Just like pointers in the C language, ArrayAccess * objects are inherently unsafe and must be used cautiously. It is the * responsibility of the user of an ArrayAccess object to make sure * that he doesn't access the provided array outside the allowed range. The * ArrayAccess object itself does nothing to enforce this, except * of course the mandatory bounds check of Java, which can throw an * ArrayIndexOutOfBoundsException. * * @version 1.9.0 * @author Mikko Tommila */ public abstract class ArrayAccess implements Serializable, AutoCloseable { /** * Create an array access.

* * @param offset The offset of the access segment within the array. * @param length The access segment. */ protected ArrayAccess(int offset, int length) { this.offset = offset; this.length = length; } /** * Create a sub-sequence view of this array access.

* * Note that the changes done to the sub-sequence array * are not necessarily committed to the underlying data * storage when the sub-sequence is closed (with {@link #close()}), * but only when the "base" ArrayAccess is closed. * * @param offset The sub-sequence starting offset within this ArrayAccess. * @param length The sub-sequence length. * * @return The sub-sequence array access. */ public abstract ArrayAccess subsequence(int offset, int length); /** * Returns the array of this array access. This is an array of a * primitive type, depending on the implementation class. * * @return The backing array of this array access. */ public abstract Object getData() throws ApfloatRuntimeException; /** * Returns the array of this array access as an int[]. * * @return The backing array of this array access. * * @exception UnsupportedOperationException In case the backing array can't be presented as int[]. */ public int[] getIntData() throws UnsupportedOperationException, ApfloatRuntimeException { throw new UnsupportedOperationException("Not implemented"); } /** * Returns the array of this array access as a long[]. * * @return The backing array of this array access. * * @exception UnsupportedOperationException In case the backing array can't be presented as long[]. */ public long[] getLongData() throws UnsupportedOperationException, ApfloatRuntimeException { throw new UnsupportedOperationException("Not implemented"); } /** * Returns the array of this array access as a float[]. * * @return The backing array of this array access. * * @exception UnsupportedOperationException In case the backing array can't be presented as float[]. */ public float[] getFloatData() throws UnsupportedOperationException, ApfloatRuntimeException { throw new UnsupportedOperationException("Not implemented"); } /** * Returns the array of this array access as a double[]. * * @return The backing array of this array access. * * @exception UnsupportedOperationException In case the backing array can't be presented as double[]. */ public double[] getDoubleData() throws UnsupportedOperationException, ApfloatRuntimeException { throw new UnsupportedOperationException("Not implemented"); } /** * Returns the offset of the access segment within the backing array. * * @return The starting index within the backing array that is allowed to be accessed. */ public int getOffset() { return this.offset; } /** * Returns the length of the access segment within the backing array. * * @return The number of elements within the backing array that is allowed to be accessed. */ public int getLength() { return this.length; } /** * Close this array access and commit any changes to the * underlying data storage if applicable.

* * If the ArrayAccess was obtained in write * mode, the changes are saved to the data storage. Note * that even if the ArrayAccess was obtained * for reading only, any changes made to the array data * may still be committed to the data storage.

* * Note that changes done to a sub-sequence array * are not necessarily committed to the underlying data * storage when the sub-sequence is closed, * but only when the "base" ArrayAccess is closed. */ @Override public abstract void close() throws ApfloatRuntimeException; private static final long serialVersionUID = -7899494275459577958L; private int offset; private int length; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/BuilderFactory.java000066400000000000000000000120251461767713300261150ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; /** * A BuilderFactory object contains factory methods for building * the various parts of an apfloat using the Builder pattern. There * is no separate "director" object in the apfloat SPI; it is suggested * that the ApfloatImpl implementation itself acts as the director, * calling the different builders directly. * * @version 1.9.0 * @author Mikko Tommila */ public interface BuilderFactory { /** * Returns an ApfloatBuilder object. * * @return An ApfloatBuilder object. */ public ApfloatBuilder getApfloatBuilder(); /** * Returns a DataStorageBuilder object. * * @return A DataStorageBuilder object. */ public DataStorageBuilder getDataStorageBuilder(); /** * Returns an AdditionBuilder object. * * @param The element type of the additions. * @param elementType The element type of the additions. * * @return An AdditionBuilder object. * * @throws IllegalArgumentException In case of unsupported element type. * * @since 1.7.0 */ public AdditionBuilder getAdditionBuilder(Class elementType) throws IllegalArgumentException; /** * Returns a ConvolutionBuilder object. * * @return A ConvolutionBuilder object. */ public ConvolutionBuilder getConvolutionBuilder(); /** * Returns an NTTBuilder object. * * @return An NTTBuilder object. */ public NTTBuilder getNTTBuilder(); /** * Returns a MatrixBuilder object. * * @return A MatrixBuilder object. * * @since 1.7.0 */ public MatrixBuilder getMatrixBuilder(); /** * Returns a CarryCRTBuilder object. * * @param The element array type of the carry-CRT. * @param elementArrayType The element array type of the carry-CRT. * * @return A CarryCRTBuilder object. * * @throws IllegalArgumentException In case of unsupported element array type. * * @since 1.7.0 */ public CarryCRTBuilder getCarryCRTBuilder(Class elementArrayType) throws IllegalArgumentException; /** * Returns an ExecutionBuilder object. * * @return An ExecutionBuilder object. * * @since 1.9.0 */ public ExecutionBuilder getExecutionBuilder(); /** * Returns the element type of the data objects created. * * @return The element type of the data objects created. * * @since 1.7.0 */ public Class getElementType(); /** * Returns the element array type of the data objects created. * * @return The element array type of the data objects created. * * @since 1.7.0 */ public Class getElementArrayType(); /** * Returns the element size of the data objects created, in bytes. * * @return The element size of the data objects created, in bytes. * * @since 1.7.0 */ public int getElementSize(); /** * Shuts down the builder factory. Clean-up tasks can be executed by this method. * This method is invoked by the {@link ApfloatContext} when cleanupAtExit is enabled. * * @since 1.6.2 */ public void shutdown() throws ApfloatRuntimeException; /** * Do garbage collection and related things such as empty any reference queues. * * @since 1.6.2 */ public void gc() throws ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/CarryCRTBuilder.java000066400000000000000000000042651461767713300261460ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; /** * Interface of a factory for creating carry-CRT related objects. * The factory method pattern is used. * * @param The element array type of the CRT. * * @see CarryCRTStrategy * @see CarryCRTStepStrategy * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface CarryCRTBuilder { /** * Creates an object for implementing the carry-CRT of a three-NTT * based convolution using the specified radix. * * @param radix The radix that will be used. * * @return A suitable object for performing the carry-CRT. */ public CarryCRTStrategy createCarryCRT(int radix); /** * Creates an object for implementing the steps of the carry-CRT * of a three-NTT based convolution using the specified radix. * * @param radix The radix that will be used. * * @return A suitable object for performing the carry-CRT steps. */ public CarryCRTStepStrategy createCarryCRTSteps(int radix); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/CarryCRTStepStrategy.java000066400000000000000000000073011461767713300272100ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; /** * Interface for performing the steps of a carry-CRT operation in a convolution. * * @param The element array type of the carry-CRT steps. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface CarryCRTStepStrategy { /** * Perform the Chinese Remainder Theorem (CRT) on each element * of the three result data sets to get the result of each element * modulo the product of the three moduli. Then it calculates the carries * for the block of data to get the final result.

* * Note that the return value's initial word may be zero or non-zero, * depending on how large the result is.

* * Assumes that MODULUS[0] > MODULUS[1] > MODULUS[2]. * * @param resultMod0 The result modulo MODULUS[0]. * @param resultMod1 The result modulo MODULUS[1]. * @param resultMod2 The result modulo MODULUS[2]. * @param dataStorage The destination data storage of the computation. * @param size The number of elements in the whole data set. * @param resultSize The number of elements needed in the final result. * @param offset The offset within the data for the block to be computed. * @param length Length of the block to be computed. * * @return The carries overflowing from this block (two elements). */ public T crt(DataStorage resultMod0, DataStorage resultMod1, DataStorage resultMod2, DataStorage dataStorage, long size, long resultSize, long offset, long length) throws ApfloatRuntimeException; /** * Propagate carries from the previous block computed with the CRT * method. * * @param dataStorage The destination data storage of the computation. * @param size The number of elements in the whole data set. * @param resultSize The number of elements needed in the final result. * @param offset The offset within the data for the block to be computed. * @param length Length of the block to be computed. * @param results The carry overflow from this block (two elements). * @param previousResults The carry overflow from the previous block (two elements). * * @return The carries overflowing from this block (two elements). */ public T carry(DataStorage dataStorage, long size, long resultSize, long offset, long length, T results, T previousResults) throws ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/CarryCRTStrategy.java000066400000000000000000000050301461767713300263510ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; /** * Interface for performing the final step of a three-modulus * Number Theoretic Transform based convolution. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface CarryCRTStrategy { /** * Calculate the final result of a three-NTT convolution.

* * Performs a Chinese Remainder Theorem (CRT) on each element * of the three result data sets to get the result of each element * modulo the product of the three moduli. Then it calculates the carries * to get the final result.

* * Note that the return value's initial word may be zero or non-zero, * depending on how large the result is.

* * Assumes that MODULUS[0] > MODULUS[1] > MODULUS[2]. * * @param resultMod0 The result modulo MODULUS[0]. * @param resultMod1 The result modulo MODULUS[1]. * @param resultMod2 The result modulo MODULUS[2]. * @param resultSize The number of elements needed in the final result. * * @return The final result with the CRT performed and the carries calculated. */ public DataStorage carryCRT(DataStorage resultMod0, DataStorage resultMod1, DataStorage resultMod2, long resultSize) throws ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/ConvolutionBuilder.java000066400000000000000000000036241461767713300270320ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; /** * Interface of a factory for creating convolutors. * The factory method pattern is used. * * @see ConvolutionStrategy * * @version 1.0 * @author Mikko Tommila */ public interface ConvolutionBuilder { /** * Returns a convolution strategy of suitable * type for the specified length. * * @param radix The radix that will be used. * @param size1 Length of first data set. * @param size2 Length of second data set. * @param resultSize Minimum number of elements needed in the result data. * * @return A suitable object for performing the convolution. */ public ConvolutionStrategy createConvolution(int radix, long size1, long size2, long resultSize); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/ConvolutionStrategy.java000066400000000000000000000045671461767713300272550ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; /** * Generic convolution strategy. To perform the convolution, * an implementing class could use e.g. * *

* * @version 1.0 * @author Mikko Tommila */ public interface ConvolutionStrategy { /** * Convolutes the two sets of data. * * @param x First data set. * @param y Second data set. * @param resultSize Number of elements needed in the result data. * * @return The convolved data. */ public DataStorage convolute(DataStorage x, DataStorage y, long resultSize) throws ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/DataStorage.java000066400000000000000000001270531461767713300254050ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import java.io.Serializable; import org.apfloat.ApfloatRuntimeException; /** * Generic data storage class.

* * Initially when a data storage is created, it is mutable * (it can be modified). After the contents have been properly * set, the user should call {@link #setReadOnly()} to set the * storage to be immutable. After this the data storage can be * safely shared between different users.

* * Access to DataStorage objects is generally not internally synchronized. * Accessing multiple non-overlapping parts of the storage concurrently with the * {@link #getArray(int,long,int)}, {@link #getArray(int,int,int,int)} * or {@link #getTransposedArray(int,int,int,int)} method and with * iterators over non-overlapping parts is permitted. Invoking * other methods must generally be externally synchronized. * * @version 1.8.1 * @author Mikko Tommila */ public abstract class DataStorage implements Serializable { /** * Read access mode specifier. */ public static final int READ = 1; /** * Write access mode specifier. */ public static final int WRITE = 2; /** * Read-write access mode specifier. For convenience, equivalent to READ | WRITE. */ public static final int READ_WRITE = READ | WRITE; /** * Iterator for iterating through elements of the data storage. */ public static abstract class Iterator implements Serializable, AutoCloseable { /** * Default constructor. Can be used e.g. for simple anonymous subclasses. */ protected Iterator() { } /** * Check if next() can be called without going past the end of the sequence.

* That is, if next() can be called without deliberately causing an exception. * * Note: It is important that the iterator is iterated * past the last element; that is next() is called * startPosition - endPosition times. The * get() or set() methods should not * be called for the last element.

* * The default implementation always returns false. * * @return true if {@link #next()} can be called, otherwise false. */ public boolean hasNext() { return false; } /** * Advances the position in the stream by one element.

* * Note: It is important that the iterator is iterated * past the last element; that is next() is called * startPosition - endPosition times. The * get() or set() methods should not * be called for the last element.

* * The default implementation always throws IllegalStateException. * * @exception IllegalStateException If the iterator has been iterated to the end already. */ public void next() throws IllegalStateException, ApfloatRuntimeException { throw new IllegalStateException("Not implemented"); } /** * Gets the current element as an int.

* * The default implementation calls {@link #get(Class)} with argument {@link Integer#TYPE}. * * @return The current element as an int. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to an int. * @exception IllegalStateException If the iterator is at the end. */ public int getInt() throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { return get(Integer.TYPE); } /** * Gets the current element as a long.

* * The default implementation calls {@link #get(Class)} with argument {@link Long#TYPE}. * * @return The current element as a long. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to a long. * @exception IllegalStateException If the iterator is at the end. */ public long getLong() throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { return get(Long.TYPE); } /** * Gets the current element as a float.

* * The default implementation calls {@link #get(Class)} with argument {@link Float#TYPE}. * * @return The current element as a float. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to a float. * @exception IllegalStateException If the iterator is at the end. */ public float getFloat() throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { return get(Float.TYPE); } /** * Gets the current element as a double.

* * The default implementation calls {@link #get(Class)} with argument {@link Double#TYPE}. * * @return The current element as a double. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to a double. * @exception IllegalStateException If the iterator is at the end. */ public double getDouble() throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { return get(Double.TYPE); } /** * Sets the current element as an int.

* * The default implementation calls {@link #set(Class,Object)} with first argument {@link Integer#TYPE}. * * @param value The value to be set to the current element as an int. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to an int. * @exception IllegalStateException If the iterator is at the end. */ public void setInt(int value) throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { set(Integer.TYPE, value); } /** * Sets the current element as a long.

* * The default implementation calls {@link #set(Class,Object)} with first argument {@link Long#TYPE}. * * @param value The value to be set to the current element as a long. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to a long. * @exception IllegalStateException If the iterator is at the end. */ public void setLong(long value) throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { set(Long.TYPE, value); } /** * Sets the current element as a float.

* * The default implementation calls {@link #set(Class,Object)} with first argument {@link Float#TYPE}. * * @param value The value to be set to the current element as a float. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to a float. * @exception IllegalStateException If the iterator is at the end. */ public void setFloat(float value) throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { set(Float.TYPE, value); } /** * Sets the current element as a double.

* * The default implementation calls {@link #set(Class,Object)} with first argument {@link Double#TYPE}. * * @param value The value to be set to the current element as a double. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to a double. * @exception IllegalStateException If the iterator is at the end. */ public void setDouble(double value) throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { set(Double.TYPE, value); } /** * Gets the current element as a the specified element type.

* * The default implementation always throws UnsupportedOperationException. * * @param The type of the element. * @param type The type of the element. * * @return The current element as the specified type. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to the specified type. * @exception IllegalStateException If the iterator is at the end. * * @since 1.7.0 */ public T get(Class type) throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { throw new UnsupportedOperationException("Not implemented"); } /** * Sets the current element as the specified element type.

* * The default implementation always throws UnsupportedOperationException. * * @param The type of the element. * @param type The type of the element. * @param value The value to be set to the current element as the specified type. * * @exception UnsupportedOperationException If the element type of the data storage can't be converted to the specified type. * @exception IllegalArgumentException If the value is not of the specified type. * @exception IllegalStateException If the iterator is at the end. * * @since 1.7.0 */ public void set(Class type, T value) throws UnsupportedOperationException, IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { throw new UnsupportedOperationException("Not implemented"); } /** * Closes the iterator. This needs to be called only if the * iterator is not iterated to the end. */ @Override public void close() throws ApfloatRuntimeException { } private static final long serialVersionUID = 7155668655967297483L; } /** * Abstract base class for iterators iterating through this DataStorage. * This class provides most of the common functionality needed. */ protected abstract class AbstractIterator extends Iterator { /** * Construct a new iterator. Elements can be iterated either * in forward or in reverse order, depending on if startPosition * is less than or greater than endPosition, correspondingly. * * @param mode Access mode for iterator: {@link #READ}, {@link #WRITE} or both. * @param startPosition Starting position of iterator in the data set. For reverse access, the first element in the iterator is startPosition - 1. * @param endPosition End position of iterator in the data set. For forward access, the last accessible element in the iterator is endPosition - 1. * * @exception IllegalArgumentException If the requested block is out of bounds of the data storage. * @exception IllegalStateException If write access is requested for a read-only data storage. */ protected AbstractIterator(int mode, long startPosition, long endPosition) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { if (startPosition < 0 || endPosition < 0 || startPosition > getSize() || endPosition > getSize()) { throw new IllegalArgumentException("Requested block out of range: startPosition=" + startPosition + ", endPosition=" + endPosition + ", available=" + getSize()); } if (isReadOnly() && (mode & WRITE) != 0) { throw new IllegalStateException("Write access requested for read-only data storage"); } this.mode = mode; if (endPosition >= startPosition) { this.position = startPosition; this.length = endPosition - startPosition; this.increment = 1; } else { this.position = startPosition - 1; this.length = startPosition - endPosition; this.increment = -1; } } /** * Check if next() can be called without going past the end of the sequence. * That is, if next() can be called without deliberately causing an exception.

* * Note: It is important that the iterator is iterated * past the last element; that is next() is called * startPosition - endPosition times. The * get() or set() methods should not * be called for the last element. * * @return true if {@link #next()} can be called, otherwise false. */ @Override public boolean hasNext() { return (this.length > 0); } /** * Advances the position in the stream by one element.

* * Note: It is important that the iterator is iterated * past the last element; that is next() is called * startPosition - endPosition times. The * get() or set() methods should not * be called for the last element. */ @Override public void next() throws IllegalStateException, ApfloatRuntimeException { checkLength(); this.position += this.increment; this.length--; } @Override public int getInt() throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { checkGet(); return super.getInt(); } @Override public long getLong() throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { checkGet(); return super.getLong(); } @Override public float getFloat() throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { checkGet(); return super.getFloat(); } @Override public double getDouble() throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { checkGet(); return super.getDouble(); } @Override public void setInt(int value) throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { checkSet(); super.setInt(value); } @Override public void setLong(long value) throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { checkSet(); super.setLong(value); } @Override public void setFloat(float value) throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { checkSet(); super.setFloat(value); } @Override public void setDouble(double value) throws UnsupportedOperationException, IllegalStateException, ApfloatRuntimeException { checkSet(); super.setDouble(value); } /** * Checks if any of the get() methods can be called. * This checks both that the iterator is not at the end yet, and * that the iterator was opened in a readable mode. * * @exception IllegalStateException If the iterator is at end or is not readable. */ protected void checkGet() throws IllegalStateException { checkLength(); if ((this.mode & READ) == 0) { throw new IllegalStateException("Not a readable iterator"); } } /** * Checks if any of the set() methods can be called. * This checks both that the iterator is not at the end yet, and * that the iterator was opened in a writable mode. * * @exception IllegalStateException If the iterator is at end or is not writable. */ protected void checkSet() throws IllegalStateException { checkLength(); if ((this.mode & WRITE) == 0) { throw new IllegalStateException("Not a writable iterator"); } } /** * Checks if the iterator is at the end yet. * * @exception IllegalStateException If the iterator is at end. */ protected void checkLength() throws IllegalStateException { if (this.length == 0) { throw new IllegalStateException("At the end of iterator"); } } /** * Returns the mode in which the iterator was created. * * @return The mode in which the iterator was created. */ protected int getMode() { return this.mode; } /** * Returns the current position of the iterator. * * @return The current position of the iterator. */ protected long getPosition() { return this.position; } /** * Returns the remaining length in the iterator. * * @return The remaining length in the iterator. */ protected long getLength() { return this.length; } /** * Returns the increment of the iterator. * This is 1 if the iterator runs forward, or -1 * if the iterator runs backwards in the data. * * @return The increment of the iterator. */ protected int getIncrement() { return this.increment; } private static final long serialVersionUID = 1668346231773868058L; private int mode, increment; private long position, length; } /** * Default constructor. To be called by subclasses when creating a new empty * DataStorage. */ protected DataStorage() { this.offset = 0; this.length = 0; this.originalDataStorage = null; // No dataStorage that this is a subsequence of this.isReadOnly = false; // Initially writable this.isSubsequenced = false; // Initially is not a subsequence nor any subsequences of this object exist } /** * Subsequence constructor. To be called by subclasses when creating a subsequence of an * existing DataStorage. * * @param dataStorage The originating data storage. * @param offset The subsequence starting position. * @param length The subsequence length. */ protected DataStorage(DataStorage dataStorage, long offset, long length) { this.offset = offset; this.length = length; this.originalDataStorage = dataStorage; } /** * Get a subsequence of this data storage. * * @param offset The subsequence starting position. * @param length The subsequence length. * * @return Data storage that represents the specified part of this data storage. * * @exception IllegalArgumentException If the requested subsequence is out of range. */ public final DataStorage subsequence(long offset, long length) throws IllegalArgumentException, ApfloatRuntimeException { if (offset < 0 || length <= 0 || offset + length < 0 || offset + length > getSize()) { throw new IllegalArgumentException("Requested subsequence out of range: offset=" + offset + ", length=" + length + ", available=" + getSize()); } setSubsequenced(); if (offset == 0 && length == getSize()) { // Full contents of the data set; not actually a subsequence return this; } return implSubsequence(offset, length); } /** * Implementation of getting a subsequence of this data storage. * The validity of the arguments of this method do not need to be * checked. * * @param offset The subsequence starting position. * @param length The subsequence length. * * @return Data storage that represents the specified part of this data storage. */ protected abstract DataStorage implSubsequence(long offset, long length) throws ApfloatRuntimeException; /** * Copies all data from another data storage to this data storage. * * @param dataStorage The data storage where the data should be copied from. * * @exception IllegalArgumentException If the origin data source has a size of zero. * @exception IllegalStateException If this data storage is read-only or has subsequences. */ public final void copyFrom(DataStorage dataStorage) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { copyFrom(dataStorage, dataStorage.getSize()); } /** * Copies the specified number of elements from another data storage to this data storage. * * @param dataStorage The data storage where the data should be copied from. * @param size The number of elements to be copied. * * @exception IllegalArgumentException If the size is invalid or zero. * @exception IllegalStateException If this data storage is read-only or has subsequences. */ public final void copyFrom(DataStorage dataStorage, long size) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { if (size <= 0) { throw new IllegalArgumentException("Illegal size: " + size); } else if (isReadOnly()) { throw new IllegalStateException("Cannot copy to read-only object"); } else if (isSubsequenced()) { throw new IllegalStateException("Cannot copy to when subsequences exist"); } implCopyFrom(dataStorage, size); } /** * Copies the specified number of elements from another data storage to this data storage. * The validity of the arguments of this method do not need to be * checked. * * @param dataStorage The data storage where the data should be copied from. * @param size The number of elements to be copied. */ protected abstract void implCopyFrom(DataStorage dataStorage, long size) throws ApfloatRuntimeException; /** * Return the size of the data storage, or the length of this sub-sequence * if this data storage is a sub-sequence. * * @return The size of the data storage. */ public final long getSize() throws ApfloatRuntimeException { if (isReadOnly() || isSubsequenced()) { return this.length; } else { return implGetSize(); } } /** * Return the size of the whole data storage, not including sub-sequence settings. * * @return The size of the whole data storage, not including sub-sequence settings. */ protected abstract long implGetSize() throws ApfloatRuntimeException; /** * Sets the size of the data storage. * * @param size The size of the data storage. * * @exception IllegalArgumentException If the size is invalid or zero. * @exception IllegalStateException If this data storage is read-only or has subsequences. */ public final void setSize(long size) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { if (size <= 0) { throw new IllegalArgumentException("Illegal size: " + size); } else if (isReadOnly()) { throw new IllegalStateException("Cannot set size of read-only object"); } else if (isSubsequenced()) { throw new IllegalStateException("Cannot set size when subsequences exist"); } implSetSize(size); } /** * Sets the size of the data storage. * The validity of the arguments of this method do not need to be * checked. * * @param size The size of the data storage. */ protected abstract void implSetSize(long size) throws ApfloatRuntimeException; /** * Returns the read-only state of this data storage. * * @return true if this data storage is read-only, otherwise false. */ public final boolean isReadOnly() { if (this.originalDataStorage == null) { return this.isReadOnly; } else { return this.originalDataStorage.isReadOnly(); } } /** * Sets this data storage as read-only. * All existing sub-sequences (recursively) of this data storage * are set to read-only as well. */ public final void setReadOnly() throws ApfloatRuntimeException { if (isReadOnly()) { return; } if (!isSubsequenced()) { this.length = implGetSize(); } if (this.originalDataStorage == null) { this.isReadOnly = true; } else { this.originalDataStorage.setReadOnly(); } } /** * Gets an array access to the data of this data storage when * the data is treated as a linear block. * * @param mode Access mode for the array access: {@link #READ}, {@link #WRITE} or both. * @param offset Starting position of the array access in the data storage. * @param length Number of accessible elements in the array access. * * @return The array access. * * @exception IllegalArgumentException If the offset or length are out of bounds of the data storage. * @exception IllegalStateException If write access is requested for a read-only data storage. */ public final ArrayAccess getArray(int mode, long offset, int length) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { if (isReadOnly() && (mode & WRITE) != 0) { throw new IllegalStateException("Write access requested for read-only data storage"); } if (offset < 0 || length < 0 || offset + length < 0 || offset + length > getSize()) { throw new IllegalArgumentException("Requested block out of range: offset=" + offset + ", length=" + length + ", available=" + getSize()); } return implGetArray(mode, offset, length); } /** * Gets an array access to the data of this data storage when it is treated as a linear block. * The validity of the arguments of this method do not need to be checked. * * @param mode Access mode for the array access: {@link #READ}, {@link #WRITE} or both. * @param offset Starting position of the array access in the data storage. * @param length Number of accessible elements in the array access. * * @return The array access. */ protected abstract ArrayAccess implGetArray(int mode, long offset, int length) throws ApfloatRuntimeException; /** * Maps a block of data to a memory array when the data is treated as a matrix. * The matrix size is n1 x n2. * The following picture illustrates the block being accessed (in gray): * * * * * * * * * * * *
Matrix
* ← startColumn → * * ← columns → * *
* n1
* ↓
*
* ← n2 *
* * @param mode Whether the array is prepared for reading, writing or both. The value should be {@link #READ}, {@link #WRITE} or a combination of these. * @param startColumn The starting column where data is read. * @param columns The number of columns of data to read. * @param rows The number of rows of data to read. This should be equivalent to n1, number of rows in the matrix. * * @return Access to an array of size columns x rows containing the data. * * @exception IllegalArgumentException If the requested area is out of bounds of the data storage. * @exception IllegalStateException If write access is requested for a read-only data storage. * * @since 1.7.0 */ public final ArrayAccess getArray(int mode, int startColumn, int columns, int rows) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { if (isReadOnly() && (mode & WRITE) != 0) { throw new IllegalStateException("Write access requested for read-only data storage"); } long size = (long) columns * rows; if (startColumn < 0 || columns < 0 || rows < 0 || startColumn + columns < 0 || (long) (startColumn + columns) * rows > getSize()) { throw new IllegalArgumentException("Requested block out of range: startColumn=" + startColumn + ", columns=" + columns + ", rows=" + rows + ", available=" + getSize()); } else if (size > Integer.MAX_VALUE) { throw new ApfloatRuntimeException("Block too large to fit in an array: " + size); } return implGetArray(mode, startColumn, columns, rows); } /** * Maps a block of data to a memory array when the data is treated as a matrix. * The validity of the arguments of this method do not need to be * checked. * * @param mode Whether the array is prepared for reading, writing or both. The value should be {@link #READ}, {@link #WRITE} or a combination of these. * @param startColumn The starting column where data is read. * @param columns The number of columns of data to read. * @param rows The number of rows of data to read. This should be equivalent to n1, number of rows in the matrix. * * @return Access to an array of size columns x rows containing the data. * * @since 1.7.0 */ protected abstract ArrayAccess implGetArray(int mode, int startColumn, int columns, int rows) throws ApfloatRuntimeException; /** * Maps a transposed block of data to a memory array when the data is treated as a matrix. * The matrix size is n1 x n2. The accessed block is illustrated in gray * in the following picture. The argument columns is the value b: * * * * * * * * * * * * * * * * * * * * * * * *
Matrix
* ← startColumn → * * A * *
* n1
* ↓
*
* B *
* C *
* D *
* ← b → *
* ← n2 *
* * The data is read from an n1 x b area of the matrix, in blocks * of b elements, to a b x n1 memory array as follows: * * * * * * * * * * * * * * * * * * * *
Read matrix section
* A * *
* b
* ↓
*
* B *
* C *
* D *
* ← n1 *
* * Each b x b block is transposed, to form the final b x n1 array * in memory, where the columns are located linearly: * * * * * * * * * * * * * *
Transposed matrix section
* A * * B * * C * * D * *
* b
* ↓
*
* ← n1 *
* * @param mode Whether the array is prepared for reading, writing or both. The value should be {@link #READ}, {@link #WRITE} or a combination of these. * @param startColumn The starting column where data is read. * @param columns The number of columns of data to read. * @param rows The number of rows of data to read. This should be equivalent to n1, number of rows in the matrix. * * @return Access to an array of size columns x rows containing the transposed data. * * @exception IllegalArgumentException If the requested area is out of bounds of the data storage. * @exception IllegalStateException If write access is requested for a read-only data storage. */ public final ArrayAccess getTransposedArray(int mode, int startColumn, int columns, int rows) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { if (isReadOnly() && (mode & WRITE) != 0) { throw new IllegalStateException("Write access requested for read-only data storage"); } long size = (long) columns * rows; if (startColumn < 0 || columns < 0 || rows < 0 || startColumn + columns < 0 || (long) (startColumn + columns) * rows > getSize()) { throw new IllegalArgumentException("Requested block out of range: startColumn=" + startColumn + ", columns=" + columns + ", rows=" + rows + ", available=" + getSize()); } else if (size > Integer.MAX_VALUE) { throw new ApfloatRuntimeException("Block too large to fit in an array: " + size); } return implGetTransposedArray(mode, startColumn, columns, rows); } /** * Maps a transposed block of data to a memory array when the data is treated as a matrix. * The validity of the arguments of this method do not need to be * checked. * * @param mode Whether the array is prepared for reading, writing or both. The value should be {@link #READ}, {@link #WRITE} or a combination of these. * @param startColumn The starting column where data is read. * @param columns The number of columns of data to read. * @param rows The number of rows of data to read. This should be equivalent to n1, number of rows in the matrix. * * @return Access to an array of size columns x rows containing the transposed data. */ protected abstract ArrayAccess implGetTransposedArray(int mode, int startColumn, int columns, int rows) throws ApfloatRuntimeException; /** * Constructs a new iterator. Elements can be iterated either * in forward or in reverse order, depending on if startPosition * is less than or greater than endPosition, correspondingly. * * @param mode Access mode for iterator: {@link #READ}, {@link #WRITE} or both. * @param startPosition Starting position of iterator in the data set. For reverse access, the first element in the iterator is startPosition - 1. * @param endPosition End position of iterator in the data set. For forward access, the last accessible element in the iterator is endPosition - 1. * * @return An iterator. * * @exception IllegalArgumentException If the requested area is out of bounds of the data storage. * @exception IllegalStateException If write access is requested for a read-only data storage. */ public abstract Iterator iterator(int mode, long startPosition, long endPosition) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException; /** * Is this object a subsequence of some other object, or do subsequences of this object exist. * * @return true if this object is a subsequence of some other object, or if subsequences of this object exist, false otherwise. */ public final boolean isSubsequenced() { if (this.originalDataStorage == null) { return this.isSubsequenced; } else { return true; } } /** * Is this object cached in memory. * * @return true if this object is cached in memory, false if not. * * @since 1.7.0 */ public abstract boolean isCached(); /** * Return the sub-sequence offset. * * @return Absolute offset of the sub-sequence within the (top-level) base data storage. */ protected final long getOffset() { return this.offset; } private void setSubsequenced() throws ApfloatRuntimeException { if (!isSubsequenced()) { if (!isReadOnly()) { this.length = implGetSize(); // Size can't be changed after this } // This may be called even after the DataStorage has been set to be read-only, but the mutation behaves // consistently even if done from multiple threads at the same time this.isSubsequenced = true; // Subsequences exist for this object } } private static final long serialVersionUID = 1862028601696578467L; private long offset; private long length; private DataStorage originalDataStorage; private boolean isReadOnly; private boolean isSubsequenced; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/DataStorageBuilder.java000066400000000000000000000104761461767713300267140ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; /** * Interface for determining a suitable storage * type for data of some expected size. The factory method * pattern is used for creating the data storages.

* * The storage type can be different based on the size of the * data. For example, it may be beneficial to store small amounts * of data always in memory, for small overhead in access times, * and to store larger objects on disk files, to avoid running * out of memory.

* * Further, an implementing class may provide data storage objects * that store data in disk files, for Java client applications, or * e.g. in a relational database, for an EJB server environment * where files are not allowed to be used. * * @see DataStorage * * @version 1.5.1 * @author Mikko Tommila */ public interface DataStorageBuilder { /** * Get an appropriate type of data storage for the requested size of data.

* * Note that the returned data storage object is not set to have the * requested size, so the client should call the object's {@link DataStorage#setSize(long)} * method before storing data to it. * * @param size The size of data to be stored in the storage, in bytes. * * @return An empty DataStorage object of an appropriate type for storing size bytes of data. */ public DataStorage createDataStorage(long size) throws ApfloatRuntimeException; /** * Get a data storage that is cached in memory, if possible, for the requested size of data.

* * Note that the returned data storage object is not set to have the * requested size, so the client should call the object's {@link DataStorage#setSize(long)} * method before storing data to it. * * @param size The size of data to be stored in the storage, in bytes. * * @return An empty DataStorage object of an appropriate type for storing size bytes of data, cached if possible. * * @since 1.5.1 */ public DataStorage createCachedDataStorage(long size) throws ApfloatRuntimeException; /** * Convert cached data storage to the appropriate normal data storage type.

* * If the data storage already has the appropriate type for its size, the data * storage may be returned unchanged. The argument data storage does not necessarily * have to be created with the {@link #createCachedDataStorage(long)} method, it can * be created as well with the {@link #createDataStorage(long)} method.

* * If the given data storage does not have the appropriate type for its size, then * a new data storage of the appropriate type is created and the data is copied to it.

* * @param dataStorage The data storage to be converted, if necessary. * * @return A DataStorage that can be the original data storage or a copy of it, with the appropriate type. * * @since 1.5.1 */ public DataStorage createDataStorage(DataStorage dataStorage) throws ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/ExecutionBuilder.java000066400000000000000000000031651461767713300264560ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; /** * Interface of a factory for creating execution related objects. * The factory method pattern is used. * * @see ExecutionStrategy * * @since 1.9.0 * @version 1.9.0 * @author Mikko Tommila */ public interface ExecutionBuilder { /** * Creates an object for execution operations. * * @return A suitable object for performing the execution operations. */ public ExecutionStrategy createExecution(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/ExecutionStrategy.java000066400000000000000000000045071461767713300266730ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import java.util.concurrent.Future; /** * Thread execution operations. * * @since 1.9.0 * @version 1.9.0 * @author Mikko Tommila */ public interface ExecutionStrategy { /** * While waiting for a Future to be completed, steal work * from any running tasks and run it.

* * While this method may functionally appear to be equivalent to just * calling future.get() it should try its best to steal * work from any other tasks submitted to the ExecutorService * of the current ApfloatContext. It may in fact steal * work using multiple threads, if the current ApfloatContext * specifies numberOfProcessors to be more than one.

* * The purpose of this method is to allow keeping all threads of the * ExecutorService (and CPU cores) maximally busy at all * times, while also not running an excessive number of parallel * threads (only as many threads as there are CPU cores). * * @param future The Future to wait for. */ public void wait(Future future); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/Factor3NTTStepStrategy.java000066400000000000000000000047661461767713300274620ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; /** * Steps for the factor-3 NTT. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface Factor3NTTStepStrategy { /** * Transform the columns of a matrix using a 3-point transform. * * @param dataStorage0 The data of the first column. * @param dataStorage1 The data of the second column. * @param dataStorage2 The data of the third column. * @param startColumn The starting element index in the data storages to transform. * @param columns How many columns to transform. * @param power2length Length of the column transform. * @param length Length of total transform (three times the length of one column). * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param modulus Index of the modulus. */ public void transformColumns(DataStorage dataStorage0, DataStorage dataStorage1, DataStorage dataStorage2, long startColumn, long columns, long power2length, long length, boolean isInverse, int modulus) throws ApfloatRuntimeException; /** * Get the maximum transform length. * * @return The maximum transform length. */ public long getMaxTransformLength(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/FilenameGenerator.java000066400000000000000000000100201461767713300265570ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatContext; /** * Class for generating filenames for temporary files. * * @version 1.0 * @author Mikko Tommila */ public class FilenameGenerator { /** * Create a new filename generator. The generated filenames will * point to the specified directory path. The base file name is a * sequential number. The specified suffix is appended to the * final file name. * * @param path The path where the file are created. If null, the default file path from the {@link ApfloatContext} is used. * @param initialValue The initial value for the numbers. If null, the default file initial value from the {@link ApfloatContext} is used. * @param suffix The suffix for file names. If null, the default file suffix from the {@link ApfloatContext} is used. * * @exception NumberFormatException If initialValue is not a valid integer number. */ public FilenameGenerator(String path, String initialValue, String suffix) throws NumberFormatException { if (path == null) { ApfloatContext ctx = ApfloatContext.getContext(); path = ctx.getProperty(ApfloatContext.FILE_PATH); } if (initialValue == null) { ApfloatContext ctx = ApfloatContext.getContext(); initialValue = ctx.getProperty(ApfloatContext.FILE_INITIAL_VALUE); } if (suffix == null) { ApfloatContext ctx = ApfloatContext.getContext(); suffix = ctx.getProperty(ApfloatContext.FILE_SUFFIX); } this.path = path; this.value = Long.parseLong(initialValue); this.suffix = suffix; } /** * Generate a filename. The returned filename is unique among * those generated by this filename generator. * * @return A generated file name. */ public synchronized String generateFilename() { return this.path + (this.value++) + this.suffix; } /** * Returns the path setting of this filename generator. * * @return The path setting of this filename generator. */ public String getPath() { return this.path; } /** * Returns the current initial value of the base file names generated. * * @return The current initial value of the base file names generated. */ public synchronized String getInitialValue() { return String.valueOf(this.value); } /** * Returns the suffix setting of this filename generator. * * @return The suffix setting of this filename generator. */ public String getSuffix() { return this.suffix; } private String path; private long value; private String suffix; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/MatrixBuilder.java000066400000000000000000000031401461767713300257500ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; /** * Interface of a factory for creating matrix related objects. * The factory method pattern is used. * * @see MatrixStrategy * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface MatrixBuilder { /** * Creates an object for matrix operations. * * @return A suitable object for performing the matrix operations. */ public MatrixStrategy createMatrix(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/MatrixStrategy.java000066400000000000000000000150311461767713300261660ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; /** * Matrix operations. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface MatrixStrategy { /** * Transpose a n1 x n2 matrix.

* * Both n1 and n2 must be powers of two. * Additionally, one of these must be true:

* * n1 = n2
* n1 = 2*n2
* n2 = 2*n1
* * @param arrayAccess Accessor to the matrix data. This data will be transposed. * @param n1 Number of rows in the matrix. * @param n2 Number of columns in the matrix. */ public void transpose(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException; /** * Transpose a square n1 x n1 block of n1 x n2 matrix.

* * Both n1 and n2 must be powers of two, * and n1 <= n2. * * @param arrayAccess Accessor to the matrix data. This data will be transposed. * @param n1 Number of rows and columns in the block to be transposed. * @param n2 Number of columns in the matrix. */ public void transposeSquare(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException; /** * Permute the rows of the n1 x n2 matrix so that it is shaped like a * n1/2 x 2*n2 matrix. Logically, the matrix is split in half, and the * lower half is moved to the right side of the upper half.

* * Both n1 and n2 must be powers of two, * and n1 >= 2.

* * E.g. if the matrix layout is originally as follows: * * * * * * * * * * * * * * *
Matrix before
0123
4567
891011
12131415
*

* * Then after this method it is as follows: * * * * * * * * *
Matrix after
0123891011
456712131415
* * @param arrayAccess Accessor to the matrix data. This data will be permuted. * @param n1 Number of rows in the matrix. * @param n2 Number of columns in the matrix. * * @since 1.7.0 */ public void permuteToDoubleWidth(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException; /** * Permute the rows of the n1 x n2 matrix so that it is shaped like a * 2*n1 x n2/2 matrix. Logically, the matrix is split in half, and the * right half is moved below the left half.

* * Both n1 and n2 must be powers of two. * * E.g. if the matrix layout is originally as follows: * * * * * * * * *
Matrix before
01234567
89101112131415
*

* * Then after this method it is as follows: * * * * * * * * * * * * * * *
Matrix after
0123
891011
4567
12131415
* * @param arrayAccess Accessor to the matrix data. This data will be permuted. * @param n1 Number of rows in the matrix. * @param n2 Number of columns in the matrix. */ public void permuteToHalfWidth(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/NTTBuilder.java000066400000000000000000000050351461767713300251560ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; /** * Interface of a factory for creating Number Theoretic Transforms. * The factory method pattern is used. * * @see NTTStrategy * @see NTTStepStrategy * * @version 1.7.0 * @author Mikko Tommila */ public interface NTTBuilder { /** * Creates a Number Theoretic Transform of suitable * type for the specified length. * * @param size The transform length that will be used. * * @return A suitable NTT object for performing the transform. */ public NTTStrategy createNTT(long size); /** * Creates an object for implementing the steps of a step-based * Number Theoretic Transform. * * @return A suitable object for performing the transform steps. * * @since 1.7.0 */ public NTTStepStrategy createNTTSteps(); /** * Creates an object for implementing the steps of a three-NTT * based convolution. * * @return A suitable object for performing the convolution steps. * * @since 1.7.0 */ public NTTConvolutionStepStrategy createNTTConvolutionSteps(); /** * Creates an object for implementing the steps of factor-3 NTT. * * @return A suitable object for performing the factor-3 NTT steps. * * @since 1.7.0 */ public Factor3NTTStepStrategy createFactor3NTTSteps(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/NTTConvolutionStepStrategy.java000066400000000000000000000052211461767713300304630ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; /** * Steps for a three-NTT convolution. This includes element-by-element * multiplication and squaring of the transformed data. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface NTTConvolutionStepStrategy { /** * Linear multiplication in the number theoretic domain. * The operation is sourceAndDestination[i] *= source[i] (mod m).

* * For maximum performance, sourceAndDestination * should be in memory if possible. * * @param sourceAndDestination The first source data storage, which is also the destination. * @param source The second source data storage. * @param modulus Which modulus to use (0, 1, 2) */ public void multiplyInPlace(DataStorage sourceAndDestination, DataStorage source, int modulus) throws ApfloatRuntimeException; /** * Linear squaring in the number theoretic domain. * The operation is sourceAndDestination[i] *= sourceAndDestination[i] (mod m).

* * For maximum performance, sourceAndDestination * should be in memory if possible. * * @param sourceAndDestination The source data storage, which is also the destination. * @param modulus Which modulus to use (0, 1, 2) */ public void squareInPlace(DataStorage sourceAndDestination, int modulus) throws ApfloatRuntimeException; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/NTTStepStrategy.java000066400000000000000000000073051461767713300262300ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; /** * Steps for the six-step or two-pass NTT. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public interface NTTStepStrategy { /** * Multiply each matrix element (i, j) by wi * j / totalTransformLength. * The matrix size is n1 x n2. * * @param arrayAccess The memory array to multiply. * @param startRow Which row in the whole matrix the starting row in the arrayAccess is. * @param startColumn Which column in the whole matrix the starting column in the arrayAccess is. * @param rows The number of rows in the arrayAccess to multiply. * @param columns The number of columns in the matrix (= n2). * @param length The length of data in the matrix being transformed. * @param totalTransformLength The total transform length, for the scaling factor. Used only for the inverse case. * @param isInverse If the multiplication is done for the inverse transform or not. * @param modulus Index of the modulus. */ public void multiplyElements(ArrayAccess arrayAccess, int startRow, int startColumn, int rows, int columns, long length, long totalTransformLength, boolean isInverse, int modulus) throws ApfloatRuntimeException; /** * Transform the rows of the data matrix. * If only one processor is available, it runs all transforms in the current * thread. If more than one processor are available, it dispatches the calculations * to multiple threads to parallelize the calculation. The number of processors is * determined using {@link ApfloatContext#getNumberOfProcessors()}. * * @param arrayAccess The memory array to split to rows and to transform. * @param length Length of one transform (one row). * @param count Number of rows. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param permute If permutation should be done. * @param modulus Index of the modulus. */ public void transformRows(ArrayAccess arrayAccess, int length, int count, boolean isInverse, boolean permute, int modulus) throws ApfloatRuntimeException; /** * Get the maximum transform length. * * @return The maximum transform length. */ public long getMaxTransformLength(); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/NTTStrategy.java000066400000000000000000000062551461767713300253770ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; /** * Number Theoretic Transform (NTT) strategy. * An implementing class could be e.g. * *

    *
  • Fast Number Theoretic Transform (FNT)
  • *
  • "Four-step" FNT
  • *
  • "Two-pass" mass storage FNT
  • *
  • Winograd Fourier Transform Algorithm (WFTA)
  • *
*

* * Note: an implementing transformation class is required only to be able * to perform an inverse transform on data transformed by the same class, * not by any other class. * * @version 1.0 * @author Mikko Tommila */ public interface NTTStrategy { /** * Perform a forward transform on the data.

* * Multiple moduli can be used, if the convolution algorithm * uses the Chinese Remainder Theorem to calculate the final * result. * * @param dataStorage The data to be transformed. * @param modulus Number of modulus to use (in case the transform supports multiple moduli). */ public void transform(DataStorage dataStorage, int modulus) throws ApfloatRuntimeException; /** * Perform an inverse transform on the data.

* * Multiple moduli can be used, if the convolution algorithm * uses the Chinese Remainder Theorem to calculate the final * result. * * @param dataStorage The data to be transformed. * @param modulus Number of modulus to use (in case the transform supports multiple moduli). * @param totalTransformLength Total transform length; the final result elements are divided by this value. */ public void inverseTransform(DataStorage dataStorage, int modulus, long totalTransformLength) throws ApfloatRuntimeException; /** * Return the supported transform length for the specified data size. * * @param size Length of the data to be transformed. * * @return Length of the transform needed by this transform. */ public long getTransformLength(long size); } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/RadixConstants.java000066400000000000000000000057761461767713300261620ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; /** * Constants related to different radixes. * * @version 1.0 * @author Mikko Tommila */ public interface RadixConstants { /** * Factors of numbers 2, ..., 36. For 2 <= radix <= 36, * RADIX_FACTORS[radix] contains an array of * integers containing the different factors of the radix. */ public static final int RADIX_FACTORS[][] = { null, null, { 2 }, { 3 }, { 2 }, { 5 }, { 2, 3 }, { 7 }, { 2 }, { 3 }, { 2, 5 }, { 11 }, { 2, 3 }, { 13 }, { 2, 7 }, { 3, 5 }, { 2 }, { 17 }, { 2, 3 }, { 19 }, { 2, 5 }, { 3, 7 }, { 2, 11 }, { 23 }, { 2, 3 }, { 5 }, { 2, 13 }, { 3 }, { 2, 7 }, { 29 }, { 2, 3, 5 }, { 31 }, { 2 }, { 3, 11 }, { 2, 17 }, { 5, 7 }, { 2, 3 } }; /** * Precision of a float in the digits of each radix. */ public static final int FLOAT_PRECISION[] = { -1, -1, 24, 16, 12, 11, 10, 9, 8, 8, 8, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5 }; /** * Precision of a double in the digits of each radix. */ public static final int DOUBLE_PRECISION[] = { -1, -1, 53, 34, 27, 23, 21, 19, 18, 17, 16, 16, 15, 15, 14, 14, 14, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11 }; /** * Precision of a long in the digits of each radix. */ public static final int LONG_PRECISION[] = { -1, -1, 63, 40, 32, 28, 25, 23, 21, 20, 19, 19, 18, 18, 17, 17, 16, 16, 16, 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 13, 13 }; /** * How many digits maximally fit in a long in each radix. */ public static final int LONG_DIGITS[] = { -1, -1, 63, 39, 31, 27, 24, 22, 21, 19, 18, 18, 17, 17, 16, 16, 15, 15, 15, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 12 }; } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/Util.java000066400000000000000000000336001461767713300241160ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import java.util.Iterator; import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.apfloat.Apfloat; import org.apfloat.OverflowException; /** * Miscellaneous utility methods. * * @version 1.13.0 * @author Mikko Tommila */ public class Util { private Util() { } /** * Round down to nearest power of two. * * @param x The input value, which must be non-negative. * * @return x rounded down to the nearest power of two. */ public static int round2down(int x) { assert (x >= 0); return Integer.highestOneBit(x); } /** * Round down to nearest power of two. * * @param x The input value, which must be non-negative. * * @return x rounded down to the nearest power of two. */ public static long round2down(long x) { assert (x >= 0); return Long.highestOneBit(x); } /** * Round up to nearest power of two. * * @param x The input value, which must be non-negative and not greater than 230. * * @return x rounded up to the nearest power of two. */ public static int round2up(int x) { assert (x >= 0); assert (x <= 0x40000000); if (x == 0) { return 0; } int r = 1; while (r < x) { r += r; } return r; } /** * Round up to nearest power of two. * * @param x The input value, which must be non-negative and not greater than 262. * * @return x rounded up to the nearest power of two. */ public static long round2up(long x) { assert (x >= 0); assert (x <= 0x4000000000000000L); if (x == 0) { return 0; } long r = 1; while (r < x) { r += r; } return r; } /** * Round down to nearest power of two or three times a power of two. * * @param x The input value, which must be non-negative. * * @return x rounded down to nearest power of two or three times a power of two. */ public static int round23down(int x) { assert (x >= 0); if (x == 0) { return 0; } int r = 1, p = 0; while (r <= x && r > 0) // Detect overflow { p = r; if (r == 1) { r = 2; } else if (r == (r & -r)) { r = r / 2 * 3; } else { r = r / 3 * 4; } } return p; } /** * Round down to nearest power of two or three times a power of two. * * @param x The input value, which must be non-negative. * * @return x rounded down to nearest power of two or three times a power of two. */ public static long round23down(long x) { assert (x >= 0); if (x == 0) { return 0; } long r = 1, p = 0; while (r <= x && r > 0) // Detect overflow { p = r; if (r == 1) { r = 2; } else if (r == (r & -r)) { r = r / 2 * 3; } else { r = r / 3 * 4; } } return p; } /** * Round up to nearest power of two or three times a power of two. * * @param x The input value, which must be non-negative and not greater than 3 * 229. * * @return x rounded up to the nearest power of two or three times a power of two. */ public static int round23up(int x) { assert (x >= 0); assert (x <= 0x60000000); if (x == 0) { return 0; } int r = 1; while (r < x) { if (r == 1) { r = 2; } else if (r == (r & -r)) { r = r / 2 * 3; } else { r = r / 3 * 4; } } return r; } /** * Round up to nearest power of two or three times a power of two. * * @param x The input value, which must be non-negative and not greater than 3 * 261. * * @return x rounded up to the nearest power of two or three times a power of two. */ public static long round23up(long x) { assert (x >= 0); assert (x <= 0x6000000000000000L); if (x == 0) { return 0; } long r = 1; while (r < x) { if (r == 1) { r = 2; } else if (r == (r & -r)) { r = r / 2 * 3; } else { r = r / 3 * 4; } } return r; } /** * Square root rounded down to nearest power of two. * * @param x The input value, which must be non-negative. * * @return Square root of x rounded down to nearest power of two. */ public static int sqrt4down(int x) { assert (x >= 0); if (x == 0) { return 0; } int r = 1; while ((x >>= 2) > 0) { r <<= 1; } return r; } /** * Square root rounded down to nearest power of two. * * @param x The input value, which must be non-negative. * * @return Square root of x rounded down to nearest power of two. */ public static long sqrt4down(long x) { assert (x >= 0); if (x == 0) { return 0; } long r = 1; while ((x >>= 2) > 0) { r <<= 1; } return r; } /** * Square root rounded up to nearest power of two. * * @param x The input value, which must be non-negative. * * @return Square root of x rounded up to nearest power of two. */ public static int sqrt4up(int x) { assert (x >= 0); if (x == 0) { return 0; } int r = 1, p = 1; while (p < x && p > 0) // Detect overflow { p <<= 2; r <<= 1; } return r; } /** * Square root rounded up to nearest power of two. * * @param x The input value, which must be non-negative. * * @return Square root of x rounded up to nearest power of two. */ public static long sqrt4up(long x) { assert (x >= 0); if (x == 0) { return 0; } long r = 1, p = 1; while (p < x && p > 0) // Detect overflow { p <<= 2; r <<= 1; } return r; } /** * Base-2 logarithm rounded down to nearest power of two. * * @param x The input value, which must be positive. * * @return log2(x) rounded down to nearest integer. */ public static int log2down(int x) { assert (x > 0); return 31 - Integer.numberOfLeadingZeros(x); } /** * Base-2 logarithm rounded down to nearest power of two. * * @param x The input value, which must be positive. * * @return log2(x) rounded down to nearest integer. */ public static int log2down(long x) { assert (x > 0); return 63 - Long.numberOfLeadingZeros(x); } /** * Base-2 logarithm rounded up to nearest power of two. * * @param x The input value, which must be positive. * * @return log2(x) rounded up to nearest integer. */ public static int log2up(int x) { assert (x > 0); return log2down(x) + (x == (x & -x) ? 0 : 1); } /** * Base-2 logarithm rounded up to nearest power of two. * * @param x The input value, which must be positive. * * @return log2(x) rounded up to nearest integer. */ public static int log2up(long x) { assert (x > 0); return log2down(x) + (x == (x & -x) ? 0 : 1); } /** * Returns the argument y limited to Apfloat.INFINITE. * In case x is Apfloat.INFINITE, then Apfloat.INFINITE * is returned, otherwise y. Also if y is negative or zero, this is * treated as a case of overflow, and Apfloat.INFINITE is returned. The * return value is thus always positive. * * @param x The argument that is tested to be Apfloat.INFINITE. * @param y The argument that is returned if x is not Apfloat.INFINITE. * * @return (x == Apfloat.INFINITE || y <= 0 ? Apfloat.INFINITE : y) */ public static long ifFinite(long x, long y) { return (x == Apfloat.INFINITE || y <= 0 ? Apfloat.INFINITE : y); } /** * Returns the maximum of the arguments. * * @param x The first argument. * @param y More arguments. * * @return The maximum of the arguments */ public static long max(long x, long... y) { long max = x; for (int i = 0; i < y.length; i++) { max = Math.max(max, y[i]); } return max; } /** * Returns the minimum of the arguments. * * @param x The first argument. * @param y More arguments. * * @return The minimum of the arguments */ public static long min(long x, long... y) { long min = x; for (int i = 0; i < y.length; i++) { min = Math.min(min, y[i]); } return min; } /** * Returns the product of the arguments, throwing an exception if the result overflows a long. * * @param x The first operand. * @param y The second operand. * * @return The result. * * @throws OverflowException If the result overflows a long */ public static long multiplyExact(long x, long y) throws OverflowException { try { return Math.multiplyExact(x, y); } catch (ArithmeticException ae) { throw new OverflowException("Overflow", ae); } } /** * Returns the sum of the arguments, throwing an exception if the result overflows a long. * * @param x The first operand. * @param y The second operand. * * @return The result. * * @throws OverflowException If the result overflows a long */ public static long addExact(long x, long y) throws OverflowException { try { return Math.addExact(x, y); } catch (ArithmeticException ae) { throw new OverflowException("Overflow", ae); } } /** * Returns the difference of the arguments, throwing an exception if the result overflows a long. * * @param x The first operand. * @param y The second operand. * * @return The result. * * @throws OverflowException If the result overflows a long */ public static long subtractExact(long x, long y) throws OverflowException { try { return Math.subtractExact(x, y); } catch (ArithmeticException ae) { throw new OverflowException("Overflow", ae); } } /** * Convert iterator to stream. * * @param The type. * @param iterator The iterator. * * @return The stream. * * @since 1.12.0 */ public static Stream stream(Iterator iterator) { Iterable iterable = () -> iterator; return StreamSupport.stream(iterable.spliterator(), false); } } apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/doc-files/000077500000000000000000000000001461767713300242015ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/doc-files/spi-classes.gif000066400000000000000000000243401461767713300271210ustar00rootroot00000000000000GIF89ae3f3333f333ff3fffff3f3f̙3f3333f3333333333f3333333f3f33ff3f3f3f3333f3333333f3̙333333f333ff3ffffff3f33f3ff3f3f3ffff3fffffffffff3fffffff3fff̙ffff3fffff3f̙3333f33̙3ff3ffff̙f3f̙3f̙̙3f̙3f3333f333ff3fffff̙̙3̙f̙̙̙3f̙3f3f3333f333ff3fffff3f3f̙3f!,e H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠC;ӨS^ͺװc2۸s˦= WR/UNУK|ku׏fνã~RCы_Ͼg:hϿ=PT& rvr5`Vhڅ|r)ANh5D}(Ё+f(4hY浸r.zHzוȔS#B:8P0&dPF)TKzbXji/vYbc^y%SL1E]g[\9b!*1nG~mVnEEW䠇.܎n騧N5)箻^~/\k\'e;r7/WR*cGwSTzo㟯~/oO x!L | :a 'H Rǂ̠# z KCHp-#< W¿0^R(RáwC@ bRh("CēP" (*Z1TH,r`$H2ofLχ5k#Hɱxc>Qt| 9@t!F^m$KIZ$&7IUi >)RC<*WTt+cIZrg̥.]%0ILbf:30|4yhRl5ne 8qB:0v)'+T8ظ)'U~f52bFC-*I_)+u;ZXgUUFaNƉqEL"B7FyIoYI%K9*qJ YX6.:eK*;=kɗ]ofO_"e0SYysܪ=w΄44^òF5:.jC4V-Lt%}fUu4&!=&.ɩ=lc7=& -jZ%W[nLfN"u9l?:6c9djWYٖm nhU4=hl{ޗw cp4|𞤼˽od҅z8֭o''mn={6Kh+/ߣMp"ϸzGܼqkޝ[$9{qG34;}r??7ȟ&;E>(yŝYGDeC}u}3}6G\w$v~{>Gr_=ܒi>kϝu:a2oh#]υ*>t+~o1\Moۖԏ~i=/9%*tfE|ۗxo>:WՋow/qw_ݏ~'p>M?~ԗWgIFy[77tnwzg}~A}րy{zH%XH {nywwygd}w}@m1}ׂxx;M?7%'7F耘G0>G腄dGWX7WAn6vhGR׃8Q{(:(԰3݁" px(4"(Hu8҉@h'f_pCf"ϣfD;)=m##h.S=B$TH &?)x78IE&8WSm)ḋ*刌X;GH,lHc^6q)26BĐJe[[I5/Q9Y?3$ &)~ՔF&@t\hvd0^6Yt@/iQғ](DC@EOGY<6>Ʉ\3AQYzuS P&jrԕQTafxO@j qNҏp-VV$ӥ"OY^hƘ-bɲ(W,-J/ 6Z9]t.iɒk_?"!C6"6YMvG#Yx_w5V/yY5L8^i-9&;RI_y/)afi*Y))XB4uh`^'g',9wr3Z XҥI /3 -7L)e1Z9/I_9jTrЩ 4%& #Xe嘺" "YɆJ^,BGz82>.;,:SZ3F3c+5 _1d@1c y*cڦhF:DU'R.u) 93I"`uZJ4U:Z4\R  e- Zj'ʛ 2"姚ʩ:@o%zZZi:7'y RJj+*2-ygJ_ZZکM$c!ڠڥ?t)": ꊢ4j1JCWʧ$ Iڣ#)a:JҪ /tʲY;ڧsI{"+ 'KO +۰izY۳iz^r*3kʣ^ۘGKk^:a)+jYJx \Sew zek)2J:V" nX 'y& ښeJ53|[2yK3b**oj_]{˜?*!:+s3\IBK_B6jXb˝!I9:V>4{I}PY*r^I Ћk/G0˼jֽ[ei+8i܋q!WɾMcKɛ-ipK9a3Kv) [+[c\(Ž؇ِ=ْ]ٔ}ٖٜ٘ٚٞڠ=ʢ}ڣڪڬڮڣ;==۶]۸}ۺۼ۾=]ܯڵҋ-ԣq; üxA }Aս ؊=۝1-ݑԍQLm-ƔaQ=5} ^1^ Ln  =97N2QK>ޝF`l|B~QMah NO!p>q>1M`^ RlPOa3~舁犞1~g玮~~>ߎa!ߢnL[>1wN=M~籞N,N~Q~8>si~쀾>>@a!~~~ή䰮n>~po.sn¾__N﫳.1ߔ}>4&o_9.Ck|- uNm([]?%acoكe/cV/oqORuO_(}%1э-[^syڭM长)/7h18ˢ!$E~1ϸ!O؈O#?8/^$狅A$rX~?'E=/qO@ DPB >(0 "^ĘQFNQH% DaRJ-HL3)SΓ( BE:ŤMn\TԅRZrϬ]FV#XeiVmDkݶv JuśW^}/W FX /Y2b]OƜY /oZ4尟G&j֭5w^hlگ!ʮ;0lu˻aaWx9B6wN:MVgn}-r '"}>|U.q? P@ 3=TA#RЦ گ CDoC "D kмUJBA|El G2%{LN oDY4E%ɤ=&JrD-3jB t̲TS'6K0"-KӜOKW-R+1-QKzTуbڕ^K=Ho4b )p`sVkYgCi,cY`)d[=OTs'ۿmr7WS9W-vfY+{sEM9?ji8T%K:O9W鍸+1NP5YVV5`}Y֘-^dUyRPeyg>ۡy9^3X7FyKw&덣Vfu[cg9n=e3.R8doJ Z{M^v.>.g'7?|پ&5wp\/?\Y^:psko]c_jO\/}'7mYwaO) GꘟzΚq֞}gocݱwweYȥ~|PZg?q# @5w$>~[ ܏xc`nzCcgU'm  k(UC .Q|򩏭h2^Eъ9dقš0C fC!YL!V6E,M`b$"XE$TT,PfdBAquHDRE#$c V́]H8FYBZra(I7q$4\(xR1||p]^0"K742CH565 &,Ր/:RdjڼfgGjfb&%aة.Sg{m+$E9~&!tuӘ$m%x7 ̖&=(S'Kyu,gؠxiTHm%G*T-ݫZ {PxϏ~fY`|]9*5|eh_jXU:k\sjV.4-XW6,MMNu`К3Q]_EWO ?xҷg@?߰ČTY*D ;P@ l @ @@`4| Ddf APlAAA?Ю<!T$ #\#TBk'ԣl?(, @ B3Bj@,d ,B0|?24Cɓ<2aB/5?%lC87 9C=lPC>|)$DB.,ĎC/DD?G3? C(\J$DM )dF[E&zFIdFF8F9J\kDgFIF"XEOLB3GGt\ԤL4E4N $MtGlFdtϱN|o FLD,OM COU 4G< ׋ LO :%5QtKeuQBDP- KBRQ +#E$%L%]'(}QG)B+,P&N/0S>R>S<1U5BQ6 @892E:N<=eN.4N@A%T1Ӝ,LEet&mTIiRTMX'T N%R OS?UeVm5QuYՙ8T:UZ^Om]5Nab5VU8$V\cugUGVmVhbTkn`UjMqr-dm5ueWq?UvytMV%WzW>#}X9ׁE؄~%€MU؈l=Ƀ؋؜`X!X،Y-Xא5ٓwUEٖuYdEUeٗٚ]R ֙ٝuّВ٠ٍuMڤOEUڧMXA=MګUO}N+.}ZZ ۵VTRHeۺ]ױeMSA[۶Y"5UAeUMA=V}K- ȵ^Ucܽ|L uiURED\;]ԅ"]x-]=E\u]}]5^]3u^\$8}M' 1(e=)ny :ө%%5N>E4:S{0ⲹ]"54p^l53}kp ؊&6FVfvfaU⭈Z6~[[ !&"6#F$V%f&v'()*+,-./01&263F4V$6v789:;<='@^0Y,FDfсMڸb VPJde9 NVkpK&R^P1SVUPY:fX+Y[N]^`_b6fלäcffvghijklmnop;apfloat-1.14.0/apfloat/src/main/java/org/apfloat/spi/package-info.java000066400000000000000000000172711461767713300255330ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ /** The apfloat Service Provider Interface (SPI).

The apfloat API is a high-level API that defines algorithms on the level of e.g. the Newton iteration for the inverse of a number. Behind this high-level API there is a lot of low-level functionality that makes all the arbitrary precision arithmetic happen. The digits of a large number are stored in an array of ints, for example. In fact, an {@link org.apfloat.Apfloat} is structurally just a pointer to an {@link org.apfloat.spi.ApfloatImpl}, and most of the functionality of the Apfloat class is simply delegated to the underlying ApfloatImpl.

The apfloat SPI defines the general interface for the low-level things that must happen behind the scenes of the high-level API. An actual implementation of the SPI can be optimized for different things, for example:

  • Size of numbers: different algorithms are efficient for numbers with with 1000 or 1000000 digits. This applies both to the actual storage method of the data, and the mathematical algorithms used for e.g. multiplying numbers.
  • Memory consumption vs. performance: different types of Fast Fourier Transform (FFT) based algorithms can be used to find a suitable trade-off between memory consumption and performance.
  • Hardware architecture: 32-bit and 64-bit systems handle int and long type elements correspondingly most efficiently, for example. Some systems perform floating-point operations (with float or double type elements) faster than integer operations (int or long).
  • Complexity: a more complex implementation may be optimized for different cases, however more code will take more space and use more memory. This may be a concern on some systems (e.g. mobile devices).
A Service Provider is only required to implement the {@link org.apfloat.spi.BuilderFactory} interface, and actually only the {@link org.apfloat.spi.BuilderFactory#getApfloatBuilder()} method in this interface. All apfloat implementations ({@link org.apfloat.spi.ApfloatImpl}) are created through the {@link org.apfloat.spi.ApfloatBuilder} interface's methods. The rest of the interfaces in the SPI exist only for the convenience of the default apfloat SPI implementations ({@link org.apfloat.internal}).

The apfloat SPI suggests the usage of various patterns, as encouraged by the specification of all the interfaces in the SPI. These patterns include:

  • Abstract factory pattern, for getting instances of the various builders, as well as other types of components built by the different builders ({@link org.apfloat.spi.ApfloatBuilder}, {@link org.apfloat.spi.DataStorageBuilder}, {@link org.apfloat.spi.ConvolutionBuilder}, {@link org.apfloat.spi.NTTBuilder}).
  • Factory method pattern; obviously the abstract factories use factory methods to create instances of objects.
  • Builder pattern: an {@link org.apfloat.spi.ApfloatImpl} needs various "parts" for its structural construction ({@link org.apfloat.spi.DataStorage}) as well as its behavior ({@link org.apfloat.spi.ConvolutionStrategy}). Builders are used to build the different sub-parts needed, and the ApfloatImpl itself only knows the high-level algorithm for how the parts are used and related. The construction of the sub-part details is left for the builders, and the ApfloatImpl accesses the parts only via an interface.
  • Strategy pattern: for multiplying numbers, completely different algorithms are optimal, depending on the size of the numbers. The {@link org.apfloat.spi.ConvolutionStrategy} defines different convolution algorithms to be used in the multiplication. For very large numbers, a transform-based convolution can be used, and even a different transform strategy can be specified via the {@link org.apfloat.spi.NTTStrategy} interface.
  • Iterators are used for iterating through {@link org.apfloat.spi.DataStorage} elements in a highly flexible manner. The base class is {@link org.apfloat.spi.DataStorage.Iterator}. For example, a data storage that uses a simple array to store the entire data set in memory can return a simple iterator that goes through the array element by element. In comparison, a data storage that stores the data in a disk file, can have an iterator that reads blocks of data from the file to a memory array, and then iterates through the array, one block at a time.
  • Singleton pattern, assumed to be used in the {@link org.apfloat.spi.BuilderFactory} class, as there should be no need to have more than one instance of each builder class. Also the BuilderFactory instance itself is a singleton, within an {@link org.apfloat.ApfloatContext}.
  • Bridge pattern: the SPI itself is the bridge pattern. An {@link org.apfloat.Apfloat} provides a simple high-level programming interface and the complex technical implementation details are delegated to an {@link org.apfloat.spi.ApfloatImpl}. The Apfloat class can be subclassed for additional functionality, and independent of that, different subclasses of an ApfloatImpl can be used to optimize the implementation.
Associations of the SPI classes are shown in a class diagram format below:

Class diagram

The class implementing {@link org.apfloat.spi.BuilderFactory} that is used in creating apfloat implementations is defined in the {@link org.apfloat.ApfloatContext}. You can set the BuilderFactory instance programmatically by calling {@link org.apfloat.ApfloatContext#setBuilderFactory(BuilderFactory)}, for example:

BuilderFactory builderFactory = new MyBuilderFactory();
ApfloatContext.getContext().setBuilderFactory(builderFactory);
It's a lot easier to specify this to happen automatically whenever your program starts. To do this just specify the BuilderFactory class name in the apfloat.properties file (or the apfloat ResourceBundle if you use one). For example, the apfloat.properties file might contain the line:
builderFactory=org.mycompany.MyBuilderFactory
For more details about configuring the apfloat BuilderFactory, see the documentation for {@link org.apfloat.ApfloatContext}. @see org.apfloat.internal */ package org.apfloat.spi; apfloat-1.14.0/apfloat/src/main/java9/000077500000000000000000000000001461767713300174155ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java9/org/000077500000000000000000000000001461767713300202045ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java9/org/apfloat/000077500000000000000000000000001461767713300216325ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java9/org/apfloat/internal/000077500000000000000000000000001461767713300234465ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/java9/org/apfloat/internal/LongBaseMath.java000066400000000000000000000266071461767713300266300ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable; import java.math.BigInteger; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import static org.apfloat.internal.LongModConstants.*; import static org.apfloat.internal.LongRadixConstants.*; /** * Mathematical operations on numbers in a base. * Implementation for the long type. * * @version 1.9.0 * @author Mikko Tommila */ public class LongBaseMath implements Serializable { /** * Creates a base math using the specified radix. * * @param radix The radix that will be used. */ public LongBaseMath(int radix) { this.radix = radix; this.inverseBase = 1.0 / BASE[radix]; this.inverseBaseLong = INVERSE_BASE[radix]; } /** * Addition in some base. Adds the data words * of src1 and src2 and stores the result to * dst. src2 may be null, in * which case it is ignored (only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] + src2[i]. * * @param src1 First source data sequence. Can be null, in which case it's ignored. * @param src2 Second source data sequence. Can be null, in which case it's ignored. * @param carry Input carry bit. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the addition of the last (leftmost) word in the accessed sequence. */ public long baseAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, long carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); boolean sameDst = (src1 == dst || src2 == dst); long base = BASE[this.radix]; for (long i = 0; i < size; i++) { long result = (src1 == null ? 0 : src1.getLong()) + carry + (src2 == null ? 0 : src2.getLong()); carry = (result >= base ? 1 : 0); result -= (result >= base ? base : 0); dst.setLong(result); if (src1 != null) src1.next(); if (src2 != null) src2.next(); if (!sameDst) dst.next(); } return carry; } /** * Subtraction in some base. Subtracts the data words * of src1 and src2 and stores the result to * dst. src1 and src2 may be * null, in which case they are ignored (the values are assumed * to be zero and only the carry is propagated).

* * Essentially calculates dst[i] = src1[i] - src2[i]. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param carry Input carry bit. This is subtracted from the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry bit. Propagated carry bit from the subtraction of the last (leftmost) word in the accessed sequence. The value is 1 if the carry is set, and 0 otherwise. */ public long baseSubtract(DataStorage.Iterator src1, DataStorage.Iterator src2, long carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 == null || src1 != src2); assert (src2 != dst); long base = BASE[this.radix]; for (long i = 0; i < size; i++) { long result = (src1 == null ? 0 : src1.getLong()) - carry - (src2 == null ? 0 : src2.getLong()); carry = (result < 0 ? 1 : 0); result += (result < 0 ? base : 0); dst.setLong(result); if (src1 != null && src1 != dst) src1.next(); if (src2 != null) src2.next(); dst.next(); } return carry; } /** * Multiplication and addition in some base. Multiplies the data words * of src1 by src3 and adds the result to the * words in src2, and stores the result to dst. * src2 may be null, in which case it is ignored * (the values are assumed to be zero).

* * Assumes that the result from the addition doesn't overflow the upper * result word (to larger than the base). This is the case e.g. when using * this method to perform an arbitrary precision multiplication.

* * Essentially calculates dst[i] = src1[i] * src3 + src2[i]. * * @param src1 First source data sequence. * @param src2 Second source data sequence. Can be null, in which case it's ignored, or can be the same as dst. * @param src3 Multiplicand. All elements of src1 are multiplied by this value. * @param carry Input carry word. This is added to the first (rightmost) word in the accessed sequence. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Overflow carry word. Propagated carry word from the multiplication and addition of the last (leftmost) word in the accessed sequence. */ public long baseMultiplyAdd(DataStorage.Iterator src1, DataStorage.Iterator src2, long src3, long carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != src2); assert (src1 != dst); long base = BASE[this.radix]; for (long i = 0; i < size; i++) { long a = src1.getLong(), b = src3; carry += (src2 == null ? 0 : src2.getLong()); final long SHIFT = 64 - 2 * (64 - MAX_POWER_OF_TWO_BITS), MASK = (1L << SHIFT) - 1; long tmp = a * b, tmp2 = ((tmp & MASK) + (carry & MASK) >>> SHIFT) + (tmp >>> SHIFT) + (carry >>> SHIFT); tmp += carry; tmp2 += Math.multiplyHigh(a, b) << 2 * (64 - MAX_POWER_OF_TWO_BITS); carry = Math.multiplyHigh(tmp2, this.inverseBaseLong); tmp -= carry * base; carry += (tmp >= base ? 1 : 0); tmp -= (tmp >= base ? base : 0); dst.setLong(tmp); // = a * b % base src1.next(); if (src2 != null && src2 != dst) src2.next(); dst.next(); } return carry; } /** * Division in some base. Divides the data words * of src1 by src2 and stores the result to * dst. src1 may be null, * in which case it is ignored (the values are assumed to be * zero and only the carry division is propagated).

* * Essentially calculates dst[i] = src1[i] / src2. * * @param src1 First source data sequence. Can be null, in which case the input values are assumed to be zero. * @param src2 Divisor. All elements of src1 are divided by this value. * @param carry Input carry word. Used as the upper word for the division of the first input element. This should be the remainder word returned from the previous block processed. * @param dst Destination data sequence. * @param size Number of elements to process. * * @return Remainder word of the propagated division of the last (rightmost) word in the accessed sequence. */ public long baseDivide(DataStorage.Iterator src1, long src2, long carry, DataStorage.Iterator dst, long size) throws ApfloatRuntimeException { assert (src1 != dst); long base = BASE[this.radix]; double inverseDivisor = 1.0 / src2; for (long i = 0; i < size; i++) { long a = (src1 == null ? 0 : src1.getLong()), tmp = carry * base + a, result = (long) (((double) carry * (double) base + (double) a) * inverseDivisor); carry = tmp - result * src2; int tmp2 = (int) ((double) carry * inverseDivisor); result += tmp2; carry -= tmp2 * src2; result += (carry >= src2 ? 1 : 0); carry -= (carry >= src2 ? src2 : 0); result += (carry >= src2 ? 1 : 0); carry -= (carry >= src2 ? src2 : 0); result -= (carry < 0 ? 1 : 0); carry += (carry < 0 ? src2 : 0); result -= (carry < 0 ? 1 : 0); carry += (carry < 0 ? src2 : 0); dst.setLong(result); // = carry * base % src2 if (src1 != null) src1.next(); dst.next(); } return carry; } int radix() { return this.radix; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.inverseBaseLong = INVERSE_BASE[this.radix]; } private static final long serialVersionUID = -6469225916787810664L; private static final long[] INVERSE_BASE; static { INVERSE_BASE = new long[Character.MAX_RADIX + 1]; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { INVERSE_BASE[radix] = BigInteger.ONE.shiftLeft(2 * MAX_POWER_OF_TWO_BITS).divide(BigInteger.valueOf(BASE[radix])).longValueExact(); } } private int radix; @SuppressWarnings("unused") // Kept only for serialization compatibility private double inverseBase; private transient long inverseBaseLong; } apfloat-1.14.0/apfloat/src/main/java9/org/apfloat/internal/LongCRTMath.java000066400000000000000000000175361461767713300264070ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import static org.apfloat.internal.LongModConstants.*; import static org.apfloat.internal.LongRadixConstants.*; import java.io.IOException; import java.io.ObjectInputStream; import java.math.BigInteger; /** * Basic arithmetic for calculating the Chinese Remainder * Theorem. Works for the long type. * * @version 1.9.0 * @author Mikko Tommila */ public class LongCRTMath extends LongBaseMath { /** * Creates a carry-CRT math using the specified radix. * * @param radix The radix that will be used. */ public LongCRTMath(int radix) { super(radix); this.base = BASE[radix]; this.inverseBase = 1.0 / BASE[radix]; this.inverseBaseLong = INVERSE_BASE[radix]; } /** * Multiplies two words by one word to produce a result of three words. * Most significant word is stored first. * * @param src Source array, first multiplicand. * @param factor Second multiplicand. * @param dst Destination array. */ public final void multiply(long[] src, long factor, long[] dst) { long tmp = src[1] * factor, carry = Math.multiplyHigh(src[1], factor) << 64 - MAX_POWER_OF_TWO_BITS | tmp >>> MAX_POWER_OF_TWO_BITS; dst[2] = tmp & BASE_MASK; // = tmp % MAX_POWER_OF_TWO_BASE tmp = src[0] * factor; long tmp2 = (tmp & BASE_MASK) + carry; carry = (Math.multiplyHigh(src[0], factor) << 64 - MAX_POWER_OF_TWO_BITS) + (tmp >>> MAX_POWER_OF_TWO_BITS) + (tmp2 >>> MAX_POWER_OF_TWO_BITS); dst[1] = tmp2 & BASE_MASK; // = tmp % MAX_POWER_OF_TWO_BASE dst[0] = carry; } /** * Compares three words. Most significant word is stored first. * * @param src1 First operand. * @param src2 Second operand. * * @return Less than zero if src1 < src2, greater than zero if src1 > src2 and zero if src1 == src2. */ public final long compare(long[] src1, long[] src2) { long result = src1[0] - src2[0]; if (result != 0) { return result; } result = src1[1] - src2[1]; if (result != 0) { return result; } return src1[2] - src2[2]; } /** * Adds three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. * * @return Overflow carry bit. */ public final long add(long[] src, long[] srcDst) { long result = srcDst[2] + src[2], carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[2] = result; result = srcDst[1] + src[1] + carry; carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[1] = result; result = srcDst[0] + src[0] + carry; carry = (result >= MAX_POWER_OF_TWO_BASE ? 1 : 0); result = (result >= MAX_POWER_OF_TWO_BASE ? result - MAX_POWER_OF_TWO_BASE : result); srcDst[0] = result; return carry; } /** * Subtracts three words. Most significant word is stored first. * * @param src First operand. * @param srcDst Second operand, and destination of the operation. */ public final void subtract(long[] src, long[] srcDst) { long result = srcDst[2] - src[2], carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[2] = result; result = srcDst[1] - src[1] - carry; carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[1] = result; result = srcDst[0] - src[0] - carry; // carry = (result < 0 ? 1 : 0); result = (result < 0 ? result + MAX_POWER_OF_TWO_BASE : result); srcDst[0] = result; } /** * Divides three words by the base to produce two words. Most significant word is stored first. * * @param srcDst Source and destination of the operation. * * @return Remainder of the division. */ public final long divide(long[] srcDst) { long tmp = srcDst[0] << 64 - MAX_POWER_OF_TWO_BITS | srcDst[1] >> MAX_POWER_OF_TWO_BITS, result = Math.multiplyHigh(tmp, this.inverseBaseLong), carry = (srcDst[0] << MAX_POWER_OF_TWO_BITS | srcDst[1]) - result * this.base; // = tmp % this.base tmp = Math.multiplyHigh(carry, this.inverseBaseLong) >> 64 - 2* (64 - MAX_POWER_OF_TWO_BITS); result += tmp; carry -= tmp * this.base; result += (carry >= this.base ? 1 : 0); carry -= (carry >= this.base ? this.base : 0); srcDst[0] = 0; srcDst[1] = result; tmp = carry << 64 - MAX_POWER_OF_TWO_BITS | srcDst[2] >> MAX_POWER_OF_TWO_BITS; result = Math.multiplyHigh(tmp, this.inverseBaseLong) + (tmp < 0 ? this.inverseBaseLong : 0); // Signed multiplication to unsigned carry = (carry << MAX_POWER_OF_TWO_BITS | srcDst[2]) - result * this.base; // = tmp % this.base tmp = Math.multiplyHigh(carry, this.inverseBaseLong) >> 64 - 2* (64 - MAX_POWER_OF_TWO_BITS); result += tmp; carry -= tmp * this.base; result += (carry >= this.base ? 1 : 0); carry -= (carry >= this.base ? this.base : 0); srcDst[2] = result; return carry; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.inverseBaseLong = INVERSE_BASE[radix()]; } private static final long serialVersionUID = 7400961005627736773L; private static final long BASE_MASK = (1L << MAX_POWER_OF_TWO_BITS) - 1; private static final long[] INVERSE_BASE; static { INVERSE_BASE = new long[Character.MAX_RADIX + 1]; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { INVERSE_BASE[radix] = BigInteger.ONE.shiftLeft(2 * MAX_POWER_OF_TWO_BITS).divide(BigInteger.valueOf(BASE[radix])).longValueExact(); } } private long base; @SuppressWarnings("unused") // Kept only for serialization compatibility private double inverseBase; private transient long inverseBaseLong; } apfloat-1.14.0/apfloat/src/main/java9/org/apfloat/internal/LongElementaryModMath.java000066400000000000000000000144031461767713300305120ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import static org.apfloat.internal.LongModConstants.*; import java.math.BigInteger; /** * Elementary modulo arithmetic functions for long data.

* * Modular addition and subtraction are trivial, when the modulus is less * than 263 and overflow can be detected easily.

* * Modular multiplication is more complicated, and since it is usually * the single most time consuming operation in the whole program execution, * the very core of the Number Theoretic Transform (NTT), it should be * carefully optimized.

* * The algorithm for multiplying two longs and taking the * remainder is not entirely obvious. The basic problem is to get the * full 128-bit result of multiplying two 64-bit integers. Before the * introduction of {@link Math#multiplyHigh(long, long)} it was impractically * slow. The legacy of this code is that the older algorithm used an * approach where the top 52 bits of the multiplication would be retrieved * by converting the operands to double and longs * would only be used to get the lowest 64 bits of the result. With round-off * errors this allows using only 57 bits in the multiplication operands. For * serialization compatibility, this algorithm still has the same limitation. *

* * The first observation is that since the modulus is practically * constant, it should be more efficient to calculate (once) the inverse * of the modulus, and then subsequently multiply by the inverse modulus * instead of dividing by the modulus.

* * The second observation is that to get the remainder of the division, * we don't necessarily need the actual result of the division (we just * want the remainder). So, we should discard the top half bits of the * full 128-bit result whenever possible, to save a few operations.

* * The basic approach is to get an approximation of a * b / modulus. * To calculate the approximate division, we multiply by the inverse modulus * using fixed-point multiplication (where the inverse modulus is calculated to * 63 bits of precision) and {@link Math#multiplyHigh(long, long)}. With 57-bit * multiplicands and 63 bits of the inverse modulus, and a prime modulus, the * approximation should be within 1 of the correct result. Thus we simply calculate * a * b - approximateDivision * modulus to get the initial remainder. * It is then easy to detect the case when the approximate division was off by one * as the final step of the algorithm. * * @version 1.9.0 * @author Mikko Tommila */ public class LongElementaryModMath { /** * Default constructor. */ public LongElementaryModMath() { } /** * Modular multiplication. * * @param a First operand. * @param b Second operand. * * @return a * b % modulus */ public final long modMultiply(long a, long b) { long tl = a * b, th = Math.multiplyHigh(a, b) << 9 | tl >>> 55; long r1 = tl - Math.multiplyHigh(th, this.inverseModulus) * this.modulus, r2 = r1 - this.modulus; return (r2 < 0 ? r1 : r2); } /** * Modular addition. * * @param a First operand. * @param b Second operand. * * @return (a + b) % modulus */ public final long modAdd(long a, long b) { long r = a + b; return (r >= this.modulus ? r - this.modulus : r); } /** * Modular subtraction. The result is always >= 0. * * @param a First operand. * @param b Second operand. * * @return (a - b + modulus) % modulus */ public final long modSubtract(long a, long b) { long r = a - b; return (r < 0 ? r + this.modulus : r); } /** * Get the modulus. * * @return The modulus. */ public final long getModulus() { return this.modulus; } /** * Set the modulus. * * @param modulus The modulus. */ public final void setModulus(long modulus) { if (modulus == MODULUS[0]) { this.inverseModulus = INVERSE_MODULUS[0]; } else if (modulus == MODULUS[1]) { this.inverseModulus = INVERSE_MODULUS[1]; } else if (modulus == MODULUS[2]) { this.inverseModulus = INVERSE_MODULUS[2]; } else { assert (false); } this.modulus = modulus; } private static final long[] INVERSE_MODULUS = { BigInteger.ONE.shiftLeft(119).divide(BigInteger.valueOf(MODULUS[0])).longValueExact(), BigInteger.ONE.shiftLeft(119).divide(BigInteger.valueOf(MODULUS[1])).longValueExact(), BigInteger.ONE.shiftLeft(119).divide(BigInteger.valueOf(MODULUS[2])).longValueExact() }; private long modulus; private long inverseModulus; } apfloat-1.14.0/apfloat/src/main/resources/000077500000000000000000000000001461767713300204155ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/resources/META-INF/000077500000000000000000000000001461767713300215555ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/resources/META-INF/services/000077500000000000000000000000001461767713300234005ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/resources/META-INF/services/org.apfloat.spi.BuilderFactory000066400000000000000000000002461461767713300312500ustar00rootroot00000000000000org.apfloat.internal.IntBuilderFactory org.apfloat.internal.LongBuilderFactory org.apfloat.internal.FloatBuilderFactory org.apfloat.internal.DoubleBuilderFactory apfloat-1.14.0/apfloat/src/main/resources/apfloat.properties000066400000000000000000000040411461767713300241600ustar00rootroot00000000000000# The apfloat service provider class. # Out-of-the-box options are: # - org.apfloat.internal.IntBuilderFactory # - org.apfloat.internal.LongBuilderFactory # - org.apfloat.internal.FloatBuilderFactory # - org.apfloat.internal.DoubleBuilderFactory builderFactory=org.apfloat.internal.LongBuilderFactory # The default radix, used for newly created numbers unless otherwise specified. defaultRadix=10 # Maximum memory block size (in bytes) that apfloat will try to allocate. # This should be somewhat less than what is available for the JVM # (the maximum heap size). maxMemoryBlockSize=50331648 # Processor level 1 cache size in bytes. # Don't change it unless you know what you are doing. cacheL1Size=8192 # Processor level 2 cache size in bytes. # Don't change it unless you know what you are doing. cacheL2Size=262144 # Processor level 1 cache line size in bytes. # Don't change it unless you know what you are doing. cacheBurst=32 # Threshold for storing numbers on disk. If the storage for the number # takes more than memoryThreshold bytes, it will by default be stored on # disk, otherwise in memory. memoryThreshold=65536 # Threshold for using the shared memory. If the storage for the number # takes more than sharedMemoryTreshold bytes, the memory block usage # will be synchronized against the shared memory lock. sharedMemoryTreshold=1048576 # Efficient disk I/O block size, in bytes. blockSize=65536 # Number of physical processor cores in the computer. numberOfProcessors=1 # Path for storing temporary files for disk-based numbers. filePath= # Initial value of the filenames for storing temporary files for disk-based # numbers. The filenames are generated as sequential numbers: 0, 1, 2, ... fileInitialValue=0 # Filename suffix of the filenames for storing temporary files for disk-based # numbers. fileSuffix=.ap # Determines if clean-up of any remaining temporary files should be run # at program exit. This can't be enabled for unsigned applets. cleanupAtExit=true apfloat-1.14.0/apfloat/src/main/template/000077500000000000000000000000001461767713300202165ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/template/org/000077500000000000000000000000001461767713300210055ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/template/org/apfloat/000077500000000000000000000000001461767713300224335ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/000077500000000000000000000000001461767713300242475ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeAdditionBuilder.java000066400000000000000000000034771461767713300315430ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.AdditionBuilder; import org.apfloat.spi.AdditionStrategy; /** * Creates additions for the specified radix and the rawtype element type.

* * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeAdditionBuilder implements AdditionBuilder { /** * Default constructor. */ public RawtypeAdditionBuilder() { } @Override public AdditionStrategy createAddition(int radix) { AdditionStrategy additionStrategy = new RawtypeAdditionStrategy(radix); return additionStrategy; } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeAdditionStrategy.java000066400000000000000000000056141461767713300317520ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.AdditionStrategy; import org.apfloat.spi.DataStorage.Iterator; /** * Basic addition strategy for the rawtype element type. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeAdditionStrategy extends RawtypeBaseMath implements AdditionStrategy { /** * Creates an addition strategy using the specified radix. * * @param radix The radix that will be used. */ public RawtypeAdditionStrategy(int radix) { super(radix); } @Override public RawType add(Iterator src1, Iterator src2, RawType carry, Iterator dst, long size) throws ApfloatRuntimeException { return baseAdd(src1, src2, carry, dst, size); } @Override public RawType subtract(Iterator src1, Iterator src2, RawType carry, Iterator dst, long size) throws ApfloatRuntimeException { return baseSubtract(src1, src2, carry, dst, size); } @Override public RawType multiplyAdd(Iterator src1, Iterator src2, RawType src3, RawType carry, Iterator dst, long size) throws ApfloatRuntimeException { return baseMultiplyAdd(src1, src2, src3, carry, dst, size); } @Override public RawType divide(Iterator src1, RawType src2, RawType carry, Iterator dst, long size) throws ApfloatRuntimeException { return baseDivide(src1, src2, carry, dst, size); } @Override public RawType zero() { return (rawtype) 0; } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeAdditionStrategy.serialVersionUID}; } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeApfloatBuilder.java000066400000000000000000000053101461767713300313620ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.PushbackReader; import java.io.IOException; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ApfloatBuilder; import org.apfloat.spi.ApfloatImpl; /** * Builder class for building {@link ApfloatImpl} implementations with the * rawtype data element type. * * @version 1.0 * @author Mikko Tommila */ public class RawtypeApfloatBuilder implements ApfloatBuilder { /** * Default constructor. */ public RawtypeApfloatBuilder() { } @Override public ApfloatImpl createApfloat(String value, long precision, int radix, boolean isInteger) throws NumberFormatException, ApfloatRuntimeException { return new RawtypeApfloatImpl(value, precision, radix, isInteger); } @Override public ApfloatImpl createApfloat(long value, long precision, int radix) throws NumberFormatException, ApfloatRuntimeException { return new RawtypeApfloatImpl(value, precision, radix); } @Override public ApfloatImpl createApfloat(double value, long precision, int radix) throws NumberFormatException, ApfloatRuntimeException { return new RawtypeApfloatImpl(value, precision, radix); } @Override public ApfloatImpl createApfloat(PushbackReader in, long precision, int radix, boolean isInteger) throws IOException, NumberFormatException, ApfloatRuntimeException { return new RawtypeApfloatImpl(in, precision, radix, isInteger); } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeApfloatImpl.java000066400000000000000000002473211461767713300307070ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.ObjectInputStream; import java.io.PushbackReader; import java.io.Writer; import java.io.StringWriter; import java.io.IOException; import org.apfloat.Apfloat; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.InfiniteExpansionException; import org.apfloat.OverflowException; import org.apfloat.spi.ApfloatImpl; import org.apfloat.spi.DataStorageBuilder; import org.apfloat.spi.DataStorage; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.AdditionBuilder; import org.apfloat.spi.AdditionStrategy; import org.apfloat.spi.ConvolutionBuilder; import org.apfloat.spi.ConvolutionStrategy; import org.apfloat.spi.Util; import static org.apfloat.spi.RadixConstants.*; import static org.apfloat.internal.RawtypeRadixConstants.*; /** * Immutable apfloat implementation class for the * rawtype data element type.

* * The associated {@link DataStorage} is assumed to be immutable also. * This way performance can be improved by sharing the data storage between * different ApfloatImpl's and by only varying the * ApfloatImpl specific fields, like sign, precision and exponent.

* * This implementation doesn't necessarily store any extra digits for added * precision, so the last digit of any operation may be inaccurate. * * @version 1.11.0 * @author Mikko Tommila */ public class RawtypeApfloatImpl extends RawtypeBaseMath implements ApfloatImpl { // Implementation notes: // - The dataStorage must never contain leading zeros or trailing zeros // - If precision is reduced then the dataStorage can contain trailing zeros (physically in the middle) // - The dataStorage should not be unnecessarily subsequenced if precision is reduced e.g. to allow autoconvolution // - Precision is in digits but exponent is in base units private RawtypeApfloatImpl(int sign, long precision, long exponent, DataStorage dataStorage, int radix) { super(radix); assert (sign == 0 || sign == -1 || sign == 1); assert (precision > 0); assert (sign != 0 || precision == Apfloat.INFINITE); assert (sign != 0 || exponent == 0); assert (sign != 0 || dataStorage == null); assert (sign == 0 || dataStorage != null); assert (exponent <= MAX_EXPONENT[radix] && exponent >= -MAX_EXPONENT[radix]); assert (dataStorage == null || dataStorage.isReadOnly()); this.sign = sign; this.precision = precision; this.exponent = exponent; this.dataStorage = dataStorage; this.radix = radix; } /** * Create a new RawtypeApfloatImpl instance from a String. * * @param value The string to be parsed to a number. * @param precision The precision of the number (in digits of the radix). * @param radix The radix in which the number is created. * @param isInteger Specifies if the number to be parsed from the string is to be treated as an integer or not. * * @exception NumberFormatException If the number is not valid. */ public RawtypeApfloatImpl(String value, long precision, int radix, boolean isInteger) throws NumberFormatException, ApfloatRuntimeException { super(checkRadix(radix)); assert (precision == Apfloat.DEFAULT || precision > 0); this.radix = radix; // Default sign if not specified this.sign = 1; int startIndex = -1, pointIndex = -1, expIndex = -1, leadingZeros = 0, trailingZeros = 0, digitSize = 0; // Scan through the string looking for various things for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); int digit = Character.digit(c, radix); // Note that checking for a valid digit takes place before checking for e or E in the string if (digit == -1) { if (i == 0 && (c == '-' || c == '+')) { // Get sign this.sign = (c == '-' ? -1 : 1); } else if (!isInteger && c == '.' && pointIndex == -1) { // Mark decimal point location pointIndex = digitSize; } else if (!isInteger && (c == 'e' || c == 'E') && expIndex == -1) { // Mark index after which the exponent is specified expIndex = i; break; } else { throw new NumberFormatException("Invalid character: " + c + " at position " + i); } } else { if (leadingZeros == digitSize && digit == 0) { // Increase number of leading zeros leadingZeros++; } else if (startIndex == -1) { // Mark index where the significant digits start startIndex = i; } // Increase number of digits digitSize++; if (digit == 0) { // Increase number of trailing zeros trailingZeros++; } else { // Reset number of trailing zeros trailingZeros = 0; } } } // Check if no digits were specified if (digitSize == 0) { throw new NumberFormatException("No digits"); } // Check if this number is zero if (startIndex == -1) { this.sign = 0; this.precision = Apfloat.INFINITE; this.exponent = 0; this.dataStorage = null; return; } // Default precision is number of significant digits, if not specified if (precision == Apfloat.DEFAULT) { assert (!isInteger); precision = digitSize - leadingZeros; } this.precision = precision; // Size of integer part int integerSize = (pointIndex >= 0 ? pointIndex : digitSize) - leadingZeros; // Read exponent as specified in string if (expIndex >= 0) { // Thanks to Charles Oliver Nutter for finding this bug String expString = value.substring(expIndex + 1); if (expString.startsWith("+")) { expString = expString.substring(1); } try { this.exponent = Long.parseLong(expString); } catch (NumberFormatException nfe) { throw new NumberFormatException("Invalid exponent: " + expString); } } else { this.exponent = 0; } // Do not allow the exponent to be too close to the limits (MIN_VALUE, MAX_VALUE), leave some slack int slack = BASE_DIGITS[radix]; // Check for overflow in exponent, roughly if (integerSize >= -slack && this.exponent >= Long.MAX_VALUE - integerSize - slack) { throw new NumberFormatException("Exponent overflow"); } else if (integerSize <= slack && this.exponent <= Long.MIN_VALUE - integerSize + slack) { // Underflow this.sign = 0; this.precision = Apfloat.INFINITE; this.exponent = 0; this.dataStorage = null; return; } // Adjust exponent by decimal point location this.exponent += integerSize; // Exponent rounded towards positive infinity to base unit long baseExp = (this.exponent + (this.exponent > 0 ? BASE_DIGITS[radix] - 1 : 0)) / BASE_DIGITS[radix]; // Check for overflow in exponent as represented in base units if (baseExp > MAX_EXPONENT[this.radix]) { throw new OverflowException("Overflow"); } else if (baseExp < -MAX_EXPONENT[this.radix]) { // Underflow this.sign = 0; this.precision = Apfloat.INFINITE; this.exponent = 0; this.dataStorage = null; return; } // Leading zeros in first base unit int digitsInBase = (int) (baseExp * BASE_DIGITS[radix] - this.exponent); // The stored exponent is really the one per base unit this.exponent = baseExp; // Remove leading and trailing zeros from size digitSize -= leadingZeros + trailingZeros; // Limit number of significant digits by specified precision digitSize = (int) Math.min(digitSize, precision); // Needed storage size in rawtypes int size = (int) getBasePrecision(digitSize, BASE_DIGITS[radix] - digitsInBase); this.dataStorage = createDataStorage(size); this.dataStorage.setSize(size); // Base unit that is constructed and stored to an element of the data storage rawtype word = 0; DataStorage.Iterator iterator = this.dataStorage.iterator(DataStorage.WRITE, 0, size); // Set the data for (int i = startIndex; digitSize > 0; i++) { char c = value.charAt(i); if (c == '.') { continue; } int digit = Character.digit(c, radix); word *= (rawtype) radix; word += (rawtype) digit; if (digitSize == 1) { // Last digit while (digitsInBase < BASE_DIGITS[radix] - 1) { // Fill last word with trailing zeros word *= (rawtype) radix; digitsInBase++; } } if (++digitsInBase == BASE_DIGITS[radix]) { // Word is full, write word digitsInBase = 0; iterator.setRawtype(word); iterator.next(); word = 0; } digitSize--; } assert (!iterator.hasNext()); this.dataStorage.setReadOnly(); } /** * Create a new RawtypeApfloatImpl instance from a long. * * @param value The value of the number. * @param precision The precision of the number (in digits of the radix). * @param radix The radix in which the number is created. * * @exception NumberFormatException If the number is not valid. */ public RawtypeApfloatImpl(long value, long precision, int radix) throws NumberFormatException, ApfloatRuntimeException { super(checkRadix(radix)); assert (precision > 0); this.radix = radix; // Faster to set now than calculate later this.isOne = (value == 1 ? 1 : 0); if (value > 0) { this.sign = 1; value = -value; // Calculate here as negative to handle 0x8000000000000000 } else if (value < 0) { this.sign = -1; } else { this.sign = 0; this.precision = Apfloat.INFINITE; this.exponent = 0; this.dataStorage = null; return; } this.precision = precision; int size; rawtype[] data = new rawtype[MAX_LONG_SIZE]; long longBase = (long) BASE[radix]; if (-longBase < value) { size = 1; // Nonzero data[MAX_LONG_SIZE - 1] = (rawtype) -value; } else { for (size = 0; value != 0; size++) { long newValue = value / longBase; data[MAX_LONG_SIZE - 1 - size] = (rawtype) (newValue * longBase - value); // Negated here value = newValue; } } this.exponent = size; this.initialDigits = getDigits(data[MAX_LONG_SIZE - size]); // Check if precision in rawtypes is less than size; truncate size if so long basePrecision = getBasePrecision(precision, this.initialDigits); if (basePrecision < size) { size = (int) basePrecision; } // Remove trailing zeros from data while (data[MAX_LONG_SIZE - 1 - (int) this.exponent + size] == 0) { size--; } this.dataStorage = createDataStorage(size); this.dataStorage.setSize(size); try (ArrayAccess arrayAccess = this.dataStorage.getArray(DataStorage.WRITE, 0, size)) { System.arraycopy(data, MAX_LONG_SIZE - (int) this.exponent, arrayAccess.getData(), arrayAccess.getOffset(), size); } this.dataStorage.setReadOnly(); } /** * Create a new RawtypeApfloatImpl instance from a double. * * @param value The value of the number. * @param precision The precision of the number (in digits of the radix). * @param radix The radix in which the number is created. * * @exception NumberFormatException If the number is not valid. */ public RawtypeApfloatImpl(double value, long precision, int radix) throws NumberFormatException, ApfloatRuntimeException { super(checkRadix(radix)); if (Double.isInfinite(value) || Double.isNaN(value)) { throw new NumberFormatException(value + " is not a valid number"); } this.radix = radix; if (value > 0) { this.sign = 1; } else if (value < 0) { this.sign = -1; value = -value; } else { this.sign = 0; this.precision = Apfloat.INFINITE; this.exponent = 0; this.dataStorage = null; return; } this.precision = precision; int size; rawtype[] data = new rawtype[MAX_DOUBLE_SIZE]; double doubleBase = (double) BASE[radix]; this.exponent = (long) Math.floor(Math.log(value) / Math.log(doubleBase)); // Avoid overflow in intermediate value if (this.exponent > 0) { value *= Math.pow(doubleBase, (double) -this.exponent); } else if (this.exponent < 0) { value *= Math.pow(doubleBase, (double) (-this.exponent - MAX_DOUBLE_SIZE)); value *= Math.pow(doubleBase, (double) MAX_DOUBLE_SIZE); } this.exponent++; if (value < 1.0) { // Round-off error in case the input was very close but just under the base, e.g. 9.999999999999996E-10 value = 1.0; } for (size = 0; size < MAX_DOUBLE_SIZE && value > 0.0; size++) { double tmp = Math.floor(value); assert (tmp <= doubleBase); if (tmp == doubleBase) { // Round-off error e.g. in case of the number being exactly 1/radix tmp -= 1.0; } data[size] = (rawtype) tmp; value -= tmp; value *= doubleBase; } this.initialDigits = getDigits(data[0]); // Check if precision in rawtypes is less than size; truncate size if so long basePrecision = getBasePrecision(precision, this.initialDigits); if (basePrecision < size) { size = (int) basePrecision; } // Remove trailing zeros from data while (data[size - 1] == 0) { size--; } this.dataStorage = createDataStorage(size); this.dataStorage.setSize(size); try (ArrayAccess arrayAccess = this.dataStorage.getArray(DataStorage.WRITE, 0, size)) { System.arraycopy(data, 0, arrayAccess.getData(), arrayAccess.getOffset(), size); } this.dataStorage.setReadOnly(); } private static long readExponent(PushbackReader in) throws IOException, NumberFormatException { StringBuilder buffer = new StringBuilder(20); int input; for (long i = 0; (input = in.read()) != -1; i++) { char c = (char) input; int digit = Character.digit(c, 10); // Exponent is always in base 10 if (i == 0 && c == '-' || digit != -1) { buffer.append(c); } else { // Stop at first invalid character and put it back in.unread(input); break; } } return Long.parseLong(buffer.toString()); } /** * Create a new RawtypeApfloatImpl instance reading from a stream.

* * Implementation note: this constructor calls the in stream's * single-character read() method. If the underlying stream doesn't * explicitly implement this method in some efficient way, but simply inherits it * from the Reader base class, performance will suffer as the default * Reader method creates a new char[1] on every call to * read(). * * @param in The stream to read from. * @param precision The precision of the number (in digits of the radix). * @param radix The radix in which the number is created. * @param isInteger Specifies if the number to be parsed from the stream is to be treated as an integer or not. * * @exception IOException If an I/O error occurs accessing the stream. * @exception NumberFormatException If the number is not valid. */ public RawtypeApfloatImpl(PushbackReader in, long precision, int radix, boolean isInteger) throws IOException, NumberFormatException, ApfloatRuntimeException { super(checkRadix(radix)); assert (precision == Apfloat.DEFAULT || precision > 0); this.radix = radix; // Default sign if not specified this.sign = 1; // Allocate a reasonable memory block, since we don't know how much data to expect long initialSize = getBlockSize(), previousAllocatedSize = 0, allocatedSize = initialSize; this.dataStorage = createDataStorage(initialSize); this.dataStorage.setSize(initialSize); // Base unit that is constructed and stored to an element of the data storage rawtype word = 0; // Number of digits stored in word int digitsInBase = 0; DataStorage.Iterator iterator = this.dataStorage.iterator(DataStorage.WRITE, previousAllocatedSize, allocatedSize); int input; long actualSize = 0, startIndex = -1, pointIndex = -1, leadingZeros = 0, trailingZeros = 0, digitSize = 0; // Scan through the string looking for various things for (long i = 0; (input = in.read()) != -1; i++) { char c = (char) input; int digit = Character.digit(c, radix); // Note that checking for a valid digit takes place before checking for e or E in the string if (digit == -1) { if (i == 0 && (c == '-' || c == '+')) { // Get sign this.sign = (c == '-' ? -1 : 1); } else if (!isInteger && c == '.' && pointIndex == -1) { // Mark decimal point location pointIndex = digitSize; } else if (!isInteger && digitSize > 0 && (c == 'e' || c == 'E')) { // Read the exponent and stop this.exponent = readExponent(in); break; } else { // Stop at first invalid character and put it back in.unread(input); break; } } else { if (leadingZeros == digitSize && digit == 0) { // Increase number of leading zeros leadingZeros++; } else { if (startIndex == -1) { // Mark index where the significant digits start startIndex = i; } // Set the data word *= (rawtype) radix; word += (rawtype) digit; // Reallocate storage if needed; done here to prepare storing last (partial) word if (actualSize == allocatedSize) { if (actualSize == initialSize) { // Initial memory block size exceeded; prepare to allocate anything DataStorage dataStorage = createDataStorage(Long.MAX_VALUE / RawType.BYTES); dataStorage.copyFrom(this.dataStorage, actualSize); this.dataStorage = dataStorage; } previousAllocatedSize = allocatedSize; allocatedSize += getBlockSize(); this.dataStorage.setSize(allocatedSize); iterator.close(); iterator = this.dataStorage.iterator(DataStorage.WRITE, previousAllocatedSize, allocatedSize); } if (++digitsInBase == BASE_DIGITS[radix]) { // Word is full, write word digitsInBase = 0; iterator.setRawtype(word); iterator.next(); word = 0; actualSize++; } } // Increase number of digits digitSize++; if (digit == 0) { // Increase number of trailing zeros trailingZeros++; } else { // Reset number of trailing zeros trailingZeros = 0; } } } // Check if no digits were specified if (digitSize == 0) { throw new NumberFormatException("No digits"); } // Check if this number is zero if (startIndex == -1) { this.sign = 0; this.precision = Apfloat.INFINITE; this.exponent = 0; this.dataStorage = null; return; } // Handle last word if (digitsInBase > 0 && word != 0) { // Last digit while (digitsInBase < BASE_DIGITS[radix]) { // Fill last word with trailing zeros word *= (rawtype) radix; digitsInBase++; } // Write word iterator.setRawtype(word); actualSize++; } iterator.close(); // Default precision is number of significant digits, if not specified if (precision == Apfloat.DEFAULT) { assert (!isInteger); precision = digitSize - leadingZeros; } this.precision = precision; // Size of integer part long integerSize = (pointIndex >= 0 ? pointIndex : digitSize) - leadingZeros; // Do not allow the exponent to be too close to the limits (MIN_VALUE, MAX_VALUE), leave some slack int slack = BASE_DIGITS[radix]; // Check for overflow in exponent, roughly if (integerSize >= -slack && this.exponent >= Long.MAX_VALUE - integerSize - slack) { throw new NumberFormatException("Exponent overflow"); } else if (integerSize <= slack && this.exponent <= Long.MIN_VALUE - integerSize + slack) { // Underflow this.sign = 0; this.precision = Apfloat.INFINITE; this.exponent = 0; this.dataStorage = null; return; } // Adjust exponent by decimal point location this.exponent += integerSize; // Exponent rounded towards negative infinity to base unit long baseExp = (this.exponent - (this.exponent < 0 ? BASE_DIGITS[radix] - 1 : 0)) / BASE_DIGITS[radix]; // Check for overflow in exponent as represented in base units if (baseExp > MAX_EXPONENT[this.radix]) { throw new OverflowException("Overflow"); } else if (baseExp < -MAX_EXPONENT[this.radix]) { // Underflow this.sign = 0; this.precision = Apfloat.INFINITE; this.exponent = 0; this.dataStorage = null; return; } // How much the data needs to be shifted int bias = (int) (this.exponent - baseExp * BASE_DIGITS[radix]); // The stored exponent is really the one per base unit this.exponent = baseExp; // Remove leading and trailing zeros from size digitSize -= leadingZeros + trailingZeros; // Limit number of significant digits by specified precision digitSize = Math.min(digitSize, precision); // Needed storage size in rawtypes actualSize = (digitSize + BASE_DIGITS[radix] - 1) / BASE_DIGITS[radix]; // Truncate allocated space to actually used amount this.dataStorage.setSize(actualSize); this.dataStorage.setReadOnly(); if (bias != 0) { // Shift by bias long factor = 1; for (int i = 0; i < bias; i++) { factor *= radix; } RawtypeApfloatImpl tmp = (RawtypeApfloatImpl) multiply(new RawtypeApfloatImpl(factor, Apfloat.INFINITE, radix)); this.exponent = tmp.exponent; this.dataStorage = tmp.dataStorage; this.initialDigits = UNDEFINED; // Needs to be reset } } // Returns number of trailing zeros before specified index private static long getTrailingZeros(DataStorage dataStorage, long index) throws ApfloatRuntimeException { long count = 0; try (DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, index, 0)) { while (iterator.hasNext()) { if (iterator.getRawtype() != 0) { break; } iterator.next(); count++; } } return count; } // Returns number of leading zeros starting from specified index private static long getLeadingZeros(DataStorage dataStorage, long index) throws ApfloatRuntimeException { long count = 0; try (DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, index, dataStorage.getSize())) { while (iterator.hasNext()) { if (iterator.getRawtype() != 0) { break; } iterator.next(); count++; } } return count; } @Override public ApfloatImpl addOrSubtract(ApfloatImpl x, boolean subtract) throws ApfloatRuntimeException { if (!(x instanceof RawtypeApfloatImpl)) { throw new ImplementationMismatchException("Wrong operand type: " + x.getClass().getName()); } RawtypeApfloatImpl that = (RawtypeApfloatImpl) x; if (this.radix != that.radix) { throw new RadixMismatchException("Cannot use numbers with different radixes: " + this.radix + " and " + that.radix); } assert (this.sign != 0); assert (that.sign != 0); int realThatSign = (subtract ? -that.sign : that.sign); boolean reallySubtract = (this.sign != realThatSign); ApfloatContext ctx = ApfloatContext.getContext(); AdditionBuilder additionBuilder = ctx.getBuilderFactory().getAdditionBuilder(RawType.TYPE); AdditionStrategy additionStrategy = additionBuilder.createAddition(this.radix); int sign; long exponent, precision; DataStorage dataStorage; if (this == that) { if (reallySubtract) { // x - x = 0 return zero(); } else { // x + x = 2 * x sign = this.sign; exponent = this.exponent; precision = this.precision; long size = getSize() + 1; dataStorage = createDataStorage(size); dataStorage.setSize(size); rawtype carry; DataStorage.Iterator src1 = this.dataStorage.iterator(DataStorage.READ, size - 1, 0), src2 = this.dataStorage.iterator(DataStorage.READ, size - 1, 0); // Sub-optimal: could be the same try (DataStorage.Iterator dst = dataStorage.iterator(DataStorage.WRITE, size, 0)) { carry = additionStrategy.add(src1, src2, (rawtype) 0, dst, size - 1); dst.setRawtype(carry); } size -= getTrailingZeros(dataStorage, size); // Check if carry occurred int carrySize = (int) carry, leadingZeros = 1 - carrySize; dataStorage = dataStorage.subsequence(leadingZeros, size - leadingZeros); exponent += carrySize; if (this.exponent == MAX_EXPONENT[this.radix] && carrySize > 0) { throw new OverflowException("Overflow"); } if (precision != Apfloat.INFINITE && (carrySize > 0 || getInitialDigits(dataStorage) > getInitialDigits())) { // Carry overflow for most significant digit; number of significant digits increases by one precision++; } } } else { // Now this != that int comparison; if (scale() > that.scale()) { comparison = 1; } else if (scale() < that.scale()) { comparison = -1; } else if (reallySubtract) { comparison = compareMantissaTo(that); // Might be sub-optimal, but a more efficient algorithm would be complicated } else { comparison = 1; // Add equally big numbers; arbitrarily choose one } RawtypeApfloatImpl big, small; if (comparison > 0) { big = this; small = that; sign = this.sign; } else if (comparison < 0) { big = that; small = this; sign = realThatSign; } else { // x - x = 0 return zero(); } long scaleDifference = big.scale() - small.scale(), exponentDifference, size, bigSize, smallSize; if (scaleDifference < 0) { // Small number is completely insignificantly small compared to big precision = big.precision; exponent = big.exponent; bigSize = big.getSize(); smallSize = 0; size = bigSize; exponentDifference = bigSize; } else { precision = Math.min(big.precision, Util.ifFinite(small.precision, scaleDifference + small.precision)); // Detects overflow also long basePrecision = Math.min(MAX_EXPONENT[this.radix], getBasePrecision(precision, big.getInitialDigits())); exponent = big.exponent; exponentDifference = big.exponent - small.exponent; size = Math.min(basePrecision, Math.max(big.getSize(), exponentDifference + small.getSize())); bigSize = Math.min(size, big.getSize()); smallSize = Math.max(0, Math.min(size - exponentDifference, small.getSize())); } long dstSize = size + 1; // One extra word for carry overflow dataStorage = createDataStorage(dstSize); dataStorage.setSize(dstSize); rawtype carry = 0; DataStorage.Iterator src1 = big.dataStorage.iterator(DataStorage.READ, bigSize, 0), src2 = small.dataStorage.iterator(DataStorage.READ, smallSize, 0); try (DataStorage.Iterator dst = dataStorage.iterator(DataStorage.WRITE, dstSize, 0)) { // big: XXXXXXXX XXXX // small: XXXXXXXX or XXXX // This part: XXXX XXXX if (size > bigSize) { long blockSize = Math.min(size - bigSize, smallSize); if (reallySubtract) { carry = additionStrategy.subtract(null, src2, carry, dst, blockSize); } else { carry = additionStrategy.add(null, src2, carry, dst, blockSize); } } // big: XXXXXXXXXXXX // small: XXXX // This part: XXXX else if (size > exponentDifference + smallSize) { long blockSize = size - exponentDifference - smallSize; if (reallySubtract) { carry = additionStrategy.subtract(src1, null, carry, dst, blockSize); } else { carry = additionStrategy.add(src1, null, carry, dst, blockSize); } } // big: XXXX // small: XXXX // This part: XXXX if (exponentDifference > bigSize) { long blockSize = exponentDifference - bigSize; if (reallySubtract) { carry = additionStrategy.subtract(null, null, carry, dst, blockSize); } else { carry = additionStrategy.add(null, null, carry, dst, blockSize); } } // big: XXXXXXXX XXXXXXXXXXXX // small: XXXXXXXX or XXXX // This part: XXXX XXXX else if (bigSize > exponentDifference) { long blockSize = Math.min(bigSize - exponentDifference, smallSize); if (reallySubtract) { carry = additionStrategy.subtract(src1, src2, carry, dst, blockSize); } else { carry = additionStrategy.add(src1, src2, carry, dst, blockSize); } } // big: XXXXXXXX XXXXXXXXXXXX XXXX // small: XXXXXXXX or XXXX or XXXX // This part: XXXX XXXX XXXX if (exponentDifference > 0) { long blockSize = Math.min(bigSize, exponentDifference); if (reallySubtract) { carry = additionStrategy.subtract(src1, null, carry, dst, blockSize); } else { carry = additionStrategy.add(src1, null, carry, dst, blockSize); } } // Set most significant word dst.setRawtype(carry); } long leadingZeros; if (reallySubtract) { // Get denormalization leadingZeros = getLeadingZeros(dataStorage, 0); assert (leadingZeros <= size); } else { // Check if carry occurred up to and including most significant word leadingZeros = (carry == 0 ? 1 : 0); if (this.exponent == MAX_EXPONENT[this.radix] && leadingZeros == 0) { throw new OverflowException("Overflow"); } } dstSize -= getTrailingZeros(dataStorage, dstSize); dataStorage = dataStorage.subsequence(leadingZeros, dstSize - leadingZeros); exponent += 1 - leadingZeros; if (exponent < -MAX_EXPONENT[this.radix]) { // Underflow return zero(); } if (precision != Apfloat.INFINITE) { // If scale of number changes, the number of significant digits changes accordingly long scaleChange = (1 - leadingZeros) * BASE_DIGITS[this.radix] + getInitialDigits(dataStorage) - big.getInitialDigits(); if (-scaleChange >= precision) { // All significant digits were lost anyway, due to trailing garbage digits return zero(); } precision += scaleChange; precision = (precision <= 0 ? Apfloat.INFINITE : precision); // Detect overflow } } dataStorage.setReadOnly(); return new RawtypeApfloatImpl(sign, precision, exponent, dataStorage, this.radix); } @Override public ApfloatImpl multiply(ApfloatImpl x) throws ApfloatRuntimeException { if (!(x instanceof RawtypeApfloatImpl)) { throw new ImplementationMismatchException("Wrong operand type: " + x.getClass().getName()); } RawtypeApfloatImpl that = (RawtypeApfloatImpl) x; if (this.radix != that.radix) { throw new RadixMismatchException("Cannot multiply numbers with different radixes: " + this.radix + " and " + that.radix); } int sign = this.sign * that.sign; if (sign == 0) { return zero(); } long exponent = this.exponent + that.exponent; if (exponent > MAX_EXPONENT[this.radix]) { throw new OverflowException("Overflow"); } else if (exponent < -MAX_EXPONENT[this.radix]) { // Underflow return zero(); } long precision = Math.min(this.precision, that.precision), basePrecision = getBasePrecision(precision, 0), // Round up thisSize = getSize(), thatSize = that.getSize(), size = Math.min(Util.ifFinite(basePrecision, basePrecision + 1), thisSize + thatSize), // Reserve one extra word for carry thisDataSize = Math.min(thisSize, basePrecision), thatDataSize = Math.min(thatSize, basePrecision); DataStorage thisDataStorage = this.dataStorage.subsequence(0, thisDataSize), thatDataStorage = (this.dataStorage == that.dataStorage ? thisDataStorage : // Enable auto-convolution that.dataStorage.subsequence(0, thatDataSize)); ApfloatContext ctx = ApfloatContext.getContext(); ConvolutionBuilder convolutionBuilder = ctx.getBuilderFactory().getConvolutionBuilder(); ConvolutionStrategy convolutionStrategy = convolutionBuilder.createConvolution(this.radix, thisDataSize, thatDataSize, size); // Possibly sub-optimal: could look up trailing zeros of the subsequences DataStorage dataStorage = convolutionStrategy.convolute(thisDataStorage, thatDataStorage, size); // Check if carry occurred up to and including most significant word int leadingZeros = (getMostSignificantWord(dataStorage) == 0 ? 1 : 0); exponent -= leadingZeros; if (exponent < -MAX_EXPONENT[this.radix]) { // Underflow return zero(); } size -= leadingZeros; dataStorage = dataStorage.subsequence(leadingZeros, size); size = Math.min(size, getBasePrecision(precision, getInitialDigits(dataStorage))); size -= getTrailingZeros(dataStorage, size); dataStorage = dataStorage.subsequence(0, size); dataStorage.setReadOnly(); return new RawtypeApfloatImpl(sign, precision, exponent, dataStorage, this.radix); } @Override public boolean isShort() throws ApfloatRuntimeException { return (this.sign == 0 || getSize() == 1); } @Override public ApfloatImpl divideShort(ApfloatImpl x) throws ApfloatRuntimeException { if (!(x instanceof RawtypeApfloatImpl)) { throw new ImplementationMismatchException("Wrong operand type: " + x.getClass().getName()); } RawtypeApfloatImpl that = (RawtypeApfloatImpl) x; if (this.radix != that.radix) { throw new RadixMismatchException("Cannot divide numbers with different radixes: " + this.radix + " and " + that.radix); } assert (this.sign != 0); assert (that.sign != 0); int sign = this.sign * that.sign; long exponent = this.exponent - that.exponent + 1; if (exponent > MAX_EXPONENT[this.radix]) { throw new OverflowException("Overflow"); } else if (exponent < -MAX_EXPONENT[this.radix]) { // Underflow return zero(); } long precision = Math.min(this.precision, that.precision), basePrecision = getBasePrecision(), thisDataSize = Math.min(getSize(), basePrecision); DataStorage dataStorage; rawtype divisor = getMostSignificantWord(that.dataStorage); if (divisor == (rawtype) 1) { long size = thisDataSize - getTrailingZeros(this.dataStorage, thisDataSize); dataStorage = this.dataStorage.subsequence(0, size); } else { ApfloatContext ctx = ApfloatContext.getContext(); AdditionBuilder additionBuilder = ctx.getBuilderFactory().getAdditionBuilder(RawType.TYPE); AdditionStrategy additionStrategy = additionBuilder.createAddition(this.radix); long size; rawtype carry; // Check for finite or infinite result sequence rawtype dividend = divisor; // Check that the factorization of the divisor consists entirely of factors of the base // E.g. if base is 10=2*5 then the divisor should be 2^n*5^m for (int i = 0; i < RADIX_FACTORS[this.radix].length; i++) { rawtype factor = RADIX_FACTORS[this.radix][i], quotient; // Keep dividing by factor as long as dividend % factor == 0 // that is remove factors of the base from the divisor while ((dividend - factor * (quotient = (rawtype) (long) (dividend / factor))) == 0) { dividend = quotient; } } // Check if the divisor was factored all the way to one by just dividing by factors of the base if (dividend != (rawtype) 1) { // Divisor does not contain only factors of the base; infinite nonzero sequence if (basePrecision == Apfloat.INFINITE) { throw new InfiniteExpansionException("Cannot perform inexact division to infinite precision"); } size = basePrecision; } else { // Divisor contains only factors of the base; calculate maximum sequence length carry = (rawtype) 1; DataStorage.Iterator dummy = new DataStorage.Iterator() { @Override public void setRawtype(rawtype value) {} @Override public void next() {} private static final long serialVersionUID = 1L; }; long sequenceSize; for (sequenceSize = 0; carry != 0; sequenceSize++) { carry = additionStrategy.divide(null, divisor, carry, dummy, 1); } size = Math.min(basePrecision, thisDataSize + sequenceSize); } // One extra word for result in case the initial word becomes zero; to avoid loss of precision size++; dataStorage = createDataStorage(size); dataStorage.setSize(size); DataStorage.Iterator src = this.dataStorage.iterator(DataStorage.READ, 0, thisDataSize), dst = dataStorage.iterator(DataStorage.WRITE, 0, size); // Perform actual division carry = additionStrategy.divide(src, divisor, (rawtype) 0, dst, thisDataSize); // Produce the trailing sequence of digits due to inexact division carry = additionStrategy.divide(null, divisor, carry, dst, size - thisDataSize); size -= getTrailingZeros(dataStorage, size); // Check if initial word of result is zero int leadingZeros = (getMostSignificantWord() < divisor ? 1 : 0); dataStorage = dataStorage.subsequence(leadingZeros, size - leadingZeros); exponent -= leadingZeros; if (exponent < -MAX_EXPONENT[this.radix]) { // Underflow return zero(); } dataStorage.setReadOnly(); } return new RawtypeApfloatImpl(sign, precision, exponent, dataStorage, this.radix); } @Override public ApfloatImpl absFloor() throws ApfloatRuntimeException { if (this.sign == 0 || this.exponent >= this.dataStorage.getSize()) // Is integer already, with no extra hidden trailing digits { return precision(Apfloat.INFINITE); } else if (this.exponent <= 0) // Is less than one in absolute value { return zero(); } long size = this.exponent; // Size of integer part, now that this.dataStorage.getSize() > this.exponent size -= getTrailingZeros(this.dataStorage, size); DataStorage dataStorage = this.dataStorage.subsequence(0, size); ApfloatImpl apfloatImpl = new RawtypeApfloatImpl(this.sign, Apfloat.INFINITE, this.exponent, dataStorage, this.radix); return apfloatImpl; } @Override public ApfloatImpl absCeil() throws ApfloatRuntimeException { if (this.sign == 0) { return this; } long exponent; DataStorage dataStorage; if (this.exponent <= 0) { // Number is < 1 but > 0; result is one int size = 1; dataStorage = createDataStorage(size); dataStorage.setSize(size); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, size)) { arrayAccess.getRawtypeData()[arrayAccess.getOffset()] = (rawtype) 1; } exponent = 1; } else if (getSize() <= this.exponent || // Check if the fractional part is nonzero findMismatch(getZeroPaddedIterator(this.exponent, getSize()), ZERO_ITERATOR, getSize() - this.exponent) < 0) { // Fractional part is zero; the result is the number itself (to infinite precision) long size = Math.min(this.dataStorage.getSize(), this.exponent); size -= getTrailingZeros(this.dataStorage, size); dataStorage = this.dataStorage.subsequence(0, size); // Ensure truncation exponent = this.exponent; } else { // Fractional part is nonzero; round up ApfloatContext ctx = ApfloatContext.getContext(); AdditionBuilder additionBuilder = ctx.getBuilderFactory().getAdditionBuilder(RawType.TYPE); AdditionStrategy additionStrategy = additionBuilder.createAddition(this.radix); long size = this.exponent; // Size of integer part dataStorage = createDataStorage(size + 1); // Reserve room for carry overflow dataStorage.setSize(size + 1); rawtype carry; try (DataStorage.Iterator src = this.dataStorage.iterator(DataStorage.READ, size, 0); DataStorage.Iterator dst = dataStorage.iterator(DataStorage.WRITE, size + 1, 0)) { carry = additionStrategy.add(src, null, (rawtype) 1, dst, size); // Add carry dst.setRawtype(carry); // Set leading rawtype as overflow carry } int carrySize = (int) carry; // For adjusting size, if carry did overflow or not size -= getTrailingZeros(dataStorage, size + 1); dataStorage = dataStorage.subsequence(1 - carrySize, size + carrySize); exponent = this.exponent + carrySize; } dataStorage.setReadOnly(); ApfloatImpl apfloatImpl = new RawtypeApfloatImpl(this.sign, Apfloat.INFINITE, exponent, dataStorage, this.radix); return apfloatImpl; } @Override public ApfloatImpl frac() throws ApfloatRuntimeException { if (this.sign == 0 || this.exponent <= 0) // Is less than one in absolute value already { return this; } if (this.exponent >= getSize()) // Is an integer, fractional part is zero { return zero(); } long size = this.dataStorage.getSize() - this.exponent; // Size of fractional part, now that getSize() > this.exponent long leadingZeros = getLeadingZeros(this.dataStorage, this.exponent); if (this.exponent + leadingZeros >= getSize()) { // All significant digits were lost, only trailing garbage digits return zero(); } DataStorage dataStorage = this.dataStorage.subsequence(this.exponent + leadingZeros, size - leadingZeros); long precision; if (this.precision != Apfloat.INFINITE) { // Precision is reduced as the integer part is omitted, plus any leading zeros precision = this.precision - getInitialDigits() - (this.exponent + leadingZeros) * BASE_DIGITS[this.radix] + getInitialDigits(dataStorage); if (precision <= 0) { // All significant digits were lost anyway, only trailing garbage digits return zero(); } } else { precision = Apfloat.INFINITE; } long exponent = -leadingZeros; ApfloatImpl apfloatImpl = new RawtypeApfloatImpl(this.sign, precision, exponent, dataStorage, this.radix); return apfloatImpl; } private ApfloatImpl zero() { return new RawtypeApfloatImpl(0, Apfloat.INFINITE, 0, null, this.radix); } @Override public int radix() { return this.radix; } @Override public long precision() { return this.precision; } @Override public long size() throws ApfloatRuntimeException { assert (this.dataStorage != null); if (this.size == 0) { // Writes and reads of volatile long values are always atomic so multiple threads can read and write this at the same time this.size = getInitialDigits() + (getSize() - 1) * BASE_DIGITS[this.radix] - getLeastZeros(); } return this.size; } // Get number of trailing zeros private long getLeastZeros() throws ApfloatRuntimeException { if (this.leastZeros == UNDEFINED) { // Cache the value // NOTE: This is not synchronized; it's OK if multiple threads set this at the same time // Writes and reads of volatile long values are always atomic so multiple threads can read and write this at the same time long index = getSize() - 1; rawtype word = getWord(index); word = getLeastSignificantWord(index, word); long leastZeros = 0; if (word == 0) { // Usually the last word is nonzero but in case precision was later changed, it might be zero long trailingZeros = getTrailingZeros(this.dataStorage, index) + 1; index -= trailingZeros; word = getWord(index); word = getLeastSignificantWord(index, word); leastZeros += trailingZeros * BASE_DIGITS[this.radix]; } assert (word != 0); while (word % this.radix == 0) { leastZeros++; word /= this.radix; } this.leastZeros = leastZeros; } return this.leastZeros; } @Override public ApfloatImpl precision(long precision) { if (this.sign == 0 || precision == this.precision) { return this; } else { return new RawtypeApfloatImpl(this.sign, precision, this.exponent, this.dataStorage, this.radix); } } @Override public long scale() throws ApfloatRuntimeException { assert (this.dataStorage != null); return (this.exponent - 1) * BASE_DIGITS[this.radix] + getInitialDigits(); } @Override public int signum() { return this.sign; } @Override public ApfloatImpl negate() throws ApfloatRuntimeException { return new RawtypeApfloatImpl(-this.sign, this.precision, this.exponent, this.dataStorage, this.radix); } @Override public double doubleValue() { if (this.sign == 0) { return 0.0; } double value = 0.0, doubleBase = (double) BASE[this.radix]; int size = (int) Math.min(MAX_DOUBLE_SIZE, getSize()); DataStorage.Iterator iterator = this.dataStorage.iterator(DataStorage.READ, size, 0); while (iterator.hasNext()) { value += (double) iterator.getRawtype(); value /= doubleBase; iterator.next(); } // If the end result fits in a double, any intermediate calculation must not overflow // Note that 1/BASE <= value < 1 if (this.exponent > 0) { return this.sign * value * Math.pow((double) BASE[this.radix], (double) (this.exponent - 1)) * BASE[this.radix]; } else { return this.sign * value * Math.pow((double) BASE[this.radix], (double) this.exponent); } } @Override public long longValue() { if (this.sign == 0 || this.exponent <= 0) { return 0; } else if (this.exponent > MAX_LONG_SIZE) { // Overflow for sure return (this.sign > 0 ? Long.MAX_VALUE : Long.MIN_VALUE); } long value = 0, longBase = (long) BASE[this.radix], maxPrevious = Long.MIN_VALUE / longBase; // Number of words in integer part of the number int size = (int) Math.min(this.exponent, getSize()); try (DataStorage.Iterator iterator = this.dataStorage.iterator(DataStorage.READ, 0, size)) { for (int i = 0; i < (int) this.exponent; i++) { if (value < maxPrevious) { // Overflow value = 0; break; } value *= longBase; if (i < size) { value -= (long) iterator.getRawtype(); // Calculate value negated to handle 0x8000000000000000 iterator.next(); } } } if (value == Long.MIN_VALUE || value >= 0) { // Overflow return (this.sign > 0 ? Long.MAX_VALUE : Long.MIN_VALUE); } else { return -this.sign * value; } } @Override public boolean isOne() throws ApfloatRuntimeException { if (this.isOne == UNDEFINED) { // Cache the value // NOTE: This is not synchronized; it's OK if multiple threads set this at the same time this.isOne = (this.sign == 1 && this.exponent == 1 && getSize() == 1 && getMostSignificantWord() == (rawtype) 1 ? 1 : 0); } return (this.isOne == 1); } @Override public long equalDigits(ApfloatImpl x) throws ApfloatRuntimeException { if (!(x instanceof RawtypeApfloatImpl)) { throw new ImplementationMismatchException("Wrong operand type: " + x.getClass().getName()); } RawtypeApfloatImpl that = (RawtypeApfloatImpl) x; if (this.sign == 0 && that.sign == 0) // Both are zero { return Apfloat.INFINITE; } else if (this.sign != that.sign) // No match { return 0; } else if (this.radix != that.radix) { throw new RadixMismatchException("Cannot compare values with different radixes: " + this.radix + " and " + that.radix); } long thisScale = scale(), thatScale = that.scale(), minScale = Math.min(thisScale, thatScale), maxScale = Math.max(thisScale, thatScale); if (maxScale - 1 > minScale) // No match { return 0; } // Need to compare mantissas long thisSize = getSize(), thatSize = that.getSize(), size = Math.max(thisSize, thatSize), result = Math.min(this.precision, that.precision); // If mantissas are identical try (DataStorage.Iterator thisIterator = getZeroPaddedIterator(0, thisSize); DataStorage.Iterator thatIterator = that.getZeroPaddedIterator(0, thatSize)) { long index; int lastMatchingDigits = -1; // Will be used for deferred comparison hanging in last word, e.g. this = 1.000000000, that = 0.999999999 rawtype carry, base = BASE[this.radix]; if (this.exponent > that.exponent) { // Possible case this = 1.0000000, that = 0.9999999 rawtype value = thisIterator.getRawtype(); // Check first word if (value != (rawtype) 1) { // No match return 0; } carry = base; thisIterator.next(); } else if (this.exponent < that.exponent) { // Possible case this = 0.9999999, that = 1.0000000 rawtype value = thatIterator.getRawtype(); // Check first word if (value != (rawtype) 1) { // No match return 0; } carry = -base; thatIterator.next(); } else { // Trivial case, e.g. this = 111234, that = 111567 carry = 0; } // Calculate this - that, stopping at first difference for (index = 0; index < size; index++) { rawtype value = thisIterator.getRawtype() - thatIterator.getRawtype() + carry; if (value == 0) { // Trivial case; words are equal carry = 0; } else if (Math.abs(value) > (rawtype) 1) { // Mismatch found if (Math.abs(value) >= base) { // Deferred comparison, e.g. this = 1.0000000002, that = 0.9999999991 lastMatchingDigits = -1; } else { // Any trivial cases and e.g. this = 1.0000000001, that = 0.9999999992 lastMatchingDigits = BASE_DIGITS[this.radix] - getDigits(Math.abs(value)); } break; } else if (value == (rawtype) 1) { // Case this = 1.0000000..., that = 0.9999999... carry = base; } else if (value == (rawtype) -1) { // Case this = 0.9999999..., that = 1.0000000... carry = -base; } thisIterator.next(); thatIterator.next(); } if (index < size || carry != 0) // Mismatch found { long initialMatchingDigits = (this.exponent == that.exponent ? Math.min(getInitialDigits(), that.getInitialDigits()) : // Normal case, e.g. this = 10, that = 5 BASE_DIGITS[this.radix]); // Special case, e.g. this = 1.0, that = 0.9 // Note that this works even if index == 0 long middleMatchingDigits = (index - 1) * BASE_DIGITS[this.radix]; // This is correct even if exponents are different // Limit by available precision result = Math.min(result, initialMatchingDigits + middleMatchingDigits + lastMatchingDigits); // Handle some cases e.g. 0.15 vs. 0.04 result = Math.max(result, 0); } } return result; } @Override public int compareTo(ApfloatImpl x) throws ApfloatRuntimeException { if (!(x instanceof RawtypeApfloatImpl)) { throw new ImplementationMismatchException("Wrong operand type: " + x.getClass().getName()); } RawtypeApfloatImpl that = (RawtypeApfloatImpl) x; if (this.sign == 0 && that.sign == 0) { return 0; } else if (this.sign < that.sign) // Now we know that not both are zero { return -1; } else if (this.sign > that.sign) { return 1; } else if (this.radix != that.radix) { throw new RadixMismatchException("Cannot compare values with different radixes: " + this.radix + " and " + that.radix); } else if (scale() < that.scale()) // Now we know that both have same sign (which is not zero) { return -this.sign; } else if (scale() > that.scale()) { return this.sign; } // Need to compare mantissas return this.sign * compareMantissaTo(that); } // Returns an iterator for this number's data storage from start to end, // least significant word is correctly truncated with getLeastSignificantWord(), // after that the iterator returns zeros only private DataStorage.Iterator getZeroPaddedIterator(long start, long end) throws ApfloatRuntimeException { DataStorage.Iterator iterator = this.dataStorage.iterator(DataStorage.READ, start, end); return new DataStorage.Iterator() { @Override public rawtype getRawtype() throws ApfloatRuntimeException { rawtype value; if (this.index < end) { value = iterator.getRawtype(); if (this.index == end - 1) { value = getLeastSignificantWord(this.index, value); } } else { value = 0; } return value; } @Override public void next() throws ApfloatRuntimeException { if (this.index < end) { iterator.next(); this.index++; } } @Override public void close() throws ApfloatRuntimeException { iterator.close(); } private static final long serialVersionUID = 1L; private long index = start; }; } // Compare absolute values of mantissas private int compareMantissaTo(RawtypeApfloatImpl that) throws ApfloatRuntimeException { int result = 0; long thisSize = getSize(), thatSize = that.getSize(), size = Math.max(thisSize, thatSize); try (DataStorage.Iterator thisIterator = getZeroPaddedIterator(0, thisSize); DataStorage.Iterator thatIterator = that.getZeroPaddedIterator(0, thatSize)) { long index = findMismatch(thisIterator, thatIterator, size); if (index >= 0) // Mismatch found { rawtype thisValue = thisIterator.getRawtype(), thatValue = thatIterator.getRawtype(); if (thisValue < thatValue) { result = -1; } else if (thisValue > thatValue) { result = 1; } } } return result; } // Returns index of first mismatching rawtype, or -1 if mantissas are equal // Iterators are left to point to the mismatching words private long findMismatch(DataStorage.Iterator thisIterator, DataStorage.Iterator thatIterator, long size) throws ApfloatRuntimeException { for (long index = 0; index < size; index++) { rawtype thisValue = thisIterator.getRawtype(), thatValue = thatIterator.getRawtype(); if (thisValue != thatValue) { return index; } thisIterator.next(); thatIterator.next(); } // All searched words matched exactly return -1; } // Truncate insignificant digits from the last rawtype of the number private rawtype getLeastSignificantWord(long index, rawtype word) throws ApfloatRuntimeException { if (this.precision == Apfloat.INFINITE) { return word; } // Total digits including the specified index long digits = getInitialDigits() + index * BASE_DIGITS[this.radix]; if (this.precision >= digits) { return word; } // Assert that the second array access will not be out of bounds rawtype divisor = MINIMUM_FOR_DIGITS[this.radix][(int) (digits - this.precision)]; return (rawtype) (long) (word / divisor) * divisor; } /** * Compares this object to the specified object. * * @param obj The object to compare with. * * @return true if the objects are equal; false otherwise. */ @Override public boolean equals(Object obj) { if (!(obj instanceof ApfloatImpl)) { return false; } ApfloatImpl thatImpl = (ApfloatImpl) obj; // Special comparisons against Apfloat.ZERO and Apfloat.ONE work regardless of radix or implementation class if (signum() == 0 && thatImpl.signum() == 0) { return true; } else if (isOne() && thatImpl.isOne()) { return true; } if (!(obj instanceof RawtypeApfloatImpl)) { return false; } RawtypeApfloatImpl that = (RawtypeApfloatImpl) obj; if (this.radix != that.radix) { // Limitation: cannot compare values with different radixes return false; } else if (this.sign != that.sign || this.exponent != that.exponent) { return false; } else { // Need to compare mantissas return compareMantissaTo(that) == 0; } } @Override public int hashCode() { if (this.hashCode == 0) { // Cache the value // NOTE: This is not synchronized; it's OK if multiple threads set this at the same time int hashCode = 1 + this.sign + (int) this.exponent + (int) (this.exponent >>> 32); if (this.dataStorage != null) { long size = getSize(); // Scan through log(size) scattered words in the mantissa for (long i = 0; i < size; i = i + i + 1) { rawtype word = getWord(i); if (i == size - 1) { word = getLeastSignificantWord(i, word); } long element = (long) word; hashCode += (int) element + (int) (element >>> 32); } } this.hashCode = hashCode; } return this.hashCode; } @Override public String toString(boolean pretty) throws ApfloatRuntimeException { if (this.sign == 0) { return "0"; } long size = getSize() * BASE_DIGITS[this.radix], // This is a rounded up value length; if (pretty) { long scale = scale(); if (scale <= 0) { length = 2 - scale + size; // Format is 0.xxxx or 0.0000xxx } else if (size > scale) { length = 1 + size; // Format is x.xxx } else { length = scale; // Format is xxxx or xxxx0000 } length += (this.sign < 0 ? 1 : 0); // Room for minus sign } else { length = size + 24; // Sign, "0.", "e", exponent sign and 19 digits of exponent } if (length > Integer.MAX_VALUE || length < 0) // Detect overflow { throw new ApfloatInternalException("Number is too large to fit in a String"); } StringWriter writer = new StringWriter((int) length); try { writeTo(writer, pretty); } catch (IOException ioe) { throw new ApfloatInternalException("Unexpected I/O error writing to StringWriter", ioe); } String value = writer.toString(); assert (value.length() <= length); // Postcondition to ensure performance return value; } private static void writeZeros(Writer out, long count) throws IOException { for (long i = 0; i < count; i++) { out.write('0'); } } @Override public void writeTo(Writer out, boolean pretty) throws IOException, ApfloatRuntimeException { if (this.sign == 0) { out.write('0'); return; } if (this.sign < 0) { out.write('-'); } long integerDigits, // Number of digits to write before the decimal point exponent; // Exponent to print if (pretty) { if (this.exponent <= 0) { out.write("0."); // Output is 0.xxxx writeZeros(out, -scale()); // Print leading zeros after decimal point before first nonzero digit integerDigits = -1; // Decimal point is already written } else { integerDigits = scale(); // Decimal point location } exponent = 0; // Do not print exponent } else { integerDigits = 1; // Always write as x.xxxey exponent = scale() - 1; // Print exponent } boolean leftPadZeros = false; // If the written base unit should be left-padded with zeros long size = getSize(), digitsToWrite = Math.min(this.precision, getInitialDigits() + (size - 1) * BASE_DIGITS[this.radix]), digitsWritten = 0, trailingZeros = 0; DataStorage.Iterator iterator = this.dataStorage.iterator(DataStorage.READ, 0, size); char[] buffer = new char[BASE_DIGITS[this.radix]]; while (size > 0) { int start = (leftPadZeros ? 0 : BASE_DIGITS[this.radix] - getInitialDigits()), digits = (int) Math.min(digitsToWrite, BASE_DIGITS[this.radix] - start); formatWord(buffer, iterator.getRawtype()); for (int i = 0; i < digits; i++) { int c = buffer[start + i]; if (c == '0') { trailingZeros++; digitsToWrite--; } else { while (trailingZeros > 0) { if (digitsWritten == integerDigits) { out.write('.'); } out.write('0'); digitsWritten++; trailingZeros--; } if (digitsWritten == integerDigits) { out.write('.'); } out.write(c); digitsWritten++; digitsToWrite--; } } leftPadZeros = true; // Always pad with zeros after first word iterator.next(); size--; } if (!pretty && exponent != 0) { out.write("e" + exponent); } writeZeros(out, integerDigits - digitsWritten); // If format is xxxx0000 } private void formatWord(char[] buffer, rawtype word) { int position = BASE_DIGITS[this.radix]; while (position > 0 && word > 0) { rawtype newWord = (rawtype) (long) (word / this.radix); int digit = (int) (word - newWord * this.radix); word = newWord; position--; buffer[position] = Character.forDigit(digit, this.radix); } // Left pad zeros while (position > 0) { position--; buffer[position] = '0'; } } // Effective size, in rawtypes private long getSize() throws ApfloatRuntimeException { assert (this.dataStorage != null); return Math.min(getBasePrecision(), this.dataStorage.getSize()); } private static int checkRadix(int radix) throws NumberFormatException { if (radix < Character.MIN_RADIX || radix > Character.MAX_RADIX) { throw new NumberFormatException("Invalid radix " + radix + "; radix must be between " + Character.MIN_RADIX + " and " + Character.MAX_RADIX); } return radix; } // Get the most significant word of this number private rawtype getMostSignificantWord() throws ApfloatRuntimeException { return getMostSignificantWord(this.dataStorage); } // Get the most significant word of the specified data storage private static rawtype getMostSignificantWord(DataStorage dataStorage) throws ApfloatRuntimeException { rawtype msw; try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ, 0, 1)) { msw = arrayAccess.getRawtypeData()[arrayAccess.getOffset()]; } return msw; } // Get number of digits in the most significant word private int getInitialDigits() throws ApfloatRuntimeException { if (this.initialDigits == UNDEFINED) { // Cache the value // NOTE: This is not synchronized; it's OK if multiple threads set this at the same time this.initialDigits = getDigits(getMostSignificantWord()); } return this.initialDigits; } // Get number of digits in the most significant word of specified data private int getInitialDigits(DataStorage dataStorage) throws ApfloatRuntimeException { return getDigits(getMostSignificantWord(dataStorage)); } // Gets the number of digits in the specified rawtype and this number's radix private int getDigits(rawtype x) { assert (x > 0); rawtype[] minimums = MINIMUM_FOR_DIGITS[this.radix]; int i = minimums.length; while (x < minimums[--i]) { } return i + 1; } // Gets the precision in rawtypes private long getBasePrecision() throws ApfloatRuntimeException { return getBasePrecision(this.precision, getInitialDigits()); } // Gets the precision in rawtypes, based on specified precision (in digits), // number of digits in most significant word and this number's radix private long getBasePrecision(long precision, int mswDigits) { if (precision == Apfloat.INFINITE) { return Apfloat.INFINITE; } else { return Long.divideUnsigned(precision + BASE_DIGITS[this.radix] - mswDigits - 1, BASE_DIGITS[this.radix]) + 1; } } private rawtype getWord(long index) { rawtype word; try (ArrayAccess arrayAccess = this.dataStorage.getArray(DataStorage.READ, index, 1)) { word = arrayAccess.getRawtypeData()[arrayAccess.getOffset()]; } return word; } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { this.leastZeros = UNDEFINED; this.isOne = UNDEFINED; in.defaultReadObject(); } // Gets a new data storage for specified size private static DataStorage createDataStorage(long size) throws ApfloatRuntimeException { ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); return dataStorageBuilder.createDataStorage(size * RawType.BYTES); } // Gets I/O block size in rawtypes private static int getBlockSize() { ApfloatContext ctx = ApfloatContext.getContext(); return ctx.getBlockSize() / RawType.BYTES; } private static final DataStorage.Iterator ZERO_ITERATOR = new DataStorage.Iterator() { @Override public rawtype getRawtype() { return 0; } @Override public void next() { } private static final long serialVersionUID = 1L; }; private static final long serialVersionUID = ${org.apfloat.internal.RawtypeApfloatImpl.serialVersionUID}; private static final int UNDEFINED = 0x80000000; private static final int MAX_LONG_SIZE = 4; private static final int MAX_DOUBLE_SIZE = 4; private int sign; private long precision; private long exponent; private DataStorage dataStorage; private int radix; private int hashCode = 0; private int initialDigits = UNDEFINED; private int isOne = UNDEFINED; private volatile long leastZeros = UNDEFINED; private volatile long size = 0; } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeBuilderFactory.java000066400000000000000000000120421461767713300314030ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.AdditionBuilder; import org.apfloat.spi.BuilderFactory; import org.apfloat.spi.ApfloatBuilder; import org.apfloat.spi.DataStorageBuilder; import org.apfloat.spi.ConvolutionBuilder; import org.apfloat.spi.NTTBuilder; import org.apfloat.spi.MatrixBuilder; import org.apfloat.spi.CarryCRTBuilder; import org.apfloat.spi.ExecutionBuilder; /** * Factory class for getting instances of the various builder classes needed * to build an ApfloatImpl with the rawtype data element type. * * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeBuilderFactory implements BuilderFactory { /** * Default constructor. */ public RawtypeBuilderFactory() { } @Override public ApfloatBuilder getApfloatBuilder() { return RawtypeBuilderFactory.apfloatBuilder; } @Override public DataStorageBuilder getDataStorageBuilder() { return RawtypeBuilderFactory.dataStorageBuilder; } @Override public AdditionBuilder getAdditionBuilder(Class elementType) throws IllegalArgumentException { if (!RawType.TYPE.equals(elementType)) { throw new IllegalArgumentException("Unsupported element type: " + elementType); } @SuppressWarnings("unchecked") AdditionBuilder additionBuilder = (AdditionBuilder) RawtypeBuilderFactory.additionBuilder; return additionBuilder; } @Override public ConvolutionBuilder getConvolutionBuilder() { return RawtypeBuilderFactory.convolutionBuilder; } @Override public NTTBuilder getNTTBuilder() { return RawtypeBuilderFactory.nttBuilder; } @Override public MatrixBuilder getMatrixBuilder() { return RawtypeBuilderFactory.matrixBuilder; } @Override public CarryCRTBuilder getCarryCRTBuilder(Class elementArrayType) throws IllegalArgumentException { if (!rawtype[].class.equals(elementArrayType)) { throw new IllegalArgumentException("Unsupported element array type: " + elementArrayType); } @SuppressWarnings("unchecked") CarryCRTBuilder carryCRTBuilder = (CarryCRTBuilder) RawtypeBuilderFactory.carryCRTBuilder; return carryCRTBuilder; } @Override public ExecutionBuilder getExecutionBuilder() { return RawtypeBuilderFactory.executionBuilder; } @Override public Class getElementType() { return RawType.TYPE; } @Override public Class getElementArrayType() { return rawtype[].class; } @Override public int getElementSize() { return RawType.BYTES; } @Override public void shutdown() throws ApfloatRuntimeException { DiskDataStorage.cleanUp(); } @Override public void gc() throws ApfloatRuntimeException { System.gc(); System.gc(); System.runFinalization(); DiskDataStorage.gc(); } private static ApfloatBuilder apfloatBuilder = new RawtypeApfloatBuilder(); private static DataStorageBuilder dataStorageBuilder = new RawtypeDataStorageBuilder(); private static AdditionBuilder additionBuilder = new RawtypeAdditionBuilder(); private static ConvolutionBuilder convolutionBuilder = new RawtypeConvolutionBuilder(); private static NTTBuilder nttBuilder = new RawtypeNTTBuilder(); private static MatrixBuilder matrixBuilder = new RawtypeMatrixBuilder(); private static CarryCRTBuilder carryCRTBuilder = new RawtypeCarryCRTBuilder(); private static ExecutionBuilder executionBuilder = new ParallelExecutionBuilder(); } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeCarryCRTBuilder.java000066400000000000000000000036571461767713300314410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.CarryCRTBuilder; import org.apfloat.spi.CarryCRTStrategy; import org.apfloat.spi.CarryCRTStepStrategy; /** * Creates carry-CRT related objects, for the * rawtype type. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeCarryCRTBuilder implements CarryCRTBuilder { /** * Default constructor. */ public RawtypeCarryCRTBuilder() { } @Override public CarryCRTStrategy createCarryCRT(int radix) { return new StepCarryCRTStrategy(radix); } @Override public CarryCRTStepStrategy createCarryCRTSteps(int radix) { return new RawtypeCarryCRTStepStrategy(radix); } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeCarryCRTStepStrategy.java000066400000000000000000000276311461767713300325070ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.math.BigInteger; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.CarryCRTStepStrategy; import org.apfloat.spi.DataStorage; import static org.apfloat.internal.RawtypeModConstants.*; /** * Class for performing the final steps of a three-modulus * Number Theoretic Transform based convolution. Works for the * rawtype type.

* * All access to this class must be externally synchronized. * * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeCarryCRTStepStrategy extends RawtypeCRTMath implements CarryCRTStepStrategy { /** * Creates a carry-CRT steps object using the specified radix. * * @param radix The radix that will be used. */ public RawtypeCarryCRTStepStrategy(int radix) { super(radix); } @Override public rawtype[] crt(DataStorage resultMod0, DataStorage resultMod1, DataStorage resultMod2, DataStorage dataStorage, long size, long resultSize, long offset, long length) throws ApfloatRuntimeException { long skipSize = (offset == 0 ? size - resultSize + 1: 0); // For the first block, ignore the first 1-3 elements long lastSize = (offset + length == size ? 1: 0); // For the last block, add 1 element long nonLastSize = 1 - lastSize; // For the other than last blocks, move 1 element long subResultSize = length - skipSize + lastSize; long subStart = size - offset, subEnd = subStart - length, subResultStart = size - offset - length + nonLastSize + subResultSize, subResultEnd = subResultStart - subResultSize; DataStorage.Iterator src0 = resultMod0.iterator(DataStorage.READ, subStart, subEnd), src1 = resultMod1.iterator(DataStorage.READ, subStart, subEnd), src2 = resultMod2.iterator(DataStorage.READ, subStart, subEnd); try (DataStorage.Iterator dst = dataStorage.iterator(DataStorage.WRITE, subResultStart, subResultEnd)) { rawtype[] carryResult = new rawtype[3], sum = new rawtype[3], tmp = new rawtype[3]; // Preliminary carry-CRT calculation (happens in parallel in multiple blocks) for (long i = 0; i < length; i++) { rawtype y0 = MATH_MOD_0.modMultiply(T0, src0.getRawtype()), y1 = MATH_MOD_1.modMultiply(T1, src1.getRawtype()), y2 = MATH_MOD_2.modMultiply(T2, src2.getRawtype()); multiply(M12, y0, sum); multiply(M02, y1, tmp); if (add(tmp, sum) != 0 || compare(sum, M012) >= 0) { subtract(M012, sum); } multiply(M01, y2, tmp); if (add(tmp, sum) != 0 || compare(sum, M012) >= 0) { subtract(M012, sum); } add(sum, carryResult); rawtype result = divide(carryResult); // In the first block, ignore the first element (it's zero in full precision calculations) // and possibly one or two more in limited precision calculations if (i >= skipSize) { dst.setRawtype(result); dst.next(); } src0.next(); src1.next(); src2.next(); } // Calculate the last words (in base math) rawtype result0 = divide(carryResult); rawtype result1 = carryResult[2]; assert (carryResult[0] == 0); assert (carryResult[1] == 0); // Last block has one extra element (corresponding to the one skipped in the first block) if (subResultSize == length - skipSize + 1) { dst.setRawtype(result0); result0 = result1; assert (result1 == 0); } rawtype[] results = { result1, result0 }; return results; } } @Override public rawtype[] carry(DataStorage dataStorage, long size, long resultSize, long offset, long length, rawtype[] results, rawtype[] previousResults) throws ApfloatRuntimeException { long skipSize = (offset == 0 ? size - resultSize + 1: 0); // For the first block, ignore the first 1-3 elements long lastSize = (offset + length == size ? 1: 0); // For the last block, add 1 element long nonLastSize = 1 - lastSize; // For the other than last blocks, move 1 element long subResultSize = length - skipSize + lastSize; long subResultStart = size - offset - length + nonLastSize + subResultSize, subResultEnd = subResultStart - subResultSize; // Get iterators for the previous block carries, and dst, padded with this block's carries // Note that size could be 1 but carries size is 2 DataStorage.Iterator src = arrayIterator(previousResults); try (DataStorage.Iterator dst = compositeIterator(dataStorage.iterator(DataStorage.READ_WRITE, subResultStart, subResultEnd), subResultSize, arrayIterator(results))) { // Propagate base addition through dst, and this block's carries rawtype carry = baseAdd(dst, src, 0, dst, previousResults.length); carry = baseCarry(dst, carry, subResultSize); assert (carry == 0); } // Iterator likely was not iterated to end return results; } private rawtype baseCarry(DataStorage.Iterator srcDst, rawtype carry, long size) throws ApfloatRuntimeException { for (long i = 0; i < size && carry > 0; i++) { carry = baseAdd(srcDst, null, carry, srcDst, 1); } return carry; } // Wrap an array in a simple reverse-order iterator, padded with zeros private static DataStorage.Iterator arrayIterator(rawtype[] data) { return new DataStorage.Iterator() { @Override public boolean hasNext() { return true; } @Override public void next() { this.position--; } @Override public rawtype getRawtype() { assert (this.position >= 0); return data[this.position]; } @Override public void setRawtype(rawtype value) { assert (this.position >= 0); data[this.position] = value; } private static final long serialVersionUID = 1L; private int position = data.length - 1; }; } // Composite iterator, made by concatenating two iterators private static DataStorage.Iterator compositeIterator(DataStorage.Iterator iterator1, long size, DataStorage.Iterator iterator2) { return new DataStorage.Iterator() { @Override public boolean hasNext() { return (this.position < size ? iterator1.hasNext() : iterator2.hasNext()); } @Override public void next() throws ApfloatRuntimeException { (this.position < size ? iterator1 : iterator2).next(); this.position++; } @Override public rawtype getRawtype() throws ApfloatRuntimeException { return (this.position < size ? iterator1 : iterator2).getRawtype(); } @Override public void setRawtype(rawtype value) throws ApfloatRuntimeException { (this.position < size ? iterator1 : iterator2).setRawtype(value); } @Override public void close() throws ApfloatRuntimeException { (this.position < size ? iterator1 : iterator2).close(); } private static final long serialVersionUID = 1L; private long position; }; } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeCarryCRTSteps.serialVersionUID}; private static final RawtypeModMath MATH_MOD_0, MATH_MOD_1, MATH_MOD_2; private static final rawtype T0, T1, T2; private static final rawtype[] M01, M02, M12, M012; static { MATH_MOD_0 = new RawtypeModMath(); MATH_MOD_1 = new RawtypeModMath(); MATH_MOD_2 = new RawtypeModMath(); MATH_MOD_0.setModulus(MODULUS[0]); MATH_MOD_1.setModulus(MODULUS[1]); MATH_MOD_2.setModulus(MODULUS[2]); // Probably sub-optimal, but it's a one-time operation BigInteger base = BigInteger.valueOf(Math.abs((long) MAX_POWER_OF_TWO_BASE)), // In int case the base is 0x80000000 m0 = BigInteger.valueOf((long) MODULUS[0]), m1 = BigInteger.valueOf((long) MODULUS[1]), m2 = BigInteger.valueOf((long) MODULUS[2]), m01 = m0.multiply(m1), m02 = m0.multiply(m2), m12 = m1.multiply(m2); T0 = m12.modInverse(m0).rawtypeValue(); T1 = m02.modInverse(m1).rawtypeValue(); T2 = m01.modInverse(m2).rawtypeValue(); M01 = new rawtype[2]; M02 = new rawtype[2]; M12 = new rawtype[2]; M012 = new rawtype[3]; BigInteger[] qr = m01.divideAndRemainder(base); M01[0] = qr[0].rawtypeValue(); M01[1] = qr[1].rawtypeValue(); qr = m02.divideAndRemainder(base); M02[0] = qr[0].rawtypeValue(); M02[1] = qr[1].rawtypeValue(); qr = m12.divideAndRemainder(base); M12[0] = qr[0].rawtypeValue(); M12[1] = qr[1].rawtypeValue(); qr = m0.multiply(m12).divideAndRemainder(base); M012[2] = qr[1].rawtypeValue(); qr = qr[0].divideAndRemainder(base); M012[0] = qr[0].rawtypeValue(); M012[1] = qr[1].rawtypeValue(); } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeConvolutionBuilder.java000066400000000000000000000055551461767713300323260ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.ConvolutionStrategy; import org.apfloat.spi.NTTStrategy; import static org.apfloat.internal.RawtypeConstants.*; /** * Creates convolutions of suitable type for the rawtype type.

* * @see RawtypeShortConvolutionStrategy * @see RawtypeMediumConvolutionStrategy * @see RawtypeKaratsubaConvolutionStrategy * @see ThreeNTTConvolutionStrategy * * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeConvolutionBuilder extends AbstractConvolutionBuilder { /** * Default constructor. */ public RawtypeConvolutionBuilder() { } @Override protected int getKaratsubaCutoffPoint() { return RawtypeKaratsubaConvolutionStrategy.CUTOFF_POINT; } @Override protected float getKaratsubaCostFactor() { return KARATSUBA_COST_FACTOR; } @Override protected float getNTTCostFactor() { return NTT_COST_FACTOR; } @Override protected ConvolutionStrategy createShortConvolutionStrategy(int radix) { return new RawtypeShortConvolutionStrategy(radix); } @Override protected ConvolutionStrategy createMediumConvolutionStrategy(int radix) { return new RawtypeMediumConvolutionStrategy(radix); } @Override protected ConvolutionStrategy createKaratsubaConvolutionStrategy(int radix) { return new RawtypeKaratsubaConvolutionStrategy(radix); } @Override protected ConvolutionStrategy createThreeNTTConvolutionStrategy(int radix, NTTStrategy nttStrategy) { return new ParallelThreeNTTConvolutionStrategy(radix, nttStrategy); } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeDataStorageBuilder.java000066400000000000000000000044601461767713300321770ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; /** * Default data storage creation strategy for the rawtype data type. * * @see RawtypeMemoryDataStorage * @see RawtypeDiskDataStorage * * @version 1.8.2 * @author Mikko Tommila */ public class RawtypeDataStorageBuilder extends AbstractDataStorageBuilder { /** * Default constructor. */ public RawtypeDataStorageBuilder() { } @Override protected long getMaxCachedSize() { return (long) RawType.BYTES * Integer.MAX_VALUE; } @Override protected DataStorage createCachedDataStorage() throws ApfloatRuntimeException { return new RawtypeMemoryDataStorage(); } @Override protected DataStorage createNonCachedDataStorage() throws ApfloatRuntimeException { return new RawtypeDiskDataStorage(); } @Override protected boolean isCached(DataStorage dataStorage) throws ApfloatRuntimeException { return (dataStorage instanceof RawtypeMemoryDataStorage); } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeDiskDataStorage.java000066400000000000000000000305761461767713300315120ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.nio.ByteBuffer; import java.nio.RawtypeBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import org.apfloat.spi.ArrayAccess; /** * Disk-based data storage for the rawtype element type. * * @version 1.8.0 * @author Mikko Tommila */ public class RawtypeDiskDataStorage extends DiskDataStorage { /** * Default constructor. */ public RawtypeDiskDataStorage() throws ApfloatRuntimeException { } /** * Subsequence constructor. * * @param rawtypeDiskDataStorage The originating data storage. * @param offset The subsequence starting position. * @param length The subsequence length. */ protected RawtypeDiskDataStorage(RawtypeDiskDataStorage rawtypeDiskDataStorage, long offset, long length) { super(rawtypeDiskDataStorage, offset, length); } @Override protected DataStorage implSubsequence(long offset, long length) throws ApfloatRuntimeException { return new RawtypeDiskDataStorage(this, offset + getOffset(), length); } private class RawtypeDiskArrayAccess extends RawtypeMemoryArrayAccess { // fileOffset is absolute position in file public RawtypeDiskArrayAccess(int mode, long fileOffset, int length) throws ApfloatRuntimeException { super(new rawtype[length], 0, length); this.mode = mode; this.fileOffset = fileOffset; if ((mode & READ) != 0) { rawtype[] array = getRawtypeData(); WritableByteChannel out = new WritableByteChannel() { @Override public int write(ByteBuffer buffer) { RawtypeBuffer src = buffer.asRawtypeBuffer(); int readLength = src.remaining(); src.get(array, this.readPosition, readLength); this.readPosition += readLength; buffer.position(buffer.position() + readLength * RawType.BYTES); return readLength * RawType.BYTES; } @Override public void close() {} @Override public boolean isOpen() { return true; } private int readPosition = 0; }; transferTo(out, fileOffset * RawType.BYTES, (long) length * RawType.BYTES); } } @Override public void close() throws ApfloatRuntimeException { if ((this.mode & WRITE) != 0 && getData() != null) { rawtype[] array = getRawtypeData(); ReadableByteChannel in = new ReadableByteChannel() { @Override public int read(ByteBuffer buffer) { RawtypeBuffer dst = buffer.asRawtypeBuffer(); int writeLength = dst.remaining(); dst.put(array, this.writePosition, writeLength); this.writePosition += writeLength; buffer.position(buffer.position() + writeLength * RawType.BYTES); return writeLength * RawType.BYTES; } @Override public void close() {} @Override public boolean isOpen() { return true; } private int writePosition = 0; }; transferFrom(in, this.fileOffset * RawType.BYTES, (long) array.length * RawType.BYTES); } super.close(); } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeDiskDataStorage$RawtypeDiskArrayAccess.serialVersionUID}; private int mode; private long fileOffset; } @Override protected ArrayAccess implGetArray(int mode, long offset, int length) throws ApfloatRuntimeException { return new RawtypeDiskArrayAccess(mode, getOffset() + offset, length); } @Override protected ArrayAccess createArrayAccess(int mode, int startColumn, int columns, int rows) { return new MemoryArrayAccess(mode, new rawtype[columns * rows], startColumn, columns, rows); } @Override protected ArrayAccess createTransposedArrayAccess(int mode, int startColumn, int columns, int rows) { return new TransposedMemoryArrayAccess(mode, new rawtype[columns * rows], startColumn, columns, rows); } private class MemoryArrayAccess extends RawtypeMemoryArrayAccess { public MemoryArrayAccess(int mode, rawtype[] data, int startColumn, int columns, int rows) { super(data, 0, data.length); this.mode = mode; this.startColumn = startColumn; this.columns = columns; this.rows = rows; } @Override public void close() throws ApfloatRuntimeException { if ((this.mode & WRITE) != 0 && getData() != null) { setArray(this, this.startColumn, this.columns, this.rows); } super.close(); } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeDiskDataStorage$MemoryArrayAccess.serialVersionUID}; private int mode, startColumn, columns, rows; } private class TransposedMemoryArrayAccess extends RawtypeMemoryArrayAccess { public TransposedMemoryArrayAccess(int mode, rawtype[] data, int startColumn, int columns, int rows) { super(data, 0, data.length); this.mode = mode; this.startColumn = startColumn; this.columns = columns; this.rows = rows; } @Override public void close() throws ApfloatRuntimeException { if ((this.mode & WRITE) != 0 && getData() != null) { setTransposedArray(this, this.startColumn, this.columns, this.rows); } super.close(); } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeDiskDataStorage$TransposedMemoryArrayAccess.serialVersionUID}; private int mode, startColumn, columns, rows; } private class BlockIterator extends AbstractIterator { public BlockIterator(int mode, long startPosition, long endPosition) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { super(mode, startPosition, endPosition); this.arrayAccess = null; this.remaining = 0; } @Override public void next() throws IllegalStateException, ApfloatRuntimeException { checkLength(); assert (this.remaining > 0); checkAvailable(); this.offset += getIncrement(); this.remaining--; if (this.remaining == 0) { close(); } super.next(); } @Override public rawtype getRawtype() throws IllegalStateException, ApfloatRuntimeException { checkGet(); checkAvailable(); return this.data[this.offset]; } @Override public void setRawtype(rawtype value) throws IllegalStateException, ApfloatRuntimeException { checkSet(); checkAvailable(); this.data[this.offset] = value; } @Override public T get(Class type) throws UnsupportedOperationException, IllegalStateException { if (!(type.equals(RawType.TYPE))) { throw new UnsupportedOperationException("Unsupported data type " + type.getCanonicalName() + ", the only supported type is rawtype"); } @SuppressWarnings("unchecked") T value = (T) (RawType) getRawtype(); return value; } @Override public void set(Class type, T value) throws UnsupportedOperationException, IllegalArgumentException, IllegalStateException { if (!(type.equals(RawType.TYPE))) { throw new UnsupportedOperationException("Unsupported data type " + type.getCanonicalName() + ", the only supported type is rawtype"); } if (!(value instanceof RawType)) { throw new IllegalArgumentException("Unsupported value type " + value.getClass().getCanonicalName() + ", the only supported type is RawType"); } setRawtype((RawType) value); } /** * Closes the iterator. This needs to be called only if the * iterator is not iterated to the end. */ @Override public void close() throws ApfloatRuntimeException { if (this.arrayAccess != null) { this.data = null; this.arrayAccess.close(); this.arrayAccess = null; } } private void checkAvailable() throws ApfloatRuntimeException { if (this.arrayAccess == null) { boolean isForward = (getIncrement() > 0); int length = (int) Math.min(getLength(), getBlockSize() / RawType.BYTES); long offset = (isForward ? getPosition() : getPosition() - length + 1); this.arrayAccess = getArray(getMode(), offset, length); this.data = this.arrayAccess.getRawtypeData(); this.offset = this.arrayAccess.getOffset() + (isForward ? 0 : length - 1); this.remaining = length; } } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeDiskDataStorage$BlockIterator.serialVersionUID}; private ArrayAccess arrayAccess; private rawtype[] data; private int offset, remaining; } @Override public Iterator iterator(int mode, long startPosition, long endPosition) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { if ((mode & READ_WRITE) == 0) { throw new IllegalArgumentException("Illegal mode: " + mode); } return new BlockIterator(mode, startPosition, endPosition); } @Override protected int getUnitSize() { return RawType.BYTES; } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeDiskDataStorage.serialVersionUID}; } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeFactor3NTTStepStrategy.java000066400000000000000000000207601461767713300327410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.Factor3NTTStepStrategy; import org.apfloat.spi.DataStorage; import static org.apfloat.internal.RawtypeModConstants.*; /** * Steps for the factor-3 NTT.

* * The transform is done using a parallel algorithm, if the data fits in memory.

* * All access to this class must be externally synchronized. * * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeFactor3NTTStepStrategy extends RawtypeModMath implements Factor3NTTStepStrategy, Parallelizable { // Runnable for transforming the columns in a factor-3 transform private class ColumnTransformRunnable implements Runnable { public ColumnTransformRunnable(DataStorage dataStorage0, DataStorage dataStorage1, DataStorage dataStorage2, long startColumn, long columns, rawtype w, rawtype ww, rawtype w1, rawtype w2, boolean isInverse) { this.dataStorage0 = dataStorage0; this.dataStorage1 = dataStorage1; this.dataStorage2 = dataStorage2; this.startColumn = startColumn; this.columns = columns; this.w = w; this.ww = ww; this.w1 = w1; this.w2 = w2; this.isInverse = isInverse; } @Override public void run() { rawtype tmp1 = modPow(this.w, (rawtype) this.startColumn), tmp2 = modPow(this.ww, (rawtype) this.startColumn); DataStorage.Iterator iterator0 = this.dataStorage0.iterator(DataStorage.READ_WRITE, this.startColumn, this.startColumn + this.columns), iterator1 = this.dataStorage1.iterator(DataStorage.READ_WRITE, this.startColumn, this.startColumn + this.columns), iterator2 = this.dataStorage2.iterator(DataStorage.READ_WRITE, this.startColumn, this.startColumn + this.columns); for (long i = 0; i < this.columns; i++) { // 3-point WFTA on the corresponding array elements rawtype x0 = iterator0.getRawtype(), x1 = iterator1.getRawtype(), x2 = iterator2.getRawtype(), t; if (this.isInverse) { // Multiply before transform x1 = modMultiply(x1, tmp1); x2 = modMultiply(x2, tmp2); } // Transform columns t = modAdd(x1, x2); x2 = modSubtract(x1, x2); x0 = modAdd(x0, t); t = modMultiply(t, this.w1); x2 = modMultiply(x2, this.w2); t = modAdd(t, x0); x1 = modAdd(t, x2); x2 = modSubtract(t, x2); if (!this.isInverse) { // Multiply after transform x1 = modMultiply(x1, tmp1); x2 = modMultiply(x2, tmp2); } iterator0.setRawtype(x0); iterator1.setRawtype(x1); iterator2.setRawtype(x2); iterator0.next(); iterator1.next(); iterator2.next(); tmp1 = modMultiply(tmp1, this.w); tmp2 = modMultiply(tmp2, this.ww); } } private DataStorage dataStorage0; private DataStorage dataStorage1; private DataStorage dataStorage2; private long startColumn; private long columns; private rawtype w; private rawtype ww; private rawtype w1; private rawtype w2; private boolean isInverse; } /** * Default constructor. */ public RawtypeFactor3NTTStepStrategy() { } @Override public void transformColumns(DataStorage dataStorage0, DataStorage dataStorage1, DataStorage dataStorage2, long startColumn, long columns, long power2length, long length, boolean isInverse, int modulus) throws ApfloatRuntimeException { // Transform length is three times a power of two assert (length == 3 * power2length); ParallelRunnable parallelRunnable = createColumnTransformParallelRunnable(dataStorage0, dataStorage1, dataStorage2, startColumn, columns, power2length, length, isInverse, modulus); if (columns <= Integer.MAX_VALUE && // Only if the size fits in an integer, but with memory arrays it should dataStorage0.isCached() && // Only if the data storage supports efficient parallel random access dataStorage1.isCached() && dataStorage2.isCached()) { ParallelRunner.runParallel(parallelRunnable); } else { parallelRunnable.run(); // Just run in current thread without parallelization } } @Override public long getMaxTransformLength() { return MAX_TRANSFORM_LENGTH; } /** * Create a ParallelRunnable object for transforming the columns of the matrix * using a 3-point NTT transform. * * @param dataStorage0 The data of the first column. * @param dataStorage1 The data of the second column. * @param dataStorage2 The data of the third column. * @param startColumn The starting element index in the data storages to transform. * @param columns How many columns to transform. * @param power2length Length of the column transform. * @param length Length of total transform (three times the length of one column). * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param modulus Index of the modulus. * * @return A suitable object for performing the 3-point transforms in parallel. */ protected ParallelRunnable createColumnTransformParallelRunnable(DataStorage dataStorage0, DataStorage dataStorage1, DataStorage dataStorage2, long startColumn, long columns, long power2length, long length, boolean isInverse, int modulus) { setModulus(MODULUS[modulus]); // Modulus rawtype w = (isInverse ? getInverseNthRoot(PRIMITIVE_ROOT[modulus], length) : getForwardNthRoot(PRIMITIVE_ROOT[modulus], length)), // Forward/inverse n:th root w3 = modPow(w, (rawtype) power2length), // Forward/inverse 3rd root ww = modMultiply(w, w), w1 = negate(modDivide((rawtype) 3, (rawtype) 2)), w2 = modAdd(w3, modDivide((rawtype) 1, (rawtype) 2)); ParallelRunnable parallelRunnable = new ParallelRunnable(columns) { @Override public Runnable getRunnable(long strideStartColumn, long strideColumns) { return new ColumnTransformRunnable(dataStorage0, dataStorage1, dataStorage2, startColumn + strideStartColumn, strideColumns, w, ww, w1, w2, isInverse); } }; return parallelRunnable; } } RawtypeKaratsubaConvolutionStrategy.java000066400000000000000000000236251461767713300343170ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorageBuilder; import org.apfloat.spi.DataStorage; /** * Convolution strategy using the Karatsuba algorithm. * The complexity of the algorithm is O(nlog(3)/log(2)) as * the operands are split to two and multiplied using three multiplications * (and five additions / subtractions). This splitting is done recursively * until some cut-off point where the basic O(n2) algorithm is * applied. The Karatsuba algorithm is faster than the basic O(n2) * multiplication algorithm for medium size numbers larger than some certain * size. For very large numbers, the transform-based convolution algorithms * are faster. * * @since 1.4 * @version 1.4 * @author Mikko Tommila */ public class RawtypeKaratsubaConvolutionStrategy extends RawtypeMediumConvolutionStrategy { /** * Cut-off point for Karatsuba / basic convolution.

* * Convolutions where the shorter number is at most this long * are calculated using the basic O(n2) algorithm * i.e. super.convolute(). */ public static final int CUTOFF_POINT = 15; /** * Creates a convolution strategy using the specified radix. * * @param radix The radix that will be used. */ public RawtypeKaratsubaConvolutionStrategy(int radix) { super(radix); } @Override public DataStorage convolute(DataStorage x, DataStorage y, long resultSize) throws ApfloatRuntimeException { if (Math.min(x.getSize(), y.getSize()) <= CUTOFF_POINT) { // The numbers are too short for Karatsuba to have any advantage, fall back to O(n^2) algorithm return super.convolute(x, y, resultSize); } DataStorage shortStorage, longStorage; if (x.getSize() > y.getSize()) { shortStorage = y; longStorage = x; } else { shortStorage = x; longStorage = y; } long shortSize = shortStorage.getSize(), longSize = longStorage.getSize(), size = shortSize + longSize, halfSize = longSize + 1 >> 1, // Split point for recursion, round up x1size = longSize - halfSize, x2size = halfSize, y1size = shortSize - halfSize; // y2size = halfSize ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); DataStorage resultStorage = dataStorageBuilder.createDataStorage(size * RawType.BYTES); resultStorage.setSize(size); if (y1size <= 0) { // The shorter number is half of the longer number or less, use simplified algorithm DataStorage.Iterator dst = resultStorage.iterator(DataStorage.WRITE, size, 0), src1 = null; rawtype carry = 0; long i = longSize, xSize; // Calculate sub-results in blocks of size shortSize do { xSize = Math.min(i, shortSize); x = longStorage.subsequence(i - xSize, xSize); y = shortStorage; // Calculate sub-convolutions recursively DataStorage a = convolute(x, y, xSize + shortSize); assert (a.getSize() == xSize + shortSize); // Add the sub-results together DataStorage.Iterator src2 = a.iterator(DataStorage.READ, xSize + shortSize, 0); carry = baseAdd(src1, src2, carry, dst, shortSize); src1 = src2; i -= shortSize; } while (i > 0); // Propagate carry through the last sub-result and store to result data carry = baseAdd(src1, null, carry, dst, xSize); assert (carry == 0); } else { // The numbers are roughly equal size (shorter is more than half of the longer), use Karatsuba algorithm DataStorage x1 = longStorage.subsequence(0, x1size), x2 = longStorage.subsequence(x1size, x2size), y1 = shortStorage.subsequence(0, y1size), y2 = shortStorage.subsequence(y1size, halfSize); // Calculate a = x1 + x2 DataStorage a = add(x1, x2); // Calculate b = y1 + y2 DataStorage b = add(y1, y2); // Calculate sub-convolutions recursively DataStorage c = convolute(a, b, a.getSize() + b.getSize()); a = convolute(x1, y1, x1size + y1size); b = convolute(x2, y2, 2 * halfSize); // Calculate c = c - a - b subtract(c, a); subtract(c, b); long cSize = c.getSize(), c1size = cSize - halfSize; if (c1size > x1size + y1size) { // We know that the top one or two words of c are zero // Omit them to avoid later having c1size > x1size + y1size long zeros = c1size - x1size - y1size; assert (isZero(c, 0)); assert (zeros == 1 || isZero(c, 1)); assert (zeros <= 2); cSize -= zeros; c1size -= zeros; c = c.subsequence(zeros, cSize); } assert (a.getSize() == x1size + y1size); assert (b.getSize() == 2 * halfSize); assert (cSize >= 2 * halfSize && cSize <= 2 * halfSize + 2); assert (c1size <= x1size + y1size); // Add the sub-results a + b + c together DataStorage.Iterator src1 = a.iterator(DataStorage.READ, x1size + y1size, 0), src2 = b.iterator(DataStorage.READ, 2 * halfSize, 0), src3 = c.iterator(DataStorage.READ, cSize, 0), dst = resultStorage.iterator(DataStorage.WRITE, size, 0); rawtype carry = 0; carry = baseAdd(src2, null, carry, dst, halfSize); carry = baseAdd(src2, src3, carry, dst, halfSize); carry = baseAdd(src1, src3, carry, dst, c1size); carry = baseAdd(src1, null, carry, dst, x1size + y1size - c1size); assert (carry == 0); } return resultStorage; } // Return x1 + x2 private DataStorage add(DataStorage x1, DataStorage x2) { long x1size = x1.getSize(), x2size = x2.getSize(); assert (x1size <= x2size); long size = x2size + 1; ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); DataStorage resultStorage = dataStorageBuilder.createDataStorage(size * RawType.BYTES); resultStorage.setSize(size); // Calculate x1 + x2 DataStorage.Iterator src1 = x1.iterator(DataStorage.READ, x1size, 0), src2 = x2.iterator(DataStorage.READ, x2size, 0), dst = resultStorage.iterator(DataStorage.WRITE, size, 0); rawtype carry = 0; carry = baseAdd(src1, src2, carry, dst, x1size); carry = baseAdd(src2, null, carry, dst, x2size - x1size); baseAdd(null, null, carry, dst, 1); // Set carry digit to the top word if (carry == 0) { resultStorage = resultStorage.subsequence(1, size - 1); // Omit zero top word } return resultStorage; } // x1 -= x2 private void subtract(DataStorage x1, DataStorage x2) { long x1size = x1.getSize(), x2size = x2.getSize(); assert (x1size >= x2size); DataStorage.Iterator src1 = x1.iterator(DataStorage.READ_WRITE, x1size, 0), src2 = x2.iterator(DataStorage.READ, x2size, 0), dst = src1; rawtype carry = 0; carry = baseSubtract(src1, src2, carry, dst, x2size); carry = baseSubtract(src1, null, carry, dst, x1size - x2size); assert (carry == 0); } private boolean isZero(DataStorage x, long index) { DataStorage.Iterator i = x.iterator(DataStorage.READ, index, index + 1); rawtype data = i.getRawtype(); i.next(); return data == 0; } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeKaratsubaConvolutionStrategy.serialVersionUID}; } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeMatrixBuilder.java000066400000000000000000000034241461767713300312440ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.MatrixBuilder; import org.apfloat.spi.MatrixStrategy; /** * Creates matrix operations objects, for the * rawtype type. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeMatrixBuilder implements MatrixBuilder { /** * Default constructor. */ public RawtypeMatrixBuilder() { } @Override public MatrixStrategy createMatrix() { return RawtypeMatrixBuilder.matrixStrategy; } private static MatrixStrategy matrixStrategy = new RawtypeMatrixStrategy(); } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeMatrixStrategy.java000066400000000000000000000427301461767713300314630ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.MatrixStrategy; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.Util; /** * Optimized matrix transposition methods for the rawtype type. * The matrix transposition algorithm isn't parallelized.

* * While the matrix transposition algorithm could easily be parallelized, * on an SMP machine it does not make any sense. If the matrix doesn't fit * in any processor specific cache then the memory (or higher level * shared cache) bandwidth becomes a bottleneck in the algorithm. Matrix * transposition is in principle a very simple algorithm - it doesn't do * anything else than move data from one place to another. If shared memory * is the bottleneck, then the algorithm isn't any faster if the data is being * moved around by one thread or by multiple threads in parallel.

* * If the data fits in a processor specific cache, then the algorithm could * theoretically be made faster with parallelization. To make the parallelization * effective however, the data would have to be set up in some kind of a NUMA * way. For example, each processor core would hold an equal section of * the data in the processor cache. Then the algorithm could be made faster * as each processor core could quickly transpose blocks of data that are in the * processor cache, and then exchange blocks with other processor cores via the * slower higher level shared cache or main memory.

* * This approach doesn't work well in practice however, at least not in a Java * program. The reason is that there are no guarantees where the data is when * the algorithm starts (in which processor core caches), and further there are * no guarantees of any processor affinity for the threads that are executing * in parallel. Different processor cores could be executing the transposition * of different sections of the data at any moment, depending on how the * operating system (and the JVM) schedule thread execution. And more often * than not, the operating system isn't smart enough to apply any such processor * affinity for the threads.

* * An additional problem for any NUMA based attempt is that the data array would * have to be aligned on a cache line (e.g. 64 or 128 bytes), to prevent * cache contention at the edges of each data section. But a JVM makes no such * guarantees about memory alignment. And since pointers do not exist in Java, * manually aligning memory addresses isn't possible.

* * Considering all of the above, the parallel algorithm doesn't in practice work * any faster than the single-thread algorithm, as the algorithm is bound by the * memory bandwidth (or shared cache bandwidth). In some cases parallelization * can even make the execution slower due to increased cache contention. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeMatrixStrategy implements MatrixStrategy { /** * Default constructor. */ public RawtypeMatrixStrategy() { } /** * Transpose a n1 x n2 matrix.

* * Both n1 and n2 must be powers of two. * Additionally, one of these must be true:

* * n1 = n2
* n1 = 2*n2
* n2 = 2*n1
* * @param arrayAccess Accessor to the matrix data. This data will be transposed. * @param n1 Number of rows in the matrix. * @param n2 Number of columns in the matrix. */ @Override public void transpose(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { rawtype[] data = arrayAccess.getRawtypeData(); int offset = arrayAccess.getOffset(); if (n1 != (n1 & -n1) || n2 != (n2 & -n2) || n1 <= 0 || n2 <= 0) { throw new ApfloatInternalException("Matrix size must be a power of two, not " + n1 + " x " + n2); } if (n1 == n2) { // Simply transpose transposeSquare(data, offset, n1, n1); } else if (n2 == 2 * n1) { // First transpose two n1 x n1 blocks transposeSquare(data, offset, n1, n2); transposeSquare(data, offset + n1, n1, n2); // Then permute the rows to correct order permuteToHalfWidth(data, offset, n1, n2); } else if (n1 == 2 * n2) { // First permute the rows to correct order permuteToDoubleWidth(data, offset, n1, n2); // Then transpose two n2 x n2 blocks transposeSquare(data, offset, n2, n1); transposeSquare(data, offset + n2, n2, n1); } else { throw new ApfloatInternalException("Must be n1 = n2, n1 = 2*n2 or n2 = 2*n1; matrix is " + n1 + " x " + n2); } } /** * Transpose a square n1 x n1 block of n1 x n2 matrix.

* * Both n1 and n2 must be powers of two, * and n1 <= n2. * * @param arrayAccess Accessor to the matrix data. This data will be transposed. * @param n1 Number of rows and columns in the block to be transposed. * @param n2 Number of columns in the matrix. */ @Override public void transposeSquare(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { transposeSquare(arrayAccess.getRawtypeData(), arrayAccess.getOffset(), n1, n2); } /** * Permute the rows of the n1 x n2 matrix so that it is shaped like a * n1/2 x 2*n2 matrix. Logically, the matrix is split in half, and the * lower half is moved to the right side of the upper half.

* * Both n1 and n2 must be powers of two, * and n1 >= 2.

* * E.g. if the matrix layout is originally as follows: * * * * * * * * * * * * * * *
Matrix before
0123
4567
891011
12131415
*

* * Then after this method it is as follows: * * * * * * * * *
Matrix after
0123891011
456712131415
* * @param arrayAccess Accessor to the matrix data. This data will be permuted. * @param n1 Number of rows in the matrix. * @param n2 Number of columns in the matrix. * * @since 1.7.0 */ @Override public void permuteToDoubleWidth(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { if (n1 != (n1 & -n1) || n2 != (n2 & -n2) || n1 <= 0 || n2 <= 0) { throw new ApfloatInternalException("Matrix size must be a power of two, not " + n1 + " x " + n2); } if (n1 < 2) { throw new ApfloatInternalException("Matrix height must be at least 2."); } permuteToDoubleWidth(arrayAccess.getRawtypeData(), arrayAccess.getOffset(), n1, n2); } /** * Permute the rows of the n1 x n2 matrix so that it is shaped like a * 2*n1 x n2/2 matrix. Logically, the matrix is split in half, and the * right half is moved below the left half.

* * Both n1 and n2 must be powers of two. * * E.g. if the matrix layout is originally as follows: * * * * * * * * *
Matrix before
01234567
89101112131415
*

* * Then after this method it is as follows: * * * * * * * * * * * * * * *
Matrix after
0123
891011
4567
12131415
* * @param arrayAccess Accessor to the matrix data. This data will be permuted. * @param n1 Number of rows in the matrix. * @param n2 Number of columns in the matrix. * * @since 1.7.0 */ @Override public void permuteToHalfWidth(ArrayAccess arrayAccess, int n1, int n2) throws ApfloatRuntimeException { if (n1 != (n1 & -n1) || n2 != (n2 & -n2) || n1 <= 0 || n2 <= 0) { throw new ApfloatInternalException("Matrix size must be a power of two, not " + n1 + " x " + n2); } permuteToHalfWidth(arrayAccess.getRawtypeData(), arrayAccess.getOffset(), n1, n2); } // Move a b x b block from source to dest private static void moveBlock(rawtype[] source, int sourceOffset, int sourceWidth, rawtype[] dest, int destOffset, int destWidth, int b) { for (int i = 0; i < b; i++) { System.arraycopy(source, sourceOffset, dest, destOffset, b); destOffset += destWidth; sourceOffset += sourceWidth; } } // Transpose two b x b blocks of matrix with specified width // data based on offset1 is accessed in columns, data based on offset2 in rows private static void transpose2blocks(rawtype[] data, int offset1, int offset2, int width, int b) { for (int i = 0, position1 = offset2; i < b; i++, position1 += width) { for (int j = 0, position2 = offset1 + i; j < b; j++, position2 += width) { rawtype tmp = data[position1 + j]; data[position1 + j] = data[position2]; data[position2] = tmp; } } } // Transpose a b x b block of matrix with specified width private static void transposeBlock(rawtype[] data, int offset, int width, int b) { for (int i = 0, position1 = offset; i < b; i++, position1 += width) { for (int j = i + 1, position2 = offset + j * width + i; j < b; j++, position2 += width) { rawtype tmp = data[position1 + j]; data[position1 + j] = data[position2]; data[position2] = tmp; } } } // Transpose a square n1 x n1 block of n1 x n2 matrix in b x b blocks private static void transposeSquare(rawtype[] data, int offset, int n1, int n2) { ApfloatContext ctx = ApfloatContext.getContext(); int cacheBurstBlockSize = Util.round2down(ctx.getCacheBurst() / 8), // Cache burst in rawtypes cacheBlockSize = Util.sqrt4down(ctx.getCacheL1Size() / 8), // Transpose block size b that fits in processor L1 cache cacheThreshold = Util.round2down(ctx.getCacheL2Size() / 8); // Size of matrix that fits in L2 cache if (n1 <= cacheBurstBlockSize || n1 <= cacheBlockSize) { // Whole matrix fits in L1 cache transposeBlock(data, offset, n2, n1); } else if (n1 * n2 <= cacheThreshold) { // Whole matrix fits in L2 cache (but not in L1 cache) // Sometimes the first algorithm (the block above) is faster, if your L2 cache is very fast int b = cacheBurstBlockSize; for (int i = 0, position1 = offset; i < n1; i += b, position1 += b * n2) { transposeBlock(data, position1 + i, n2, b); for (int j = i + b, position2 = offset + j * n2 + i; j < n1; j += b, position2 += b * n2) { transpose2blocks(data, position1 + j, position2, n2, b); } } } else { // Whole matrix doesn't fit in L2 cache // This algorithm works fastest if L1 cache size is set correctly int b = cacheBlockSize; rawtype[] tmp1 = new rawtype[b * b], tmp2 = new rawtype[b * b]; for (int i = 0, position1 = offset; i < n1; i += b, position1 += b * n2) { moveBlock(data, position1 + i, n2, tmp1, 0, b, b); transposeBlock(tmp1, 0, b, b); moveBlock(tmp1, 0, b, data, position1 + i, n2, b); for (int j = i + b, position2 = offset + j * n2 + i; j < n1; j += b, position2 += b * n2) { moveBlock(data, position1 + j, n2, tmp1, 0, b, b); transposeBlock(tmp1, 0, b, b); moveBlock(data, position2, n2, tmp2, 0, b, b); transposeBlock(tmp2, 0, b, b); moveBlock(tmp2, 0, b, data, position1 + j, n2, b); moveBlock(tmp1, 0, b, data, position2, n2, b); } } } } // Permute the rows of matrix to correct order, to make the n1 x n2 matrix half as wide (2*n1 x n2/2) private static void permuteToHalfWidth(rawtype[] data, int offset, int n1, int n2) { if (n1 < 2) { return; } int twicen1 = 2 * n1; int halfn2 = n2 / 2; rawtype[] tmp = new rawtype[halfn2]; boolean[] isRowDone = new boolean[twicen1]; int j = 1; do { int o = j, m = j; System.arraycopy(data, offset + halfn2 * m, tmp, 0, halfn2); isRowDone[m] = true; m = (m < n1 ? 2 * m : 2 * (m - n1) + 1); while (m != j) { isRowDone[m] = true; System.arraycopy(data, offset + halfn2 * m, data, offset + halfn2 * o, halfn2); o = m; m = (m < n1 ? 2 * m : 2 * (m - n1) + 1); } System.arraycopy(tmp, 0, data, offset + halfn2 * o, halfn2); while (isRowDone[j]) { j++; } } while (j < twicen1 - 1); } // Permute the rows of matrix to correct order, to make the n1 x n2 matrix twice as wide (n1/2 x 2*n2) private static void permuteToDoubleWidth(rawtype[] data, int offset, int n1, int n2) { if (n1 < 4) { return; } int halfn1 = n1 / 2; rawtype[] tmp = new rawtype[n2]; boolean[] isRowDone = new boolean[n1]; int j = 1; do { int o = j, m = j; System.arraycopy(data, offset + n2 * m, tmp, 0, n2); isRowDone[m] = true; m = ((m & 1) != 0 ? m / 2 + halfn1 : m / 2); while (m != j) { isRowDone[m] = true; System.arraycopy(data, offset + n2 * m, data, offset + n2 * o, n2); o = m; m = ((m & 1) != 0 ? m / 2 + halfn1 : m / 2); } System.arraycopy(tmp, 0, data, offset + n2 * o, n2); while (isRowDone[j]) { j++; } } while (j < n1 - 1); } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeMediumConvolutionStrategy.java000066400000000000000000000136101461767713300336720ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ConvolutionStrategy; import org.apfloat.spi.DataStorageBuilder; import org.apfloat.spi.DataStorage; /** * Medium-length convolution strategy. * Performs a simple O(n2) multiplication when the size of one operand is relatively short. * * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeMediumConvolutionStrategy extends RawtypeBaseMath implements ConvolutionStrategy { // Implementation notes: // - Assumes that the operands have been already truncated to match resultSize (the resultSize argument is ignored) // - This class probably shouldn't be converted to a single class using generics because there is some performance impact /** * Creates a convolution strategy using the specified radix. * * @param radix The radix that will be used. */ public RawtypeMediumConvolutionStrategy(int radix) { super(radix); } @Override public DataStorage convolute(DataStorage x, DataStorage y, long resultSize) throws ApfloatRuntimeException { DataStorage shortStorage, longStorage; if (x.getSize() > y.getSize()) { shortStorage = y; longStorage = x; } else { shortStorage = x; longStorage = y; } long shortSize = shortStorage.getSize(), longSize = longStorage.getSize(), size = shortSize + longSize; if (shortSize > Integer.MAX_VALUE) { throw new ApfloatInternalException("Too long shorter number, size = " + shortSize); } int bufferSize = (int) shortSize; ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); DataStorage resultStorage = dataStorageBuilder.createDataStorage(size * RawType.BYTES); resultStorage.setSize(size); DataStorage.Iterator src = longStorage.iterator(DataStorage.READ, longSize, 0), dst = resultStorage.iterator(DataStorage.WRITE, size, 0), tmpDst = new DataStorage.Iterator() // Cyclic iterator { @Override public void next() { this.position++; this.position = (this.position == bufferSize ? 0 : this.position); } @Override public rawtype getRawtype() { return this.buffer[this.position]; } @Override public void setRawtype(rawtype value) { this.buffer[this.position] = value; } private static final long serialVersionUID = 1L; private rawtype[] buffer = new rawtype[bufferSize]; private int position = 0; }; for (long i = 0; i < longSize; i++) { DataStorage.Iterator tmpSrc = shortStorage.iterator(DataStorage.READ, shortSize, 0); // Sub-optimal: this could be cyclic also rawtype factor = src.getRawtype(), // Get one word of source data carry = baseMultiplyAdd(tmpSrc, tmpDst, factor, 0, tmpDst, shortSize), result = tmpDst.getRawtype(); // Least significant word of the result dst.setRawtype(result); // Store one word of result tmpDst.setRawtype(carry); // Set carry from calculation as new last word in cyclic buffer tmpDst.next(); // Cycle buffer; current first word becomes last src.next(); dst.next(); } // Exhaust last words from temporary cyclic buffer and store them to result data for (int i = 0; i < bufferSize; i++) { rawtype result = tmpDst.getRawtype(); dst.setRawtype(result); tmpDst.next(); dst.next(); } return resultStorage; } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeMediumConvolutionStrategy.serialVersionUID}; } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeMemoryArrayAccess.java000066400000000000000000000047371461767713300320720ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; /** * Array access class based on a rawtype[]. * * @version 1.6.3 * @author Mikko Tommila */ public class RawtypeMemoryArrayAccess extends ArrayAccess { /** * Create an array access.

* * @param data The underlying array. * @param offset The offset of the access segment within the array. * @param length The access segment. */ public RawtypeMemoryArrayAccess(rawtype[] data, int offset, int length) { super(offset, length); this.data = data; } @Override public ArrayAccess subsequence(int offset, int length) { return new RawtypeMemoryArrayAccess(this.data, getOffset() + offset, length); } @Override public Object getData() { return this.data; } @Override public rawtype[] getRawtypeData() { return this.data; } @Override public void close() throws ApfloatRuntimeException { this.data = null; // Might have an impact on garbage collection } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeMemoryArrayAccess.serialVersionUID}; private rawtype[] data; } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeMemoryDataStorage.java000066400000000000000000000247661461767713300320740ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.DataStorage; import org.apfloat.spi.ArrayAccess; /** * Memory based data storage implementation for the rawtype * element type. * * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeMemoryDataStorage extends DataStorage { /** * Default constructor. */ public RawtypeMemoryDataStorage() { this.data = new rawtype[0]; } /** * Subsequence constructor. * * @param rawtypeMemoryDataStorage The originating data storage. * @param offset The subsequence starting position. * @param length The subsequence length. */ protected RawtypeMemoryDataStorage(RawtypeMemoryDataStorage rawtypeMemoryDataStorage, long offset, long length) { super(rawtypeMemoryDataStorage, offset, length); this.data = rawtypeMemoryDataStorage.data; } @Override public boolean isCached() { return true; } @Override protected DataStorage implSubsequence(long offset, long length) throws ApfloatRuntimeException { return new RawtypeMemoryDataStorage(this, offset + getOffset(), length); } @Override protected void implCopyFrom(DataStorage dataStorage, long size) throws ApfloatRuntimeException { assert (size > 0); assert (!isReadOnly()); assert (!isSubsequenced()); if (size > Integer.MAX_VALUE) { throw new ApfloatInternalException("Size too big for memory array: " + size); } if (dataStorage == this) { setSize(size); return; } this.data = new rawtype[(int) size]; ApfloatContext ctx = ApfloatContext.getContext(); int readSize = (int) Math.min(size, dataStorage.getSize()), position = 0, bufferSize = ctx.getBlockSize() / RawType.BYTES; while (readSize > 0) { int length = (int) Math.min(bufferSize, readSize); try (ArrayAccess arrayAccess = dataStorage.getArray(READ, position, length)) { System.arraycopy(arrayAccess.getRawtypeData(), arrayAccess.getOffset(), this.data, position, length); } readSize -= length; position += length; } } @Override protected long implGetSize() { return this.data.length; } @Override protected void implSetSize(long size) throws ApfloatRuntimeException { assert (size > 0); assert (!isReadOnly()); assert (!isSubsequenced()); if (size == this.data.length) { return; } if (size > Integer.MAX_VALUE) { throw new ApfloatInternalException("Size too big for memory array: " + size); } int newSize = (int) size; rawtype[] newData = new rawtype[newSize]; System.arraycopy(this.data, 0, newData, 0, Math.min(this.data.length, newSize)); this.data = newData; } @Override protected ArrayAccess implGetArray(int mode, long offset, int length) throws ApfloatRuntimeException { return new RawtypeMemoryArrayAccess(this.data, (int) (offset + getOffset()), length); } @Override protected ArrayAccess implGetArray(int mode, int startColumn, int columns, int rows) throws ApfloatRuntimeException { throw new ApfloatInternalException("Method not implemented - would be sub-optimal; change the apfloat configuration settings"); } @Override protected ArrayAccess implGetTransposedArray(int mode, int startColumn, int columns, int rows) throws ApfloatRuntimeException { throw new ApfloatInternalException("Method not implemented - would be sub-optimal; change the apfloat configuration settings"); } private class ReadWriteIterator extends AbstractIterator { public ReadWriteIterator(long startPosition, long endPosition) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { this(READ_WRITE, startPosition, endPosition); } protected ReadWriteIterator(int mode, long startPosition, long endPosition) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { super(mode, startPosition, endPosition); this.data = RawtypeMemoryDataStorage.this.data; this.position = (int) getPosition() + (int) getOffset(); this.length = (int) getLength(); } @Override public boolean hasNext() { return (this.length > 0); } @Override public void next() throws IllegalStateException { checkLength(); this.position += getIncrement(); this.length--; } @Override public rawtype getRawtype() throws IllegalStateException { checkLength(); return this.data[this.position]; } @Override public void setRawtype(rawtype value) throws IllegalStateException { checkLength(); this.data[this.position] = value; } @Override public T get(Class type) throws UnsupportedOperationException, IllegalStateException { if (!(type.equals(RawType.TYPE))) { throw new UnsupportedOperationException("Unsupported data type " + type.getCanonicalName() + ", the only supported type is rawtype"); } @SuppressWarnings("unchecked") T value = (T) (RawType) getRawtype(); return value; } @Override public void set(Class type, T value) throws UnsupportedOperationException, IllegalArgumentException, IllegalStateException { if (!(type.equals(RawType.TYPE))) { throw new UnsupportedOperationException("Unsupported data type " + type.getCanonicalName() + ", the only supported type is rawtype"); } if (!(value instanceof RawType)) { throw new IllegalArgumentException("Unsupported value type " + value.getClass().getCanonicalName() + ", the only supported type is RawType"); } setRawtype((RawType) value); } @Override protected void checkLength() throws IllegalStateException { if (this.length == 0) { throw new IllegalStateException("At the end of iterator"); } } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeMemoryDataStorage$ReadWriteIterator}; private rawtype[] data; private int position, length; } private class ReadOnlyIterator extends ReadWriteIterator { public ReadOnlyIterator(long startPosition, long endPosition) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { super(READ, startPosition, endPosition); } @Override public void setRawtype(rawtype value) throws IllegalStateException { throw new IllegalStateException("Not a writable iterator"); } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeMemoryDataStorage$ReadOnlyIterator}; } private class WriteOnlyIterator extends ReadWriteIterator { public WriteOnlyIterator(long startPosition, long endPosition) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { super(WRITE, startPosition, endPosition); } @Override public rawtype getRawtype() throws IllegalStateException { throw new IllegalStateException("Not a readable iterator"); } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeMemoryDataStorage$WriteOnlyIterator}; } @Override public Iterator iterator(int mode, long startPosition, long endPosition) throws IllegalArgumentException, IllegalStateException, ApfloatRuntimeException { Iterator iterator; switch (mode & READ_WRITE) { case READ: iterator = new ReadOnlyIterator(startPosition, endPosition); break; case WRITE: iterator = new WriteOnlyIterator(startPosition, endPosition); break; case READ_WRITE: iterator = new ReadWriteIterator(startPosition, endPosition); break; default: throw new IllegalArgumentException("Illegal mode: " + mode); } return iterator; } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeMemoryDataStorage.serialVersionUID}; private rawtype[] data; } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeModMath.java000066400000000000000000000113211461767713300300150ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Modulo arithmetic functions for rawtype data. * * @version 1.0 * @author Mikko Tommila */ public class RawtypeModMath extends RawtypeElementaryModMath { /** * Default constructor. */ public RawtypeModMath() { } /** * Create a table of powers of n:th root of unity. * * @param w The n:th root of unity modulo the current modulus. * @param n The table length (= transform length). * * @return Table of table[i]=wi mod m, i = 0, ..., n-1. */ public final rawtype[] createWTable(rawtype w, int n) { rawtype[] wTable = new rawtype[n]; rawtype wTemp = 1; for (int i = 0; i < n; i++) { wTable[i] = wTemp; wTemp = modMultiply(wTemp, w); } return wTable; } /** * Get forward n:th root of unity. This is w.

* * Assumes that the modulus is prime. * * @param primitiveRoot Primitive root of the modulus. * @param n The transform length. * * @return Forward n:th root of unity. */ public rawtype getForwardNthRoot(rawtype primitiveRoot, long n) { return modPow(primitiveRoot, getModulus() - 1 - (getModulus() - 1) / (rawtype) n); } /** * Get inverse n:th root of unity. This is w-1.

* * Assumes that the modulus is prime. * * @param primitiveRoot Primitive root of the modulus. * @param n The transform length. * * @return Inverse n:th root of unity. */ public rawtype getInverseNthRoot(rawtype primitiveRoot, long n) { return modPow(primitiveRoot, (getModulus() - 1) / (rawtype) n); } /** * Modular inverse, that is 1 / a. Assumes that the modulus is prime. * * @param a The operand. * * @return a-1 mod m. */ public final rawtype modInverse(rawtype a) { return modPow(a, getModulus() - 2); } /** * Modular division. Assumes that the modulus is prime. * * @param a The dividend. * @param b The divisor. * * @return a*b-1 mod m. */ public final rawtype modDivide(rawtype a, rawtype b) { return modMultiply(a, modInverse(b)); } /** * Modular negation. * * @param a The argument. * * @return -a mod m. */ public final rawtype negate(rawtype a) { return (a == 0 ? 0 : getModulus() - a); } /** * Modular power. Assumes that the modulus is prime. * * @param a The base. * @param n The exponent. * * @return an mod m. */ public final rawtype modPow(rawtype a, rawtype n) { assert (a != 0 || n != 0); if (n == 0) { return 1; } else if (n < 0) { return modPow(a, getModulus() - 1 + n); } long exponent = (long) n; while ((exponent & 1) == 0) { a = modMultiply(a, a); exponent >>= 1; } rawtype r = a; while ((exponent >>= 1) > 0) { a = modMultiply(a, a); if ((exponent & 1) != 0) { r = modMultiply(r, a); } } return r; } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeNTTBuilder.java000066400000000000000000000044731461767713300304520ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.NTTStrategy; import org.apfloat.spi.NTTStepStrategy; import org.apfloat.spi.Factor3NTTStepStrategy; import org.apfloat.spi.NTTConvolutionStepStrategy; /** * Creates Number Theoretic Transforms for the * rawtype type. * * @see RawtypeTableFNTStrategy * @see SixStepFNTStrategy * @see TwoPassFNTStrategy * @see Factor3NTTStrategy * * @version 1.8.3 * @author Mikko Tommila */ public class RawtypeNTTBuilder extends AbstractNTTBuilder { /** * Default constructor. */ public RawtypeNTTBuilder() { } @Override public NTTStepStrategy createNTTSteps() { return new RawtypeNTTStepStrategy(); } @Override public NTTConvolutionStepStrategy createNTTConvolutionSteps() { return new RawtypeNTTConvolutionStepStrategy(); } @Override public Factor3NTTStepStrategy createFactor3NTTSteps() { return new RawtypeFactor3NTTStepStrategy(); } @Override protected NTTStrategy createSimpleFNTStrategy(long size) { return new RawtypeTableFNTStrategy(); } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeNTTConvolutionStepStrategy.java000066400000000000000000000175011461767713300337560ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.NTTConvolutionStepStrategy; import org.apfloat.spi.DataStorage; import static org.apfloat.internal.RawtypeModConstants.*; /** * Steps of a three-NTT convolution for the rawtype type. * This class implements the details of the element-by-element multiplication * and element-by-element squaring of the transformed elements.

* * The in-place multiplication and squaring of the data elements is done * using a parallel algorithm, if the data fits in memory.

* * All access to this class must be externally synchronized. * * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeNTTConvolutionStepStrategy extends RawtypeModMath implements NTTConvolutionStepStrategy, Parallelizable { // Runnable for multiplying elements in place private class MultiplyInPlaceRunnable implements Runnable { public MultiplyInPlaceRunnable(DataStorage sourceAndDestination, DataStorage source, long offset, long length) { this.sourceAndDestination = sourceAndDestination; this.source = source; this.offset = offset; this.length = length; } @Override public void run() { DataStorage.Iterator dest = this.sourceAndDestination.iterator(DataStorage.READ_WRITE, this.offset, this.offset + this.length), src = this.source.iterator(DataStorage.READ, this.offset, this.offset + this.length); while (this.length > 0) { dest.setRawtype(modMultiply(dest.getRawtype(), src.getRawtype())); dest.next(); src.next(); this.length--; } } private DataStorage sourceAndDestination, source; private long offset, length; } // Runnable for squaring elements in place private class SquareInPlaceRunnable implements Runnable { public SquareInPlaceRunnable(DataStorage sourceAndDestination, long offset, long length) { this.sourceAndDestination = sourceAndDestination; this.offset = offset; this.length = length; } @Override public void run() { DataStorage.Iterator iterator = this.sourceAndDestination.iterator(DataStorage.READ_WRITE, this.offset, this.offset + this.length); while (this.length > 0) { rawtype value = iterator.getRawtype(); iterator.setRawtype(modMultiply(value, value)); iterator.next(); this.length--; } } private DataStorage sourceAndDestination; private long offset, length; } /** * Default constructor. */ public RawtypeNTTConvolutionStepStrategy() { } @Override public void multiplyInPlace(DataStorage sourceAndDestination, DataStorage source, int modulus) throws ApfloatRuntimeException { assert (sourceAndDestination != source); long size = sourceAndDestination.getSize(); ParallelRunnable parallelRunnable = createMultiplyInPlaceParallelRunnable(sourceAndDestination, source, modulus); if (size <= Integer.MAX_VALUE && // Only if the size fits in an integer, but with memory arrays it should sourceAndDestination.isCached() && source.isCached()) // Only if the data storage supports efficient parallel random access { ParallelRunner.runParallel(parallelRunnable); } else { parallelRunnable.run(); // Just run in current thread without parallelization } } @Override public void squareInPlace(DataStorage sourceAndDestination, int modulus) throws ApfloatRuntimeException { long size = sourceAndDestination.getSize(); ParallelRunnable parallelRunnable = createSquareInPlaceParallelRunnable(sourceAndDestination, modulus); if (size <= Integer.MAX_VALUE && // Only if the size fits in an integer, but with memory arrays it should sourceAndDestination.isCached()) // Only if the data storage supports efficient parallel random access { ParallelRunner.runParallel(parallelRunnable); } else { parallelRunnable.run(); // Just run in current thread without parallelization } } /** * Create a ParallelRunnable for multiplying the elements in-place. * * @param sourceAndDestination The first source data storage, which is also the destination. * @param source The second source data storage. * @param modulus Which modulus to use (0, 1, 2) * * @return An object suitable for multiplying the elements in parallel. */ protected ParallelRunnable createMultiplyInPlaceParallelRunnable(DataStorage sourceAndDestination, DataStorage source, int modulus) { long size = sourceAndDestination.getSize(); setModulus(MODULUS[modulus]); ParallelRunnable parallelRunnable = new ParallelRunnable(size) { @Override public Runnable getRunnable(long offset, long length) { return new MultiplyInPlaceRunnable(sourceAndDestination, source, offset, length); } }; return parallelRunnable; } /** * Create a ParallelRunnable for squaring the elements in-place. * * @param sourceAndDestination The source data storage, which is also the destination. * @param modulus Which modulus to use (0, 1, 2) * * @return An object suitable for squaring the elements in parallel. */ protected ParallelRunnable createSquareInPlaceParallelRunnable(DataStorage sourceAndDestination, int modulus) { long size = sourceAndDestination.getSize(); setModulus(MODULUS[modulus]); ParallelRunnable parallelRunnable = new ParallelRunnable(size) { @Override public Runnable getRunnable(long offset, long length) { return new SquareInPlaceRunnable(sourceAndDestination, offset, length); } }; return parallelRunnable; } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeNTTStepStrategy.java000066400000000000000000000231061461767713300315140ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.NTTStepStrategy; import static org.apfloat.internal.RawtypeModConstants.*; /** * Common methods to calculate Fast Number Theoretic Transforms * in parallel using multiple threads.

* * All access to this class must be externally synchronized. * * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeNTTStepStrategy extends RawtypeTableFNT implements NTTStepStrategy, Parallelizable { // Runnable for calculating the row transforms in parallel private class TableFNTRunnable implements Runnable { public TableFNTRunnable(int length, boolean isInverse, ArrayAccess arrayAccess, rawtype[] wTable, int[] permutationTable) { this.length = length; // Transform length this.isInverse = isInverse; this.arrayAccess = arrayAccess; this.wTable = wTable; this.permutationTable = permutationTable; } @Override public void run() { int maxI = this.arrayAccess.getLength(); for (int i = 0; i < maxI; i += this.length) { ArrayAccess arrayAccess = this.arrayAccess.subsequence(i, this.length); if (this.isInverse) { inverseTableFNT(arrayAccess, this.wTable, this.permutationTable); } else { tableFNT(arrayAccess, this.wTable, this.permutationTable); } } } private int length; private boolean isInverse; private ArrayAccess arrayAccess; private rawtype[] wTable; private int[] permutationTable; } // Runnable for multiplying elements in the matrix private class MultiplyRunnable implements Runnable { public MultiplyRunnable(ArrayAccess arrayAccess, int startRow, int startColumn, int rows, int columns, rawtype w, rawtype scaleFactor) { this.arrayAccess = arrayAccess; this.startRow = startRow; this.startColumn = startColumn; this.rows = rows; this.columns = columns; this.w = w; this.scaleFactor = scaleFactor; } @Override public void run() { rawtype[] data = this.arrayAccess.getRawtypeData(); int position = this.arrayAccess.getOffset(); rawtype rowFactor = modPow(this.w, (rawtype) this.startRow); rawtype columnFactor = modPow(this.w, (rawtype) this.startColumn); rawtype rowStartFactor = modMultiply(this.scaleFactor, modPow(rowFactor, (rawtype) this.startColumn)); for (int i = 0; i < this.rows; i++) { rawtype factor = rowStartFactor; for (int j = 0; j < this.columns; j++, position++) { data[position] = modMultiply(data[position], factor); factor = modMultiply(factor, rowFactor); } rowFactor = modMultiply(rowFactor, this.w); rowStartFactor = modMultiply(rowStartFactor, columnFactor); } } private ArrayAccess arrayAccess; private int startRow; private int startColumn; private int rows; private int columns; private rawtype w; private rawtype scaleFactor; } /** * Default constructor. */ public RawtypeNTTStepStrategy() { } @Override public void multiplyElements(ArrayAccess arrayAccess, int startRow, int startColumn, int rows, int columns, long length, long totalTransformLength, boolean isInverse, int modulus) throws ApfloatRuntimeException { ParallelRunnable parallelRunnable = createMultiplyElementsParallelRunnable(arrayAccess, startRow, startColumn, rows, columns, length, totalTransformLength, isInverse, modulus); ParallelRunner.runParallel(parallelRunnable); } @Override public void transformRows(ArrayAccess arrayAccess, int length, int count, boolean isInverse, boolean permute, int modulus) throws ApfloatRuntimeException { ParallelRunnable parallelRunnable = createTransformRowsParallelRunnable(arrayAccess, length, count, isInverse, permute, modulus); ParallelRunner.runParallel(parallelRunnable); } @Override public long getMaxTransformLength() { return MAX_TRANSFORM_LENGTH; } /** * Create a ParallelRunnable object for multiplying the elements of the matrix. * * @param arrayAccess The memory array to multiply. * @param startRow Which row in the whole matrix the starting row in the arrayAccess is. * @param startColumn Which column in the whole matrix the starting column in the arrayAccess is. * @param rows The number of rows in the arrayAccess to multiply. * @param columns The number of columns in the matrix (= n2). * @param length The length of data in the matrix being transformed. * @param totalTransformLength The total transform length, for the scaling factor. Used only for the inverse case. * @param isInverse If the multiplication is done for the inverse transform or not. * @param modulus Index of the modulus. * * @return An object suitable for multiplying the elements of the matrix in parallel. */ protected ParallelRunnable createMultiplyElementsParallelRunnable(ArrayAccess arrayAccess, int startRow, int startColumn, int rows, int columns, long length, long totalTransformLength, boolean isInverse, int modulus) throws ApfloatRuntimeException { setModulus(MODULUS[modulus]); rawtype w = (isInverse ? getInverseNthRoot(PRIMITIVE_ROOT[modulus], length) : getForwardNthRoot(PRIMITIVE_ROOT[modulus], length)), scaleFactor = (isInverse ? modDivide((rawtype) 1, (rawtype) totalTransformLength) : (rawtype) 1); ParallelRunnable parallelRunnable = new ParallelRunnable(rows) { @Override public Runnable getRunnable(int strideStartRow, int strideRows) { ArrayAccess subArrayAccess = arrayAccess.subsequence(strideStartRow * columns, strideRows * columns); return new MultiplyRunnable(subArrayAccess, startRow + strideStartRow, startColumn, strideRows, columns, w, scaleFactor); } }; return parallelRunnable; } /** * Create a ParallelRunnable object for transforming the rows of the matrix. * * @param arrayAccess The memory array to split to rows and to transform. * @param length Length of one transform (one row). * @param count Number of rows. * @param isInverse true if an inverse transform is performed, false if a forward transform is performed. * @param permute If permutation should be done. * @param modulus Index of the modulus. * * @return An object suitable for transforming the rows of the matrix in parallel. */ protected ParallelRunnable createTransformRowsParallelRunnable(ArrayAccess arrayAccess, int length, int count, boolean isInverse, boolean permute, int modulus) throws ApfloatRuntimeException { setModulus(MODULUS[modulus]); rawtype[] wTable = (isInverse ? RawtypeWTables.getInverseWTable(modulus, length) : RawtypeWTables.getWTable(modulus, length)); int[] permutationTable = (permute ? Scramble.createScrambleTable(length) : null); ParallelRunnable parallelRunnable = new ParallelRunnable(count) { @Override public Runnable getRunnable(int startIndex, int strideCount) { ArrayAccess subArrayAccess = arrayAccess.subsequence(startIndex * length, strideCount * length); return new TableFNTRunnable(length, isInverse, subArrayAccess, wTable, permutationTable); } }; return parallelRunnable; } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeScramble.java000066400000000000000000000043241461767713300302210ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; /** * Functions to perform bit-reverse ordering of rawtype data. * * @version 1.0 * @author Mikko Tommila */ public class RawtypeScramble { private RawtypeScramble() { } /** * Permute the data in the table to bit-reversed order.

* * The permutation table argument should contain pairs of indexes * that indicate array elements whose contents are swapped. * * @param data The array to permute. * @param offset The offset within the array to permute. * @param permutationTable Table of indexes indicating, which elements in the data are to be swapped. */ public static void scramble(rawtype[] data, int offset, int[] permutationTable) { for (int k = 0; k < permutationTable.length; k += 2) { int i = offset + permutationTable[k], j = offset + permutationTable[k + 1]; rawtype tmp = data[i]; data[i] = data[j]; data[j] = tmp; } } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeShortConvolutionStrategy.java000066400000000000000000000072351461767713300335570ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatContext; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ConvolutionStrategy; import org.apfloat.spi.DataStorageBuilder; import org.apfloat.spi.DataStorage; import org.apfloat.spi.ArrayAccess; /** * Short convolution strategy. * Performs a simple multiplication when the size of one operand is 1. * * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeShortConvolutionStrategy extends RawtypeBaseMath implements ConvolutionStrategy { // Implementation notes: // - Assumes that the operands have been already truncated to match resultSize (the resultSize argument is ignored) // - This class shouldn't be converted to a single class using generics because the performance impact is noticeable /** * Creates a convolution strategy using the specified radix. * * @param radix The radix that will be used. */ public RawtypeShortConvolutionStrategy(int radix) { super(radix); } @Override public DataStorage convolute(DataStorage x, DataStorage y, long resultSize) throws ApfloatRuntimeException { DataStorage shortStorage, longStorage, resultStorage; if (x.getSize() > 1) { shortStorage = y; longStorage = x; } else { shortStorage = x; longStorage = y; } assert (shortStorage.getSize() == 1); long size = longStorage.getSize() + 1; rawtype factor; try (ArrayAccess arrayAccess = shortStorage.getArray(DataStorage.READ, 0, 1)) { factor = arrayAccess.getRawtypeData()[arrayAccess.getOffset()]; } ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); resultStorage = dataStorageBuilder.createDataStorage(size * RawType.BYTES); resultStorage.setSize(size); DataStorage.Iterator src = longStorage.iterator(DataStorage.READ, size - 1, 0); try (DataStorage.Iterator dst = resultStorage.iterator(DataStorage.WRITE, size, 0)) { rawtype carry = baseMultiplyAdd(src, null, factor, 0, dst, size - 1); dst.setRawtype(carry); } return resultStorage; } private static final long serialVersionUID = ${org.apfloat.internal.RawtypeShortConvolutionStrategy.serialVersionUID}; } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeTableFNT.java000066400000000000000000000130421461767713300300650ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.ArrayAccess; /** * Fast Number Theoretic Transform that uses lookup tables * for powers of n:th root of unity and permutation indexes.

* * All access to this class must be externally synchronized. * * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeTableFNT extends RawtypeModMath { /** * Default constructor. */ public RawtypeTableFNT() { } /** * Forward (Sande-Tukey) fast Number Theoretic Transform. * Data length must be a power of two. * * @param arrayAccess The data array to transform. * @param wTable Table of powers of n:th root of unity w modulo the current modulus. * @param permutationTable Table of permutation indexes, or null if the data should not be permuted. */ public void tableFNT(ArrayAccess arrayAccess, rawtype[] wTable, int[] permutationTable) throws ApfloatRuntimeException { int nn, offset, istep, mmax, r; rawtype[] data; data = arrayAccess.getRawtypeData(); offset = arrayAccess.getOffset(); nn = arrayAccess.getLength(); assert (nn == (nn & -nn)); if (nn < 2) { return; } r = 1; mmax = nn >> 1; while (mmax > 0) { istep = mmax << 1; // Optimize first step when wr = 1 for (int i = offset; i < offset + nn; i += istep) { int j = i + mmax; rawtype a = data[i]; rawtype b = data[j]; data[i] = modAdd(a, b); data[j] = modSubtract(a, b); } int t = r; for (int m = 1; m < mmax; m++) { for (int i = offset + m; i < offset + nn; i += istep) { int j = i + mmax; rawtype a = data[i]; rawtype b = data[j]; data[i] = modAdd(a, b); data[j] = modMultiply(wTable[t], modSubtract(a, b)); } t += r; } r <<= 1; mmax >>= 1; } if (permutationTable != null) { RawtypeScramble.scramble(data, offset, permutationTable); } } /** * Inverse (Cooley-Tukey) fast Number Theoretic Transform. * Data length must be a power of two. * * @param arrayAccess The data array to transform. * @param wTable Table of powers of n:th root of unity w modulo the current modulus. * @param permutationTable Table of permutation indexes, or null if the data should not be permuted. */ public void inverseTableFNT(ArrayAccess arrayAccess, rawtype[] wTable, int[] permutationTable) throws ApfloatRuntimeException { int nn, offset, istep, mmax, r; rawtype[] data; data = arrayAccess.getRawtypeData(); offset = arrayAccess.getOffset(); nn = arrayAccess.getLength(); assert (nn == (nn & -nn)); if (nn < 2) { return; } if (permutationTable != null) { RawtypeScramble.scramble(data, offset, permutationTable); } r = nn; mmax = 1; while (nn > mmax) { istep = mmax << 1; r >>= 1; // Optimize first step when w = 1 for (int i = offset; i < offset + nn; i += istep) { int j = i + mmax; rawtype wTemp = data[j]; data[j] = modSubtract(data[i], wTemp); data[i] = modAdd(data[i], wTemp); } int t = r; for (int m = 1; m < mmax; m++) { for (int i = offset + m; i < offset + nn; i += istep) { int j = i + mmax; rawtype wTemp = modMultiply(wTable[t], data[j]); data[j] = modSubtract(data[i], wTemp); data[i] = modAdd(data[i], wTemp); } t += r; } mmax = istep; } } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeTableFNTStrategy.java000066400000000000000000000107051461767713300316130ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.ApfloatRuntimeException; import org.apfloat.spi.NTTStrategy; import org.apfloat.spi.DataStorage; import org.apfloat.spi.ArrayAccess; import org.apfloat.spi.Util; import static org.apfloat.internal.RawtypeModConstants.*; /** * Fast Number Theoretic Transform strategy that uses lookup tables * for powers of n:th root of unity and permutation indexes.

* * All access to this class must be externally synchronized. * * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeTableFNTStrategy extends RawtypeTableFNT implements NTTStrategy { /** * Default constructor. */ public RawtypeTableFNTStrategy() { } @Override public void transform(DataStorage dataStorage, int modulus) throws ApfloatRuntimeException { long length = dataStorage.getSize(); // Transform length n if (length > MAX_TRANSFORM_LENGTH) { throw new TransformLengthExceededException("Maximum transform length exceeded: " + length + " > " + MAX_TRANSFORM_LENGTH); } else if (length > Integer.MAX_VALUE) { throw new ApfloatInternalException("Maximum array length exceeded: " + length); } setModulus(MODULUS[modulus]); // Modulus rawtype[] wTable = RawtypeWTables.getWTable(modulus, (int) length); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ_WRITE, 0, (int) length)) { tableFNT(arrayAccess, wTable, null); } } @Override public void inverseTransform(DataStorage dataStorage, int modulus, long totalTransformLength) throws ApfloatRuntimeException { long length = dataStorage.getSize(); // Transform length n if (Math.max(length, totalTransformLength) > MAX_TRANSFORM_LENGTH) { throw new TransformLengthExceededException("Maximum transform length exceeded: " + Math.max(length, totalTransformLength) + " > " + MAX_TRANSFORM_LENGTH); } else if (length > Integer.MAX_VALUE) { throw new ApfloatInternalException("Maximum array length exceeded: " + length); } setModulus(MODULUS[modulus]); // Modulus rawtype[] wTable = RawtypeWTables.getInverseWTable(modulus, (int) length); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ_WRITE, 0, (int) length)) { inverseTableFNT(arrayAccess, wTable, null); divideElements(arrayAccess, (rawtype) totalTransformLength); } } @Override public long getTransformLength(long size) { return Util.round2up(size); } private void divideElements(ArrayAccess arrayAccess, rawtype divisor) throws ApfloatRuntimeException { rawtype inverseFactor = modDivide((rawtype) 1, divisor); rawtype[] data = arrayAccess.getRawtypeData(); int length = arrayAccess.getLength(), offset = arrayAccess.getOffset(); for (int i = 0; i < length; i++) { data[i + offset] = modMultiply(data[i + offset], inverseFactor); } } } apfloat-1.14.0/apfloat/src/main/template/org/apfloat/internal/RawtypeWTables.java000066400000000000000000000100211461767713300300210ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentMap; import static org.apfloat.internal.RawtypeModConstants.*; /** * Helper class for generating and caching tables of powers of the n:th root of unity. * * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeWTables extends RawtypeModMath { private RawtypeWTables() { // Default constructor } /** * Get a table of powers of n:th root of unity. * * @param modulus The index of the modulus to be used. * @param length The length of the table to be returned, i.e. n. * * @return The table of powers of the n:th root of unity. */ public static rawtype[] getWTable(int modulus, int length) { return getWTable(modulus, length, false); } /** * Get a table of inverses of powers of n:th root of unity. * * @param modulus The index of the modulus to be used. * @param length The length of the table to be returned, i.e. n. * * @return The table of inverses of powers of the n:th root of unity. */ public static rawtype[] getInverseWTable(int modulus, int length) { return getWTable(modulus, length, true); } private static rawtype[] getWTable(int modulus, int length, boolean isInverse) { List key = Arrays.asList(isInverse ? 1 : 0, modulus, length); rawtype[] wTable = RawtypeWTables.cache.get(key); // Do not synchronize, multiple threads may do this at the same time, but only one gets to put the value in the cache if (wTable == null) { RawtypeModMath instance = getInstance(modulus); rawtype w = (isInverse ? instance.getInverseNthRoot(PRIMITIVE_ROOT[modulus], length) : // Inverse n:th root instance.getForwardNthRoot(PRIMITIVE_ROOT[modulus], length)); // Forward n:th root wTable = instance.createWTable(w, length); // Check if another thread already put the wTable in the cache; if so then use it rawtype[] value = RawtypeWTables.cache.putIfAbsent(key, wTable); if (value != null) { // Another thread did put the value in the cache so use it wTable = value; } } return wTable; } private static RawtypeModMath getInstance(int modulus) { RawtypeModMath instance = new RawtypeModMath(); instance.setModulus(MODULUS[modulus]); return instance; } // With inverses, three moduli and lengths being powers of two, the theoretical maximum map size is 2 * 3 * 30 = 180 entries private static ConcurrentMap, rawtype[]> cache = new ConcurrentSoftHashMap<>(); } apfloat-1.14.0/apfloat/src/test/000077500000000000000000000000001461767713300164365ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/java/000077500000000000000000000000001461767713300173575ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/java/org/000077500000000000000000000000001461767713300201465ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/java/org/apfloat/000077500000000000000000000000001461767713300215745ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ApcomplexMathTest.java000066400000000000000000025716701461767713300260630ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import junit.framework.TestSuite; /** * @version 1.14.0 * @author Mikko Tommila */ public class ApcomplexMathTest extends ApfloatTestCase { public ApcomplexMathTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApcomplexMathTest("testNegate")); suite.addTest(new ApcomplexMathTest("testAbs")); suite.addTest(new ApcomplexMathTest("testNorm")); suite.addTest(new ApcomplexMathTest("testScale")); suite.addTest(new ApcomplexMathTest("testIntegerPow")); suite.addTest(new ApcomplexMathTest("testInverseRoot")); suite.addTest(new ApcomplexMathTest("testRoot")); suite.addTest(new ApcomplexMathTest("testAllRoots")); suite.addTest(new ApcomplexMathTest("testAgm")); suite.addTest(new ApcomplexMathTest("testLog")); suite.addTest(new ApcomplexMathTest("testLogBase")); suite.addTest(new ApcomplexMathTest("testExp")); suite.addTest(new ApcomplexMathTest("testPow")); suite.addTest(new ApcomplexMathTest("testArg")); suite.addTest(new ApcomplexMathTest("testAcosh")); suite.addTest(new ApcomplexMathTest("testAsinh")); suite.addTest(new ApcomplexMathTest("testAtanh")); suite.addTest(new ApcomplexMathTest("testCosh")); suite.addTest(new ApcomplexMathTest("testSinh")); suite.addTest(new ApcomplexMathTest("testTanh")); suite.addTest(new ApcomplexMathTest("testAcos")); suite.addTest(new ApcomplexMathTest("testAsin")); suite.addTest(new ApcomplexMathTest("testAtan")); suite.addTest(new ApcomplexMathTest("testCos")); suite.addTest(new ApcomplexMathTest("testSin")); suite.addTest(new ApcomplexMathTest("testTan")); suite.addTest(new ApcomplexMathTest("testCot")); suite.addTest(new ApcomplexMathTest("testSinc")); suite.addTest(new ApcomplexMathTest("testW")); suite.addTest(new ApcomplexMathTest("testProduct")); suite.addTest(new ApcomplexMathTest("testSum")); suite.addTest(new ApcomplexMathTest("testGamma")); suite.addTest(new ApcomplexMathTest("testGammaIncomplete")); suite.addTest(new ApcomplexMathTest("testGammaIncompleteGeneralized")); suite.addTest(new ApcomplexMathTest("testLogGamma")); suite.addTest(new ApcomplexMathTest("testDigamma")); suite.addTest(new ApcomplexMathTest("testPolygamma")); suite.addTest(new ApcomplexMathTest("testBeta")); suite.addTest(new ApcomplexMathTest("testBetaIncomplete")); suite.addTest(new ApcomplexMathTest("testBetaIncompleteGeneralized")); suite.addTest(new ApcomplexMathTest("testPochhammer")); suite.addTest(new ApcomplexMathTest("testBinomial")); suite.addTest(new ApcomplexMathTest("testZeta")); suite.addTest(new ApcomplexMathTest("testZetaHurwitz")); suite.addTest(new ApcomplexMathTest("testHypergeometric0F1")); suite.addTest(new ApcomplexMathTest("testHypergeometric1F1")); suite.addTest(new ApcomplexMathTest("testHypergeometric2F1")); suite.addTest(new ApcomplexMathTest("testHypergeometric0F1Regularized")); suite.addTest(new ApcomplexMathTest("testHypergeometric1F1Regularized")); suite.addTest(new ApcomplexMathTest("testHypergeometric2F1Regularized")); suite.addTest(new ApcomplexMathTest("testHypergeometricU")); suite.addTest(new ApcomplexMathTest("testErf")); suite.addTest(new ApcomplexMathTest("testErfc")); suite.addTest(new ApcomplexMathTest("testErfi")); suite.addTest(new ApcomplexMathTest("testFresnelS")); suite.addTest(new ApcomplexMathTest("testFresnelC")); suite.addTest(new ApcomplexMathTest("testExpIntegralE")); suite.addTest(new ApcomplexMathTest("testExpIntegralEi")); suite.addTest(new ApcomplexMathTest("testLogIntegral")); suite.addTest(new ApcomplexMathTest("testSinIntegral")); suite.addTest(new ApcomplexMathTest("testCosIntegral")); suite.addTest(new ApcomplexMathTest("testSinhIntegral")); suite.addTest(new ApcomplexMathTest("testCoshIntegral")); suite.addTest(new ApcomplexMathTest("testAiryAi")); suite.addTest(new ApcomplexMathTest("testAiryAiPrime")); suite.addTest(new ApcomplexMathTest("testAiryBi")); suite.addTest(new ApcomplexMathTest("testAiryBiPrime")); suite.addTest(new ApcomplexMathTest("testBesselJ")); suite.addTest(new ApcomplexMathTest("testBesselI")); suite.addTest(new ApcomplexMathTest("testBesselY")); suite.addTest(new ApcomplexMathTest("testBesselK")); suite.addTest(new ApcomplexMathTest("testEllipticK")); suite.addTest(new ApcomplexMathTest("testEllipticE")); suite.addTest(new ApcomplexMathTest("testHermiteH")); suite.addTest(new ApcomplexMathTest("testLaguerreL")); suite.addTest(new ApcomplexMathTest("testLaguerreLGeneralized")); suite.addTest(new ApcomplexMathTest("testLegendreP")); suite.addTest(new ApcomplexMathTest("testLegendrePAssociated")); suite.addTest(new ApcomplexMathTest("testLegendreQ")); suite.addTest(new ApcomplexMathTest("testLegendreQAssociated")); suite.addTest(new ApcomplexMathTest("testSphericalHarmonicY")); suite.addTest(new ApcomplexMathTest("testChebyshevT")); suite.addTest(new ApcomplexMathTest("testChebyshevU")); suite.addTest(new ApcomplexMathTest("testGegenbauerCRenormalized")); suite.addTest(new ApcomplexMathTest("testGegenbauerC")); suite.addTest(new ApcomplexMathTest("testJacobiP")); suite.addTest(new ApcomplexMathTest("testFibonacci")); suite.addTest(new ApcomplexMathTest("testEulerE")); suite.addTest(new ApcomplexMathTest("testBernoulliB")); suite.addTest(new ApcomplexMathTest("testHarmonicNumber")); suite.addTest(new ApcomplexMathTest("testHarmonicNumberGeneralized")); suite.addTest(new ApcomplexMathTest("testPolylog")); suite.addTest(new ApcomplexMathTest("testLogisticSigmoid")); suite.addTest(new ApcomplexMathTest("testUlp")); return suite; } @SuppressWarnings("deprecation") public static void testNegate() { Apcomplex z = new Apcomplex("(2,3)"); assertEquals("(2,3)", new Apcomplex("(-2,-3)"), ApcomplexMath.negate(z)); z = new Apcomplex("0"); assertEquals("0", new Apcomplex("0"), ApcomplexMath.negate(z)); } public static void testAbs() { Apcomplex z = new Apcomplex("(3,4)"); assertEquals("(3,4)", new Apfloat(5), ApcomplexMath.abs(z)); z = new Apcomplex("-4"); assertEquals("-4", new Apfloat(4), ApcomplexMath.abs(z)); z = new Apcomplex("(0,-4)"); assertEquals("(0,-4)", new Apfloat(4), ApcomplexMath.abs(z)); z = new Apcomplex("0"); assertEquals("0", new Apfloat(0), ApcomplexMath.abs(z)); } public static void testNorm() { Apcomplex z = new Apcomplex(new Apfloat(2), new Apfloat(3)); assertEquals("(2,3)", new Apfloat(13), ApcomplexMath.norm(z)); z = new Apcomplex("0"); assertEquals("0", new Apfloat(0), ApcomplexMath.norm(z)); } public static void testScale() { Apcomplex z = new Apcomplex("(2,3)"); assertEquals("(2,3)", new Apcomplex("(20,30)"), ApcomplexMath.scale(z, 1)); z = new Apcomplex("0"); assertEquals("0", new Apfloat(0), ApcomplexMath.scale(z, 1)); } public static void testIntegerPow() { Apcomplex z = new Apcomplex(new Apfloat(2, 1000), new Apfloat(3, 1000)); assertEquals("(2,3)^3", new Apcomplex("(-46,9)"), ApcomplexMath.pow(z, 3)); z = new Apcomplex(new Apfloat(3, 1000), new Apfloat(4, 1000)); assertEquals("(3,4)^-1", new Apcomplex("(0.12,-0.16)"), ApcomplexMath.pow(z, -1)); assertEquals("(3,4)^-2", new Apcomplex("(-0.0112,-0.0384)"), ApcomplexMath.pow(z, -2)); assertEquals("(3,4)^0", new Apcomplex("1"), ApcomplexMath.pow(z, 0)); z = new Apcomplex(Apfloat.ZERO, new Apfloat(4, 1000)); assertEquals("(0,4)^0", new Apcomplex("1"), ApcomplexMath.pow(z, 0)); assertEquals("(2,3)^1000000000", ApcomplexMath.pow(z, 1000000000).precision(10), ApcomplexMath.pow(z.precision(11), 1000000000).precision(10)); z = new Apcomplex("(0,1.0000000000000000000000000000000000000000100000000)"); assertEquals("1.00000000000000000000000000000000000000001^0x7FFFFFFFFFFFFFFF", new Apcomplex("(0,-1.0000000000000000000000922337203685477580700042535)"), ApcomplexMath.pow(z, 0x7FFFFFFFFFFFFFFFL), new Apfloat(1e-48)); assertEquals("1.00000000000000000000000000000000000000001^0x8000000000000000", new Apfloat("0.99999999999999999999990776627963145224192000425352"), ApcomplexMath.pow(z, 0x8000000000000000L), new Apfloat(1e-48)); try { ApcomplexMath.pow(new Apcomplex("0"), 0); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } } public static void testInverseRoot() { Apcomplex z = new Apcomplex(new Apfloat(0), new Apfloat(1, 30)); assertEquals("(0,1)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(0,1)^-1/2, value", new Apcomplex("(0.707106781186547524400844362105, -0.707106781186547524400844362105)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-30")); z = new Apcomplex(new Apfloat(0), new Apfloat(1, 20)); assertEquals("(0,1)^-1/2, precision", 20, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(0,1)^-1/2, value", new Apcomplex("(0.70710678118654752440, -0.70710678118654752440)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-20")); z = new Apcomplex(new Apfloat(0), new Apfloat(1, 10)); assertEquals("(0,1)^-1/2, precision", 10, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(0,1)^-1/2, value", new Apcomplex("(0.7071067812, -0.7071067812)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-10")); z = new Apcomplex(new Apfloat(0), new Apfloat(1, 5)); assertEquals("(0,1)^-1/2, precision", 5, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(0,1)^-1/2, value", new Apcomplex("(0.70711, -0.70711)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-5")); z = new Apcomplex(new Apfloat(0), new Apfloat(-1, 30)); assertEquals("(0,-1)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(0,-1)^-1/2, value", new Apcomplex("(0.707106781186547524400844362105, 0.707106781186547524400844362105)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-30")); z = new Apcomplex(new Apfloat(-1, 30), new Apfloat(0)); assertEquals("(-1,0)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(-1,0)^-1/2, value", new Apcomplex("(0, -1)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-30")); z = new Apcomplex(new Apfloat(-1, 30), new Apfloat(0)); assertEquals("(-1,0)^-1/3, precision", 30, ApcomplexMath.inverseRoot(z, 3).precision()); assertEquals("(-1,0)^-1/3, value", new Apcomplex("(0.5, -0.866025403784438646763723170753)"), ApcomplexMath.inverseRoot(z, 3), new Apfloat("5e-30")); z = new Apcomplex(new Apfloat(-1, 30), new Apfloat(0)); assertEquals("(-1,0)^-1/4, precision", 30, ApcomplexMath.inverseRoot(z, 4).precision()); assertEquals("(-1,0)^-1/4, value", new Apcomplex("(0.707106781186547524400844362105, -0.707106781186547524400844362105)"), ApcomplexMath.inverseRoot(z, 4), new Apfloat("5e-30")); z = new Apcomplex("(-0.707106781186547524400844362105, 0.707106781186547524400844362105)"); assertEquals("(-1/sqrt(2),1/sqrt(2))^-1/3, precision", 30, ApcomplexMath.inverseRoot(z, 3).precision()); assertEquals("(-1/sqrt(2),1/sqrt(2))^-1/3, value", new Apcomplex("(0.707106781186547524400844362105, -0.707106781186547524400844362105)"), ApcomplexMath.inverseRoot(z, 3), new Apfloat("5e-30")); z = new Apcomplex("(0.707106781186547524400844362105, 0.707106781186547524400844362105)"); assertEquals("(1/sqrt(2),1/sqrt(2))^-1/3, precision", 30, ApcomplexMath.inverseRoot(z, 3).precision()); assertEquals("(1/sqrt(2),1/sqrt(2))^-1/3, value", new Apcomplex("(0.965925826289068286749743199729, -0.258819045102520762348898837624)"), ApcomplexMath.inverseRoot(z, 3), new Apfloat("5e-30")); z = new Apcomplex(new Apfloat(2, 30), new Apfloat(0)); assertEquals("2^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("2^-1/2, value", new Apcomplex("0.707106781186547524400844362105"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-30")); z = new Apcomplex(new Apfloat("-1e20", 30), new Apfloat(1)); assertEquals("(-1e20,1)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(-1e20,1)^-1/2, value", new Apcomplex(new Apfloat("5e-31", 30), new Apfloat("-1e-10", 30)), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-40")); z = new Apcomplex(new Apfloat("-1e20", 30), new Apfloat(-1)); assertEquals("(-1e20,-1)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(-1e20,-1)^-1/2, value", new Apcomplex(new Apfloat("5e-31", 30), new Apfloat("1e-10", 30)), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-40")); z = new Apcomplex(new Apfloat(0), new Apfloat("1e2000", 30)); assertEquals("(0,1e2000)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(0,1e2000)^-1/2, value", new Apcomplex("(0.707106781186547524400844362105e-1000, -0.707106781186547524400844362105e-1000)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-1030")); z = new Apcomplex(new Apfloat(1), new Apfloat("1e2000", 30)); assertEquals("(1,1e2000)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(1,1e2000)^-1/2, value", new Apcomplex("(0.707106781186547524400844362105e-1000, -0.707106781186547524400844362105e-1000)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-1030")); z = new Apcomplex(new Apfloat(0), new Apfloat("-1e2000", 30)); assertEquals("(0,-1e2000)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(0,-1e2000)^-1/2, value", new Apcomplex("(0.707106781186547524400844362105e-1000, 0.707106781186547524400844362105e-1000)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-1030")); z = new Apcomplex(new Apfloat(1), new Apfloat("-1e2000", 30)); assertEquals("(1,-1e2000)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(1,-1e2000)^-1/2, value", new Apcomplex("(0.707106781186547524400844362105e-1000, 0.707106781186547524400844362105e-1000)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-1030")); z = new Apcomplex(new Apfloat("1e2000", 30), new Apfloat(0)); assertEquals("(1e2000,0)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(1e2000,0)^-1/2, value", new Apcomplex("1e-1000"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-1030")); z = new Apcomplex(new Apfloat("1e2000", 30), new Apfloat(1)); assertEquals("(1e2000,1)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(1e2000,1)^-1/2, value", new Apcomplex("1e-1000"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-1030")); z = new Apcomplex(new Apfloat("-1e2000", 30), new Apfloat(0)); assertEquals("(-1e2000,0)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(-1e2000,0)^-1/2, value", new Apcomplex("(0, -1e-1000)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-1030")); z = new Apcomplex(new Apfloat("-1e2000", 30), new Apfloat(1)); assertEquals("(-1e2000,1)^-1/2, precision", 30, ApcomplexMath.inverseRoot(z, 2).precision()); assertEquals("(-1e2000,1)^-1/2, value", new Apcomplex("(0, -1e-1000)"), ApcomplexMath.inverseRoot(z, 2), new Apfloat("5e-1030")); z = new Apcomplex("(-0.707106781186547524400844362105e3000, 0.707106781186547524400844362105e3000)"); assertEquals("(-1e3000/sqrt(2),1e3000/sqrt(2))^-1/3, precision", 30, ApcomplexMath.inverseRoot(z, 3).precision()); assertEquals("(-1e3000/sqrt(2),1e3000/sqrt(2))^-1/3, value", new Apcomplex("(0.707106781186547524400844362105e-1000, -0.707106781186547524400844362105e-1000)"), ApcomplexMath.inverseRoot(z, 3), new Apfloat("5e-1030")); assertEquals("1", new Apfloat(1), ApcomplexMath.inverseRoot(Apcomplex.ONE, 5)); assertEquals("i^1/2", new Apcomplex("(0.70710678,0.70710678)"), ApcomplexMath.inverseRoot(new Apcomplex("(0,1.0000000)"), -2)); z = new Apcomplex(new Apfloat("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745530506820349625245174939965143142980919065925093722169646151570985838741059788595977297549893016175392846813826868386894277415599185592524595395943104997252468084598727364469584865383673622262609912460805124388439045124413654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767889525213852254995466672782398645659611635488623057745649803559363456817432411251507606947945109659609402522887971089314566913686722874894056010150330861792868092087476091782493858900971490967598526136554978189312978482168299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610213596953623144295248493718711014576540359027993440374200731057853906219838744780847848968332144571386875194350643021845319104848100537061468067491927819119793995206141966342875444064374512371819217999839101591956181467514269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672218256259966150142150306803844773454920260541466592520149744285073251866600213243408819071048633173464965145390579626856100550810665879699816357473638405257145910289706414011097120628043903975951567715770042033786993600723055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816909152801735067127485832228718352093539657251210835791513698820914442100675103346711031412671113699086585163983150197016515116851714376576183515565088490998985998238734552833163550764791853589322618548963213293308985706420467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325974636673058360414281388303203824903758985243744170291327656180937734440307074692112019130203303801976211011004492932151608424448596376698389522868478312355265821314495768572624334418930396864262434107732269780280731891544110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201855810072936065987648611791045334885034611365768675324944166803962657978771855608455296541266540853061434443185867697514566140680070023787765913440171274947042056223053899456131407112700040785473326993908145466464588079727082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923099079654737612551765675135751782966645477917450112996148903046399471329621073404375189573596145890193897131117904297828564750320319869151402870808599048010941214722131794764777262241425485454033215718530614228813758504306332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120918076383271664162748888007869256029022847210403172118608204190004229661711963779213375751149595015660496318629472654736425230817703675159067350235072835405670403867435136222247715891504953098444893330963408780769325993978054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229246543668009806769282382806899640048243540370141631496589794092432378969070697794223625082216889573837986230015937764716512289357860158816175578297352334460428151262720373431465319777741603199066554187639792933441952154134189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759882816133231666365286193266863360627356763035447762803504507772355471058595487027908143562401451718062464362679456127531813407833033625423278394497538243720583531147711992606381334677687969597030983391307710987040859133746414428227726346594704745878477872019277152807317679077071572134447306057007334924369311383504931631284042512192565179806941135280131470130478164378851852909285452011658393419656213491434159562586586557055269049652098580338507224264829397285847831630577775606888764462482468579260395352773480304802900587607582510474709164396136267604492562742042083208566119062545433721315359584506877246029016187667952406163425225771954291629919306455377991403734043287526288896399587947572917464263574552540790914513571113694109119393251910760208252026187985318877058429725916778131496990090192116971737278476847268608490033770242429165130050051683233643503895170298939223345172201381280696501178440874519601212285993716231301711444846409038906449544400619869075485160263275052983491874078668088183385102283345085048608250393021332197155184306354550076682829493041377655279397517546139539846833936383047461199665385815384205685338621867252334028308711232827892125077126294632295639898989358211674562701021835646220134967151881909730381198004973407239610368540664319395097901906996395524530054505806855019567302292191393391856803449039820595510022635353619204199474553859381023439554495977837790237421617271117236434354394782218185286240851400666044332588856986705431547069657474585503323233421073015459405165537906866273337995851156257843229882737231989875714159578111963583300594087306812160287649628674460477464915995054973742562690104903778198683593814657412680492564879855614537234786733039046883834363465537949864192705638729317487233208376011230299113679386270894387993620162951541337142489283072201269014754668476535761647737946752004907571555278196536213239264061601363581559074220202031872776052772190055614842555187925303435139844253223415762336106425063904975008656271095359194658975141310348227693062474353632569160781547818115284366795706110861533150445212747392454494542368288606134084148637767009612071512491404302725386076482363414334623518975766452164137679690314950191085759844239198629164219399490723623464684411739403265918404437805133389452574239950829659122850855582157250310712570126683024029295252201187267675622041542051618416348475651699981161410100299607838690929160302884002691041407928862150784245167090870006992821206604183718065355672525325675328612910424877618258297651579598470356222629348600341587229805349896502262917487882027342092222453398562647669149055628425039127577102840279980663658254889264880254566101729670266407655904290994568150652653053718294127033693137851786090407086671149655834343476933857817113864558736781230145876871266034891390956200993936103102916161528813843790990423174733639480457593149314052976347574811935670911013775172100803155902485309066920376719220332290943346768514221447737939375170344366199104033751117354719185504644902636551281622882446257591633303910722538374218214088350865739177150968288747826569959957449066175834413752239709683408005355984917541738188399944697486762655165827658483588453142775687900290951702835297163445621296404352311760066510124120065975585127617858382920419748442360800719304576189323492292796501987518721272675079812554709589045563579212210333466974992356302549478024901141952123828153091140790738602515227429958180724716259166854513331239480494707911915326734302824418604142636395480004480026704962482017928964766975831832713142517029692348896276684403232609275249603579964692565049368183609003238092934595889706953653494060340216654437558900456328822505452556405644824651518754711962184439658253375438856909411303150952617937800297412076651479394259029896959469955657612186561967337862362561252163208628692221032748892186543648022967807057656151446320469279068212073883778142335628236089632080682224680122482611771858963814091839036736722208883215137556003727983940041529700287830766709444745601345564172543709069793961225714298946715435784687886144458123145935719849225284716050492212424701412147805734551050080190869960330276347870810817545011930714122339086639383395294257869050764310063835198343893415961318543475464955697810382930971646514384070070736041123735998434522516105070270562352660127648483084076118301305279320542746286540360367453286510570658748822569815793678976697422057505968344086973502014102067235850200724522563265134105592401902742162484391403599895353945909440704691209140938700126456001623742880210927645793106579229552498872758461012648369998922569596881592056001016552563756785667227966198857827948488558343975187445455129656344348039664205579829368043522027709842942325330225763418070394769941597915945300697521482933665556615678736400536665641654732170439035213295435291694145990416087532018683793702348886894791510716378529023452924407736594956305100742108714261349745956151384987137570471017879573104229690666702144986374645952808243694457897723300487647652413390759204340196340391147320233807150952220106825634274716460243354400515212669324934196739770415956837535551667302739007497297363549645332888698440611964961627734495182736955882207573551766515898551909866653935494810688732068599075407923424023009259007017319603622547564789406475483466477604114632339056513433068449539790709030234604614709616968868850140834704054607429586991382966824681857103188790652870366508324319744047718556789348230894310682870272280973624809399627060747264553992539944280811373694338872940630792615959954626246297070625948455690347119729964090894180595343932512362355081349490043642785271383159125689892951964272875739469142725343669415323610045373048819855170659412173524625895487301676002988659257866285612496655235338294287854253404830833070165372285635591525347844598183134112900199920598135220511733658564078264849427644113763938669248031183644536985891754426473998822846218449008777697763127957226726555625962825427653183001340709223343657791601280931794017185985999338492354956400570995585611349802524990669842330173503580440811685526531170995708994273287092584878944364600504108922669178352587078595129834417295351953788553457374260859029081765155780390594640873506123226112009373108048548526357228257682034160504846627750450031262008007998049254853469414697751649327095049346393824322271885159740547021482897111777923761225788734771881968254629812686858170507402725502633290449762778944236216741191862694396506715157795867564823993917604260176338704549901761436412046921823707648878341968968611815581587360629386038101712158552726683008238340465647588040513808016336388742163714064354955618689641122821407533026551004241048967835285882902436709048871181909094945331442182876618103100735477054981596807720094746961343609286148494178501718077930681085469000944589952794243981392135055864221964834915126390128038320010977386806628779239718014613432445726400973742570073592100315415089367930081699805365202760072774967458400283624053460372634165542590276018348403068113818551059797056640075094260878857357960373245141467867036880988060971642584975951380693094494015154222219432913021739125383559150310033303251117491569691745027149433151558854039221640972291011290355218157628232831823425483261119128009282525619020526301639114772473314857391077758744253876117465786711694147764214411112635835538713610110232679877564102468240322648346417663698066378576813492045302240819727856471983963087815432211669122464159117767322532643356861461865452226812688726844596844241610785401676814208088502800541436131462308210259417375623899420757136275167457318918945628352570441335437585753426986994725470316566139919996826282472706413362221789239031760854289437339356188916512504244040089527198378738648058472689546243882343751788520143956005710481194988423906061369573423155907967034614914344788636041031823507365027785908975782727313050488939890099239135033732508559826558670892426124294736701939077271307068691709264625484232407485503660801360466895118400936686095463250021458529309500009071510582362672932645373821049387249966993394246855164832611341461106802674466373343753407642940266829738652209357016263846485285149036293201991996882851718395366913452224447080459239660281715655156566611135982311225062890585491450971575539002439315351909021071194573002438801766150352708626025378817975194780610137150044899172100222013350131060163915415895780371177927752259787428919179155224171895853616805947412341933984202187456492564434623925319531351033114763949119950728584306583619353693296992898379149419394060857248639688369032655643642166442576079147108699843157337496488352927693282207629472823815374099615455987982598910937171262182830258481123890119682214294576675807186538065064870261338928229949725745303328389638184394477077940228435988341003583854238973542439564755568409522484455413923941000162076936368467764130178196593799715574685419463348937484391297423914336593604100352343777065888677811394986164787471407932638587386247328896456435987746676384794665040741118256583788784548581489629612739984134427260860618724554523606431537101127468097787044640947582803487697589483282412392929605829486191966709189580898332012103184303401284951162035342801441276172858302435598300320420245120728725355811958401491809692533950757784000674655260314461670508276827722235341911026341631571474061238504258459884199076112872580591139356896014316682831763235673254170734208173322304629879928049085140947903688786878949305469557030726190095020764334933591060245450864536289354568629585313153371838682656178622736371697577418302398600659148161640494496501173213138957470620884748023653710311508984279927544268532779743113951435741722197597993596852522857452637962896126915723579866205734083757668738842664059909935050008133754324546359675048442352848747014435454195762584735642161981340734685411176688311865448937769795665172796623267148103386439137518659467300244345005449953997423723287124948347060440634716063258306498297955101095418362350303094530973358344628394763047756450150085075789495489313939448992161255255977014368589435858775263796255970816776438001254365023714127834679261019955852247172201777237004178084194239487254068015560359983905489857235467456423905858502167190313952629445543913166313453089390620467843877850542393905247313620129476918749751910114723152893267725339181466073000890277689631148109022097245207591672970078505807171863810549679731001678708506942070922329080703832634534520380278609905569001341371823683709919495164896007550493412678764367463849020639640197666855923356546391383631857456981471962108410809618846054560390384553437291414465134749407848844237721751543342603066988317683310011331086904219390310801437843341513709243530136776310849135161564226984750743032971674696406665315270353254671126675224605511995818319637637076179919192035795820075956053023462677579439363074630569010801149427141009391369138107258137813578940055995001835425118417213605572752210352680373572652792241737360575112788721819084490061780138897107708229310027976659358387589093956881485602632243937265624727760378908144588378550197028437793624078250527048758164703245812908783952324532378960298416692254896497156069811921865849267704039564812781021799132174163058105545988013004845629976511212415363745150056350701278159267142413421033015661653560247338078430286552572227530499988370153487930080626018096238151613669033411113865385109193673938352293458883225508870645075394739520439680790670868064450969865488016828743437861264538158342807530618454859037982179945996811544197425363443996029025100158882721647450068207041937615845471231834600726293395505482395571372568402322682130124767945226448209102356477527230820810635188991526928891084555711266039650343978962782500161101532351605196559042118449499077899920073294769058685778787209829013529566139788848605097860859570177312981553149516814671769597609942100361835591387778176984587581044662839988060061622984861693533738657877359833616133841338536842119789389001852956919678045544828584837011709672125353387586215823101331038776682721157269495181795897546939926421979155233857662316762754757035469941489290413018638611943919628388705436777432242768091323654494853667680000010652624854730558615989991401707698385483188750142938908995068545307651168033373222651756622075269517914422528081651716677667279303548515420402381746089232839170327542575086765511785939500279338959205766827896776445318404041855401043513483895312013263783692835808271937831265496174599705674507183320650345566440344904536275600112501843356073612227659492783937064784264567633881880756561216896050416113903906396016202215368494109260538768871483798955999911209916464644119185682770045742434340216722764455893301277815868695250694993646101756850601671453543158148010545886056455013320375864548584032402987170934809105562116715468484778039447569798042631809917564228098739987669732376957370158080682290459921236616890259627304306793165311494017647376938735140933618332161428021497633991898354848756252987524238730775595559554651963944018218409984124898262367377146722606163364329640633572810707887581640438148501884114318859882769449011932129682715888413386943468285900666408063140777577257056307294004929403024204984165654797367054855804458657202276378404668233798528271057843197535417950113472736257740802134768260450228515797957976474670228409995616015691089038458245026792659420555039587922981852648007068376504183656209455543461351341525700659748819163413595567196496540321872716026485930490397874895890661272507948282769389535217536218507962977851461884327192232238101587444505286652380225328438913752738458923844225354726530981715784478342158223270206902872323300538621634798850946954720047952311201504329322662827276321779088400878614802214753765781058197022263097174950721272484794781695729614236585957820908307332335603484653187302930266596450137183754288975579714499246540386817992138934692447419850973346267933210726868707680626399193619650440995421676278409146698569257150743157407938053239252394775574415918458215625181921552337096074833292349210345146264374498055961033079941453477845746999921285999993996122816152193148887693880222810830019860165494165426169685867883726095877456761825072759929508931805218729246108676399589161458550583972742098090978172932393010676638682404011130402470073508578287246271349463685318154696904669686939254725194139929146524238577625500474852954768147954670070503479995888676950161249722820403039954632788306959762493615101024365553522306906129493885990157346610237122354789112925476961760050479749280607212680392269110277722610254414922157650450812067717357120271802429681062037765788371669091094180744878140490755178203856539099104775941413215432844062503018027571696508209642734841469572639788425600845312140659358090412711359200419759851362547961606322887361813673732445060792441176399759746193835845749159880976674470930065463424234606342374746660804317012600520559284936959414340814685298150539471789004518357551541252235905906872648786357525419112888773717663748602766063496035367947026923229718683277173932361920077745221262475186983349515101986426988784717193966497690708252174233656627259284406204302141137199227852699846988477023238238400556555178890876613601304770984386116870523105531491625172837327286760072481729876375698163354150746088386636406934704372066886512756882661497307886570156850169186474885416791545965072342877306998537139043002665307839877638503238182155355973235306860430106757608389086270498418885951380910304235957824951439885901131858358406674723702971497850841458530857813391562707603563907639473114554958322669457024941398316343323789759556808568362972538679132750555425244919435891284050452269538121791319145135009938463117740179715122837854601160359554028644059024964669307077690554810288502080858008781157738171917417760173307385547580060560143377432990127286772530431825197579167929699650414607066457125888346979796429316229655201687973000356463045793088403274807718115553309098870255052076804630346086581653948769519600440848206596737947316808641564565053004988161649057883115434548505266006982309315777650037807046612647060214575057932709620478256152471459189652236083966456241051955105223572397395128818164059785914279148165426328920042816091369377737222999833270820829699557377273756676155271139225880552018988762011416800546873655806334716037342917039079863965229613128017826797172898229360702880690877686605932527463784053976918480820410219447197138692560841624511239806201131845412447820501107987607171556831540788654390412108730324020106853419472304766667217498698685470767812051247367924791931508564447753798537997322344561227858432968466475133365736923872014647236794278700425032555899268843495928761240075587569464137056251400117971331662071537154360068764773186755871487839890810742953094106059694431584775397009439883949144323536685392099468796450665339857388878661476294434140104988899316005120767810358861166020296119363968213496075011164983278563531614516845769568710900299976984126326650234771672865737857908574664607722834154031144152941880478254387617707904300015669867767957609099669360755949651527363498118964130433116627747123388174060373174397054067031096767657486953587896700319258662594105105335843846560233917967492678447637084749783336555790073841914731988627135259546251816043422537299628632674968240580602964211463864368642247248872834341704415734824818333016405669596688667695634914163284264149745333499994800026699875888159350735781519588990053951208535103572613736403436753471410483601754648830040784641674521673719048310967671134434948192626811107399482506073949507350316901973185211955263563258433909982249862406703107683184466072912487475403161796994113973877658998685541703188477886759290260700432126661791922352093822787888098863359911608192353555704646349113208591897961327913197564909760001399623444553501434642686046449586247690943470482932941404111465409239883444351591332010773944111840741076849810663472410482393582740194493566516108846312567852977697346843030614624180358529331597345830384554103370109167677637427621021370135485445092630719011473184857492331816720721372793556795284439254815609137281284063330393735624200160456645574145881660521666087387480472433912129558777639069690370788285277538940524607584962315743691711317613478388271941686066257210368513215664780014767523103935786068961112599602818393095487090590738613519145918195102973278755710497290114871718971800469616977700179139196137914171627070189584692143436967629274591099400600849835684252019155937037010110497473394938778859894174330317853487076032219829705797511914405109942358830345463534923498268836240433272674155403016195056806541809394099820206099941402168909007082133072308966211977553066591881411915778362729274615618571037217247100952142369648308641025928874579993223749551912219519034244523075351338068568073544649951272031744871954039761073080602699062580760202927314552520780799141842906388443734996814582733720726639176702011830046481900024130835088465841521489912761065137415394356572113903285749187690944137020905170314877734616528798482353382972601361109845148418238081205409961252745808810994869722161285248974255555160763716750548961730168096138038119143611439921063800508321409876045993093248510251682944672606661381517457125597549535802399831469822036133808284993567055755247129027453977621404931820146580080215665360677655087838043041343105918046068008345911366408348874080057412725867047922583191274157390809143831384564241509408491339180968402511639919368532255573389669537490266209232613188558915808324555719484538756287861288590041060060737465014026278240273469625282171749415823317492396835301361786536737606421667781377399510065895288774276626368418306801908046098498094697636673356622829151323527888061577682781595886691802389403330764419124034120223163685778603572769415417788264352381319050280870185750470463129333537572853866058889045831114507739429352019943219711716422350056440429798920815943071670198574692738486538334361457946341759225738985880016980147574205429958012429581054565108310462972829375841611625325625165724980784920998979906200359365099347215829651741357984910471116607915874369865412223483418877229294463351786538567319625598520260729476740726167671455736498121056777168934849176607717052771876011999081441130586455779105256843048114402619384023224709392498029335507318458903553971330884461741079591625117148648744686112476054286734367090466784686702740918810142497111496578177242793470702166882956108777944050484375284433751088282647719785400065097040330218625561473321177711744133502816088403517814525419643203095760186946490886815452856213469883554445602495566684366029221951248309106053772019802183101032704178386654471812603971906884623708575180800353270471856594994761242481109992886791589690495639476246084240659309486215076903149870206735338483495508363660178487710608098042692471324100094640143736032656451845667924566695510015022983307984960799498824970617236744936122622296179081431141466094123415935930958540791390872083227335495720807571651718765994498569379562387555161757543809178052802946420044721539628074636021132942559160025707356281263873310600589106524570802447493754318414940148211999627645310680066311838237616396631809314446712986155275982014514102756006892975024630401735148919457636078935285550531733141645705049964438909363084387448478396168405184527328840323452024705685164657164771393237755172947951261323982296023945485797545865174587877133181387529598094121742273003522965080891777050682592488223221549380483714547816472139768209633205083056479204820859204754998573203888763916019952409189389455767687497308569559580106595265030362661597506622250840674288982659075106375635699682115109496697445805472886936310203678232501823237084597901115484720876182124778132663304120762165873129708112307581598212486398072124078688781145016558251361789030708608701989758898074566439551574153631931919810705753366337380382721527988493503974800158905194208797113080512339332219034662499171691509485414018710603546037946433790058909577211808044657439628061867178610171567409676620802957665770512912099079443046328929473061595104309022214393718495606340561893425130572682914657832933405246350289291754708725648426003496296116541382300773133272983050016025672401418515204189070115428857992081219844931569990591820118197335001261877280368124819958770702075324063612593134385955425477819611429351635612234966615226147353996740515849986035529533292457523888101362023476246690558164389678630976273655047243486430712184943734853006063876445662721866617012381277156213797461498613287441177145524447089971445228856629424402301847912054784985745216346964489738920624019435183100882834802492490854030778638751659113028739587870981007727182718745290139728366148421428717055317965430765045343246005363614726181809699769334862640774351999286863238350887566835950972655748154319401955768504372480010204137498318722596773871549583997184449072791419658459300839426370208756353982169620553248032122674989114026785285996734052420310917978999057188219493913207534317079800237365909853755202389116434671855829068537118979526262344924833924963424497146568465912489185566295893299090352392333336474352037077010108438800329075983421701855422838616172104176030116459187805393674474720599850235828918336929223373239994804371084196594731626548257480994825099918330069765693671596893644933488647442135008407006608835972350395323401795825570360169369909886711321097988970705172807558551912699306730992507040702455685077867906947661262980822516331363995211709845280926303759224267425755998928927837047444521893632034894155210445972618838003006776179313813991620580627016510244588692476492468919246121253102757313908404700071435613623169923716948481325542009145304103713545329662063921054798243921251725401323149027405858920632175894943454890684639931375709103463327141531622328055229729795380188016285907357295541627886764982741861642187898857410716490691918511628152854867941736389066538857642291583425006736124538491606741373401735727799563410433268835695078149313780073623541800706191802673285511919426760912210359874692411728374931261633950012395992405084543756985079570462226646190001035004901830341535458428337643781119885563187777925372011667185395418359844383052037628194407615941068207169703022851522505731260930468984234331527321313612165828080752126315477306044237747535059522871744026663891488171730864361113890694202790881431194487994171540421034121908470940802540239329429454938786402305129271190975135360009219711054120966831115163287054230284700731206580326264171161659576132723515666625366727189985341998952368848309993027574199164638414270779887088742292770538912271724863220288984251252872178260305009945108247835729056919885554678860794628053712270424665431921452817607414824038278358297193010178883456741678113989547504483393146896307633966572267270433932167454218245570625247972199786685427989779923395790575818906225254735822052364248507834071101449804787266919901864388229323053823185597328697809222535295910173414073348847610055640182423921926950620831838145469839236646136398910121021770959767049083050818547041946643713122996923588953849301363565761861060622287055994233716310212784574464639897381885667462608794820186474876727272220626764653380998019668836809941590757768526398651462533363124505364026105696055131838131742611844201890888531963569869627950367384243130113317533053298020166888174813429886815855778103432317530647849832106297184251843855344276201282345707169885305183261796411785796088881503296022907056144762209150947390359466469162353968092013945781758910889319921122600739281491694816152738427362642980982340632002440244958944561291670495082358124873917996486411334803247577752197089327722623494860150466526814398770516153170266969297049283162855042128981467061953319702695072143782304768752802873541261663917082459251700107141808548006369232594620190022780874098597719218051585321473926532515590354102092846659252999143537918253145452905984158176370589279069098969111643811878094353715213322614436253144901274547726957393934815469163116249288735747188240715039950094467319543161938554852076657388251396391635767231510055560372633948672082078086537349424401157996675073607111593513319591971209489647175530245313647709420946356969822266737752099451684506436238242118535348879893956731878066061078854400055082765703055874485418057788917192078814233511386629296671796434687600770479995378833878703487180218424373421122739402557176908196030920182401884270570460926225641783752652633583242406612533115294234579655695025068100183109004112453790153329661569705223792103257069370510908307894799990049993953221536227484766036136776979785673865846709366795885837887956259464648913766521995882869338018360119323685785585581955560421562508836502033220245137621582046181067051953306530606065010548871672453779428313388716313955969058320834168984760656071183471362181232462272588419902861420872849568796393254642853430753011052857138296437099903569488852851904029560473461311382638788975517885604249987483163828040468486189381895905420398898726506976202019955484126500053944282039301274816381585303964399254702016727593285743666616441109625663373054092195196751483287348089574777752783442210910731113518280460363471981856555729571447476825528578633493428584231187494400032296906977583159038580393535213588600796003420975473922967333106493956018122378128545843176055617338611267347807458506760630482294096530411183066710818930311088717281675195796753471885372293096161432040063813224658411111577583585811350185690478153689381377184728147519983505047812977185990847076219746058874232569958288925350419379582606162118423687685114183160683158679946016520577405294230536017803133572632670547903384012573059123396018801378254219270947673371919872873852480574212489211834708766296672072723256505651293331260595057777275424712416483128329820723617505746738701282095755443059683955556868611883971355220844528526400812520276655576774959696266126045652456840861392382657685833846984997787267065551918544686984694784957346226062942196245570853712727765230989554501930377321666491825781546772920052126671434632096378918523232150189761260343736840671941930377468809992968775824410478781232662531818459604538535438391144967753128642609252115376732588667226040425234910870269580996475958057946639734190640100363619040420331135793365424263035614570090112448008900208014780566037101541223288914657223931450760716706435568274377439657890679726874384730763464516775621030986040927170909512808630902973850445271828927496892121066700816485833955377359191369501531620189088874842107987068991148046692706509407620465027725286507289053285485614331608126930056937854178610969692025388650345771831766868859236814884752764984688219497397297077371871884004143231276365048145311228509900207424092558592529261030210673681543470152523487863516439762358604191941296976904052648323470099111542426012734380220893310966863678986949779940012601642276092608234930411806438291383473546797253992623387915829984864592717340592256207491053085315371829116816372193951887009577881815868504645076993439409874335144316263303172477474868979182092394808331439708406730840795893581089665647758599055637695252326536144247802308268118310377358870892406130313364773710116282146146616794040905186152603600925219472188909181073358719641421444786548995285823439470500798303885388608310357193060027711945580219119428999227223534587075662469261776631788551443502182870266856106650035310502163182060176092179846849368631612937279518730789726373537171502563787335797718081848784588665043358243770041477104149349274384575871071597315594394264125702709651251081155482479394035976811881172824721582501094960966253933953809221955919181885526780621499231727631632183398969380756168559117529984501320671293924041445938623988093812404521914848316462101473891825101090967738690664041589736104764365000680771056567184862814963711188321924456639458144914861655004956769826903089111856879869294705135248160917432430153836847072928989828460222373014526556798986277679680914697983782687643115988321090437156112997665215396354644208691975673700057387649784376862876817924974694384274652563163230055513041742273416464551278127845777724575203865437542828256714128858345444351325620544642410110379554641905811686230596447695870540721419852121067343324107567675758184569906930460475227701670056845439692340417110898889934163505851578873534308155208117720718803791040469830695786854739376564336319797868036718730796939242363214484503547763156702553900654231179201534649779290662415083288583952905426376876689688050333172278001858850697362324038947004718976193473443084374437599250341788079722358591342458131440498477017323616947197657153531977549971627856631190469126091825912498903676541769799036237552865263757337635269693443544004730671988689019681474287677908669796885225016369498567302175231325292653758964151714795595387842784998664563028788319620998304945198743963690706827626574858104391122326187940599415540632701319898957037611053236062986748037791537675115830432084987209202809297526498125691634250005229088726469252846661046653921714820801305022980526378364269597337070539227891535105688839381132497570713310295044303467159894487868471164383280506925077662745001220035262037094660234146489983902525888301486781621967751945831677187627572005054397944124599007711520515461993050983869825428464072555409274031325716326407929341833421470904125425335232480219322770753555467958716383587501815933871742360615511710131235256334858203651461418700492057043720182617331947157008675785393360786227395581857975872587441025420771054753612940474601000940954449596628814869159038990718659805636171376922272907641977551777201042764969496110562205925024202177042696221549587264539892276976603105249808557594716310758701332088614632664125911486338812202844406941694882615295776253250198703598706743804698219420563812558334364219492322759372212890564209430823525440841108645453694049692714940033197828613181861888111184082578659287574263844500599442295685864604810330153889114994869354360302218109434667640000223625505736312946262960961987605642599639461386923308371962659547392346241345977957485246478379807956931986508159776753505539189911513352522987361127791827485420086895396583594219633315028695611920122988898870060799927954111882690230789131076036176347794894320321027733594169086500719328040171638406449878717537567811853213284082165711075495282949749362146082155832056872321855740651610962748743750980922302116099826330339154694946444910045152809250897450748967603240907689836529406579201983152654106581368237919840906457124689484702093577611931399802468134052003947819498662026240089021501661638135383815150377350229660746279529103840686855690701575166241929872444827194293310048548244545807188976330032325258215812803274679620028147624318286221710543528983482082734516801861317195933247110746622285087106661177034653528395776259977446721857158161264111432717943478859908928084866949141390977167369002777585026866465405659503948678411107901161040085727445629384254941675946054871172359464291058509099502149587931121961359083158826206823321561530868337308381732793281969838750870834838804638847844188400318471269745437093732983624028751979208023218787448828728437273780178270080587824107493575148899789117397461293203510814327032514090304874622629423443275712600866425083331876886507564292716055252895449215376517514921963671810494353178583834538652556566406572513635750643532365089367904317025978781771903148679638408288102094614900797151377170990619549696400708676671023300486726314755105372317571143223174114116806228642063889062101923552235467116621374996932693217370431059872250394565749246169782609702533594750209138366737728944386964000281103440260847128990007468077648440887113413525033678773167977093727786821661178653442317322646378476978751443320953400016506921305464768909850502030150448808342618452087305309731894929164253229336124315143065782640702838984098416029503092418971209716016492656134134334222988279099217860426798124572853458013382609958771781131021673402565627440072968340661984806766158050216918337236803990279316064204368120799003162644491461902194582296909921227885539487835383056468648816555622943156731282743908264506116289428035016613366978240517701552196265227254558507386405852998303791803504328767038092521679075712040612375963276856748450791511473134400018325703449209097124358094479004624943134550289006806487042935340374360326258205357901183956490893543451013429696175452495739606214902887289327925206965353863964432253883275224996059869747598823299162635459733244451637553343774929289905811757863555556269374269109471170021654117182197505198317871371060510637955585889055688528879890847509157646390746936198815078146852621332524738376511929901561091897779220087057933964638274906806987691681974923656242260871541761004306089043779766785196618914041449252704808819714988015420577870065215940092897776013307568479669929554336561398477380603943688958876460549838714789684828053847017308711177611596635050399793438693391197898871091565417091330826076474063057114110988393880954814378284745288383680794188843426662220704387228874139478010177213922819119923654055163958934742639538248296090369002883593277458550608013179884071624465639979482757836501955142215513392819782269842786383916797150912624105487257009240700454884856929504481107380879965474815689139353809434745569721289198271770207666136024895814681191336141212587838955773571949863172108443989014239484966592517313881716026632619310653665350414730708044149391693632623737677770958503132559900957627319573086480424677012123270205337426670531424482081681303063973787366424836725398374876909806021827857862165127385635132901489035098832706172589325753639939790557291751600976154590447716922658063151110280384360173747421524760851520990161585823125715907334217365762671423904782795872815050956330928026684589376496497702329736413190609827406335310897924642421345837409011693919642504591288134034988106354008875968200544083643865166178805576089568967275315380819420773325979172784376256611843198910250074918290864751497940031607038455494653859460274524474668123146879434416109933389089926384118474252570445725174593257389895651857165759614812660203107976282541655905060424791140169579003383565748692528007430256234194982864679144763227740055294609039401775363356554719310001754300475047191448998410400158679461792416100164547165513370740739502604427695385538343975505488710997852054011751697475813449260794336895437832211724506873442319898788441285420647428097356258070669831069799352606933921356858813912148073547284632277849080870024677763036055512323866562951788537196730346347012229395816067925091532174890308408865160611190114984434123501246469280288059961342835118847154497712784733617662850621697787177438243625657117794500644777183702219991066950216567576440449979407650379999548450027106659878136038023141268369057831904607927652972776940436130230517870805465115424693952651271010529270703066730244471259739399505146284047674313637399782591845411764133279064606365841529270190302760173394748669603486949765417524293060407270050590395031485229213925755948450788679779252539317651564161971684435243697944473559642606333910551268260615957262170366985064732812667245219890605498802807828814297963366967441248059821921463395657457221022986775997467381260693670691340815594120161159601902377535255563006062479832612498812881929373434768626892192397778339107331065882568137771723283153290825250927330478507249771394483338925520811756084529665905539409655685417060011798572938139982583192936791003918440992865756059935989100029698644609747147184701015312837626311467742091455740418159088000649432378558393085308283054760767995243573916312218860575496738322431956506554608528812019023636447127037486344217272578795034284863129449163184753475314350413920961087960577309872013524840750576371992536504709085825139368634638633680428917671076021111598288755399401200760139470336617937153963061398636554922137415979051190835882900976566473007338793146789131814651093167615758213514248604422924453041131606527009743300884990346754055186406773426035834096086055337473627609356588531097609942383473822220872924644976845605795625167655740884103217313456277358560523582363895320385340248422733716391239732159954408284216666360232965456947035771848734420342277066538373875061692127680157661810954200977083636043611105924091178895403380214265239489296864398089261146354145715351943428507213534530183158756282757338982688985235577992957276452293915674775666760510878876484534936360682780505646228135988858792599409464460417052044700463151379754317371877560398159626475014109066588661621800382669899619655805872086397211769952194667898570117983324406018115756580742841829106151939176300591943144346051540477105700543390001824531177337189558576036071828605063564799790041397618089553636696031621931132502238517916720551806592635180362512145759262383693482226658955769946604919381124866090997981285718234940066155521961122072030922776462009993152442735894887105766238946938894464950939603304543408421024624010487233287500817491798755438793873814398942380117627008371960530943839400637561164585609431295175977139353960743227924892212670458081833137641658182695621058728924477400359470092686626596514220506300785920024882918608397437323538490839643261470005324235406470420894992102504047267810590836440074663800208701266642094571817029467522785400745085523777208905816839184465928294170182882330149715542352359117748186285929676050482038643431087795628929254056389466219482687110428281638939757117577869154301650586029652174595819888786804081103284327398671986213062055598552660364050462821523061545944744899088390819997387474529698107762014871340001225355222466954093152131153379157980269795557105085074738747507580687653764457825244326380461430428892359348529610582693821034980004052484070844035611678171705128133788057056434506161193304244407982603779511985486945591520519600930412710072778493015550388953603382619293437970818743209499141595933963681106275572952780042548630600545238391510689989135788200194117865356821491185282078521301255185184937115034221595422445119002073935396274002081104655302079328672547405436527175958935007163360763216147258154076420530200453401835723382926619153083540951202263291650544261236191970516138393573266937601569144299449437448568097756963031295887191611292946818849363386473927476012269641588489009657170861605981472044674286642087653347998582220906198021732116142304194777549907387385679411898246609130916917722742072333676350326783405863019301932429963972044451792881228544782119535308989101253429755247276357302262813820918074397486714535907786335301608215599113141442050914472935350222308171936635093468658586563148555758624478186201087118897606529698992693281787055764351433820601410773292610634315253371822433852635202177354407152818981376987551575745469397271504884697936195004777209705617939138289898453274262272886471088832701737232588182446584362495805925603381052156062061557132991560848920643403033952622634514542836786982880742514225674518061841495646861116354049718976821542277224794740335715274368194098920501136534001238467142965518673441537416150425632567134302476551252192180357801692403266995417460875924092070046693403965101781348578356944407604702325407555577647284507518268904182939661133101601311190773986324627782190236506603740416067249624901374332172464540974129955705291424382080760983648234659738866913499197840131080155813439791948528304367390124820824448141280954437738983200598649091595053228579145768849625786658859991798675205545580990045564611787552493701245532171701942828846174027366499784755082942280202329012216301023097721515694464279098021908266898688342630716092079140851976952355534886577434252775311972474308730436195113961190800302558783876442060850447306312992778889427291897271698905759252446796601897074829609491906487646937027507738664323919190422542902353189233772931667360869962280325571853089192844038050710300647768478632431910002239297852553723755662136447400967605394398382357646069924652600890906241059042154539279044115295803453345002562441010063595300395988644661695956263518780606885137234627079973272331346939714562855426154676506324656766202792452085813477176085216913409465203076733918411475041401689241213198268815686645614853802875393311602322925556189410429953356400957864953409351152664540244187759493169305604486864208627572011723195264050230997745676478384889734643172159806267876718380052476968840849891850861490034324034767426862459523958903585821350064509981782446360873177543788596776729195261112138591947254514003011805034378752776644027626189410175768726804281766238606804778852428874302591452470739505465251353394595987896197789110418902929438185672050709646062635417329446495766126519534957018600154126239622864138977967333290705673769621564981845068422636903678495559700260798679962610190393312637685569687670292953711625280055431007864087289392257145124811357786276649024251619902774710903359333093049483805978566288447874414698414990671237647895822632949046798120899848571635710878311918486302545016209298058292083348136384054217200561219893536693713367333924644161252231969434712064173754912163570085736943973059797097197266666422674311177621764030686813103518991122713397240368870009968629225464650063852886203938005047782769128356033725482557939129852515068299691077542576474883253414121328006267170940090982235296579579978030182824284902214707481111240186076134151503875698309186527806588966823625239378452726345304204188025084423631903833183845505223679923577529291069250432614469501098610888999146585518818735825281643025209392852580779697376208456374821144339881627100317031513344023095263519295886806908213558536801610002137408511544849126858412686958991741491338205784928006982551957402018181056412972508360703568510553317878408290000415525118657794539633175385320921497205266078312602819611648580986845875251299974040927976831766399146553861089375879522149717317281315179329044311218158710235187407572221001237687219447472093493123241070650806185623725267325407333248757544829675734500193219021991199607979893733836732425761039389853492787774739805080800155447640610535222023254094435677187945654304067358964910176107759483645408234861302547184764851895758366743997915085128580206078205544629917232020282229148869593997299742974711553718589242384938558585954074381048826246487880533042714630119415898963287926783273224561038521970111304665871005000832851773117764897352309266612345888731028835156264460236719966445547276083101187883891511493409393447500730258558147561908813987523578123313422798665035227253671712307568610450045489703600795698276263923441071465848957802414081584052295369374997106655948944592462866199635563506526234053394391421112718106910522900246574236041"), new Apfloat("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745530506820349625245174939965143142980919065925093722169646151570985838741059788595977297549893016175392846813826868386894277415599185592524595395943104997252468084598727364469584865383673622262609912460805124388439045124413654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767889525213852254995466672782398645659611635488623057745649803559363456817432411251507606947945109659609402522887971089314566913686722874894056010150330861792868092087476091782493858900971490967598526136554978189312978482168299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610213596953623144295248493718711014576540359027993440374200731057853906219838744780847848968332144571386875194350643021845319104848100537061468067491927819119793995206141966342875444064374512371819217999839101591956181467514269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672218256259966150142150306803844773454920260541466592520149744285073251866600213243408819071048633173464965145390579626856100550810665879699816357473638405257145910289706414011097120628043903975951567715770042033786993600723055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816909152801735067127485832228718352093539657251210835791513698820914442100675103346711031412671113699086585163983150197016515116851714376576183515565088490998985998238734552833163550764791853589322618548963213293308985706420467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325974636673058360414281388303203824903758985243744170291327656180937734440307074692112019130203303801976211011004492932151608424448596376698389522868478312355265821314495768572624334418930396864262434107732269780280731891544110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201855810072936065987648611791045334885034611365768675324944166803962657978771855608455296541266540853061434443185867697514566140680070023787765913440171274947042056223053899456131407112700040785473326993908145466464588079727082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923099079654737612551765675135751782966645477917450112996148903046399471329621073404375189573596145890193897131117904297828564750320319869151402870808599048010941214722131794764777262241425485454033215718530614228813758504306332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120918076383271664162748888007869256029022847210403172118608204190004229661711963779213375751149595015660496318629472654736425230817703675159067350235072835405670403867435136222247715891504953098444893330963408780769325993978054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229246543668009806769282382806899640048243540370141631496589794092432378969070697794223625082216889573837986230015937764716512289357860158816175578297352334460428151262720373431465319777741603199066554187639792933441952154134189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759882816133231666365286193266863360627356763035447762803504507772355471058595487027908143562401451718062464362679456127531813407833033625423278394497538243720583531147711992606381334677687969597030983391307710987040859133746414428227726346594704745878477872019277152807317679077071572134447306057007334924369311383504931631284042512192565179806941135280131470130478164378851852909285452011658393419656213491434159562586586557055269049652098580338507224264829397285847831630577775606888764462482468579260395352773480304802900587607582510474709164396136267604492562742042083208566119062545433721315359584506877246029016187667952406163425225771954291629919306455377991403734043287526288896399587947572917464263574552540790914513571113694109119393251910760208252026187985318877058429725916778131496990090192116971737278476847268608490033770242429165130050051683233643503895170298939223345172201381280696501178440874519601212285993716231301711444846409038906449544400619869075485160263275052983491874078668088183385102283345085048608250393021332197155184306354550076682829493041377655279397517546139539846833936383047461199665385815384205685338621867252334028308711232827892125077126294632295639898989358211674562701021835646220134967151881909730381198004973407239610368540664319395097901906996395524530054505806855019567302292191393391856803449039820595510022635353619204199474553859381023439554495977837790237421617271117236434354394782218185286240851400666044332588856986705431547069657474585503323233421073015459405165537906866273337995851156257843229882737231989875714159578111963583300594087306812160287649628674460477464915995054973742562690104903778198683593814657412680492564879855614537234786733039046883834363465537949864192705638729317487233208376011230299113679386270894387993620162951541337142489283072201269014754668476535761647737946752004907571555278196536213239264061601363581559074220202031872776052772190055614842555187925303435139844253223415762336106425063904975008656271095359194658975141310348227693062474353632569160781547818115284366795706110861533150445212747392454494542368288606134084148637767009612071512491404302725386076482363414334623518975766452164137679690314950191085759844239198629164219399490723623464684411739403265918404437805133389452574239950829659122850855582157250310712570126683024029295252201187267675622041542051618416348475651699981161410100299607838690929160302884002691041407928862150784245167090870006992821206604183718065355672525325675328612910424877618258297651579598470356222629348600341587229805349896502262917487882027342092222453398562647669149055628425039127577102840279980663658254889264880254566101729670266407655904290994568150652653053718294127033693137851786090407086671149655834343476933857817113864558736781230145876871266034891390956200993936103102916161528813843790990423174733639480457593149314052976347574811935670911013775172100803155902485309066920376719220332290943346768514221447737939375170344366199104033751117354719185504644902636551281622882446257591633303910722538374218214088350865739177150968288747826569959957449066175834413752239709683408005355984917541738188399944697486762655165827658483588453142775687900290951702835297163445621296404352311760066510124120065975585127617858382920419748442360800719304576189323492292796501987518721272675079812554709589045563579212210333466974992356302549478024901141952123828153091140790738602515227429958180724716259166854513331239480494707911915326734302824418604142636395480004480026704962482017928964766975831832713142517029692348896276684403232609275249603579964692565049368183609003238092934595889706953653494060340216654437558900456328822505452556405644824651518754711962184439658253375438856909411303150952617937800297412076651479394259029896959469955657612186561967337862362561252163208628692221032748892186543648022967807057656151446320469279068212073883778142335628236089632080682224680122482611771858963814091839036736722208883215137556003727983940041529700287830766709444745601345564172543709069793961225714298946715435784687886144458123145935719849225284716050492212424701412147805734551050080190869960330276347870810817545011930714122339086639383395294257869050764310063835198343893415961318543475464955697810382930971646514384070070736041123735998434522516105070270562352660127648483084076118301305279320542746286540360367453286510570658748822569815793678976697422057505968344086973502014102067235850200724522563265134105592401902742162484391403599895353945909440704691209140938700126456001623742880210927645793106579229552498872758461012648369998922569596881592056001016552563756785667227966198857827948488558343975187445455129656344348039664205579829368043522027709842942325330225763418070394769941597915945300697521482933665556615678736400536665641654732170439035213295435291694145990416087532018683793702348886894791510716378529023452924407736594956305100742108714261349745956151384987137570471017879573104229690666702144986374645952808243694457897723300487647652413390759204340196340391147320233807150952220106825634274716460243354400515212669324934196739770415956837535551667302739007497297363549645332888698440611964961627734495182736955882207573551766515898551909866653935494810688732068599075407923424023009259007017319603622547564789406475483466477604114632339056513433068449539790709030234604614709616968868850140834704054607429586991382966824681857103188790652870366508324319744047718556789348230894310682870272280973624809399627060747264553992539944280811373694338872940630792615959954626246297070625948455690347119729964090894180595343932512362355081349490043642785271383159125689892951964272875739469142725343669415323610045373048819855170659412173524625895487301676002988659257866285612496655235338294287854253404830833070165372285635591525347844598183134112900199920598135220511733658564078264849427644113763938669248031183644536985891754426473998822846218449008777697763127957226726555625962825427653183001340709223343657791601280931794017185985999338492354956400570995585611349802524990669842330173503580440811685526531170995708994273287092584878944364600504108922669178352587078595129834417295351953788553457374260859029081765155780390594640873506123226112009373108048548526357228257682034160504846627750450031262008007998049254853469414697751649327095049346393824322271885159740547021482897111777923761225788734771881968254629812686858170507402725502633290449762778944236216741191862694396506715157795867564823993917604260176338704549901761436412046921823707648878341968968611815581587360629386038101712158552726683008238340465647588040513808016336388742163714064354955618689641122821407533026551004241048967835285882902436709048871181909094945331442182876618103100735477054981596807720094746961343609286148494178501718077930681085469000944589952794243981392135055864221964834915126390128038320010977386806628779239718014613432445726400973742570073592100315415089367930081699805365202760072774967458400283624053460372634165542590276018348403068113818551059797056640075094260878857357960373245141467867036880988060971642584975951380693094494015154222219432913021739125383559150310033303251117491569691745027149433151558854039221640972291011290355218157628232831823425483261119128009282525619020526301639114772473314857391077758744253876117465786711694147764214411112635835538713610110232679877564102468240322648346417663698066378576813492045302240819727856471983963087815432211669122464159117767322532643356861461865452226812688726844596844241610785401676814208088502800541436131462308210259417375623899420757136275167457318918945628352570441335437585753426986994725470316566139919996826282472706413362221789239031760854289437339356188916512504244040089527198378738648058472689546243882343751788520143956005710481194988423906061369573423155907967034614914344788636041031823507365027785908975782727313050488939890099239135033732508559826558670892426124294736701939077271307068691709264625484232407485503660801360466895118400936686095463250021458529309500009071510582362672932645373821049387249966993394246855164832611341461106802674466373343753407642940266829738652209357016263846485285149036293201991996882851718395366913452224447080459239660281715655156566611135982311225062890585491450971575539002439315351909021071194573002438801766150352708626025378817975194780610137150044899172100222013350131060163915415895780371177927752259787428919179155224171895853616805947412341933984202187456492564434623925319531351033114763949119950728584306583619353693296992898379149419394060857248639688369032655643642166442576079147108699843157337496488352927693282207629472823815374099615455987982598910937171262182830258481123890119682214294576675807186538065064870261338928229949725745303328389638184394477077940228435988341003583854238973542439564755568409522484455413923941000162076936368467764130178196593799715574685419463348937484391297423914336593604100352343777065888677811394986164787471407932638587386247328896456435987746676384794665040741118256583788784548581489629612739984134427260860618724554523606431537101127468097787044640947582803487697589483282412392929605829486191966709189580898332012103184303401284951162035342801441276172858302435598300320420245120728725355811958401491809692533950757784000674655260314461670508276827722235341911026341631571474061238504258459884199076112872580591139356896014316682831763235673254170734208173322304629879928049085140947903688786878949305469557030726190095020764334933591060245450864536289354568629585313153371838682656178622736371697577418302398600659148161640494496501173213138957470620884748023653710311508984279927544268532779743113951435741722197597993596852522857452637962896126915723579866205734083757668738842664059909935050008133754324546359675048442352848747014435454195762584735642161981340734685411176688311865448937769795665172796623267148103386439137518659467300244345005449953997423723287124948347060440634716063258306498297955101095418362350303094530973358344628394763047756450150085075789495489313939448992161255255977014368589435858775263796255970816776438001254365023714127834679261019955852247172201777237004178084194239487254068015560359983905489857235467456423905858502167190313952629445543913166313453089390620467843877850542393905247313620129476918749751910114723152893267725339181466073000890277689631148109022097245207591672970078505807171863810549679731001678708506942070922329080703832634534520380278609905569001341371823683709919495164896007550493412678764367463849020639640197666855923356546391383631857456981471962108410809618846054560390384553437291414465134749407848844237721751543342603066988317683310011331086904219390310801437843341513709243530136776310849135161564226984750743032971674696406665315270353254671126675224605511995818319637637076179919192035795820075956053023462677579439363074630569010801149427141009391369138107258137813578940055995001835425118417213605572752210352680373572652792241737360575112788721819084490061780138897107708229310027976659358387589093956881485602632243937265624727760378908144588378550197028437793624078250527048758164703245812908783952324532378960298416692254896497156069811921865849267704039564812781021799132174163058105545988013004845629976511212415363745150056350701278159267142413421033015661653560247338078430286552572227530499988370153487930080626018096238151613669033411113865385109193673938352293458883225508870645075394739520439680790670868064450969865488016828743437861264538158342807530618454859037982179945996811544197425363443996029025100158882721647450068207041937615845471231834600726293395505482395571372568402322682130124767945226448209102356477527230820810635188991526928891084555711266039650343978962782500161101532351605196559042118449499077899920073294769058685778787209829013529566139788848605097860859570177312981553149516814671769597609942100361835591387778176984587581044662839988060061622984861693533738657877359833616133841338536842119789389001852956919678045544828584837011709672125353387586215823101331038776682721157269495181795897546939926421979155233857662316762754757035469941489290413018638611943919628388705436777432242768091323654494853667680000010652624854730558615989991401707698385483188750142938908995068545307651168033373222651756622075269517914422528081651716677667279303548515420402381746089232839170327542575086765511785939500279338959205766827896776445318404041855401043513483895312013263783692835808271937831265496174599705674507183320650345566440344904536275600112501843356073612227659492783937064784264567633881880756561216896050416113903906396016202215368494109260538768871483798955999911209916464644119185682770045742434340216722764455893301277815868695250694993646101756850601671453543158148010545886056455013320375864548584032402987170934809105562116715468484778039447569798042631809917564228098739987669732376957370158080682290459921236616890259627304306793165311494017647376938735140933618332161428021497633991898354848756252987524238730775595559554651963944018218409984124898262367377146722606163364329640633572810707887581640438148501884114318859882769449011932129682715888413386943468285900666408063140777577257056307294004929403024204984165654797367054855804458657202276378404668233798528271057843197535417950113472736257740802134768260450228515797957976474670228409995616015691089038458245026792659420555039587922981852648007068376504183656209455543461351341525700659748819163413595567196496540321872716026485930490397874895890661272507948282769389535217536218507962977851461884327192232238101587444505286652380225328438913752738458923844225354726530981715784478342158223270206902872323300538621634798850946954720047952311201504329322662827276321779088400878614802214753765781058197022263097174950721272484794781695729614236585957820908307332335603484653187302930266596450137183754288975579714499246540386817992138934692447419850973346267933210726868707680626399193619650440995421676278409146698569257150743157407938053239252394775574415918458215625181921552337096074833292349210345146264374498055961033079941453477845746999921285999993996122816152193148887693880222810830019860165494165426169685867883726095877456761825072759929508931805218729246108676399589161458550583972742098090978172932393010676638682404011130402470073508578287246271349463685318154696904669686939254725194139929146524238577625500474852954768147954670070503479995888676950161249722820403039954632788306959762493615101024365553522306906129493885990157346610237122354789112925476961760050479749280607212680392269110277722610254414922157650450812067717357120271802429681062037765788371669091094180744878140490755178203856539099104775941413215432844062503018027571696508209642734841469572639788425600845312140659358090412711359200419759851362547961606322887361813673732445060792441176399759746193835845749159880976674470930065463424234606342374746660804317012600520559284936959414340814685298150539471789004518357551541252235905906872648786357525419112888773717663748602766063496035367947026923229718683277173932361920077745221262475186983349515101986426988784717193966497690708252174233656627259284406204302141137199227852699846988477023238238400556555178890876613601304770984386116870523105531491625172837327286760072481729876375698163354150746088386636406934704372066886512756882661497307886570156850169186474885416791545965072342877306998537139043002665307839877638503238182155355973235306860430106757608389086270498418885951380910304235957824951439885901131858358406674723702971497850841458530857813391562707603563907639473114554958322669457024941398316343323789759556808568362972538679132750555425244919435891284050452269538121791319145135009938463117740179715122837854601160359554028644059024964669307077690554810288502080858008781157738171917417760173307385547580060560143377432990127286772530431825197579167929699650414607066457125888346979796429316229655201687973000356463045793088403274807718115553309098870255052076804630346086581653948769519600440848206596737947316808641564565053004988161649057883115434548505266006982309315777650037807046612647060214575057932709620478256152471459189652236083966456241051955105223572397395128818164059785914279148165426328920042816091369377737222999833270820829699557377273756676155271139225880552018988762011416800546873655806334716037342917039079863965229613128017826797172898229360702880690877686605932527463784053976918480820410219447197138692560841624511239806201131845412447820501107987607171556831540788654390412108730324020106853419472304766667217498698685470767812051247367924791931508564447753798537997322344561227858432968466475133365736923872014647236794278700425032555899268843495928761240075587569464137056251400117971331662071537154360068764773186755871487839890810742953094106059694431584775397009439883949144323536685392099468796450665339857388878661476294434140104988899316005120767810358861166020296119363968213496075011164983278563531614516845769568710900299976984126326650234771672865737857908574664607722834154031144152941880478254387617707904300015669867767957609099669360755949651527363498118964130433116627747123388174060373174397054067031096767657486953587896700319258662594105105335843846560233917967492678447637084749783336555790073841914731988627135259546251816043422537299628632674968240580602964211463864368642247248872834341704415734824818333016405669596688667695634914163284264149745333499994800026699875888159350735781519588990053951208535103572613736403436753471410483601754648830040784641674521673719048310967671134434948192626811107399482506073949507350316901973185211955263563258433909982249862406703107683184466072912487475403161796994113973877658998685541703188477886759290260700432126661791922352093822787888098863359911608192353555704646349113208591897961327913197564909760001399623444553501434642686046449586247690943470482932941404111465409239883444351591332010773944111840741076849810663472410482393582740194493566516108846312567852977697346843030614624180358529331597345830384554103370109167677637427621021370135485445092630719011473184857492331816720721372793556795284439254815609137281284063330393735624200160456645574145881660521666087387480472433912129558777639069690370788285277538940524607584962315743691711317613478388271941686066257210368513215664780014767523103935786068961112599602818393095487090590738613519145918195102973278755710497290114871718971800469616977700179139196137914171627070189584692143436967629274591099400600849835684252019155937037010110497473394938778859894174330317853487076032219829705797511914405109942358830345463534923498268836240433272674155403016195056806541809394099820206099941402168909007082133072308966211977553066591881411915778362729274615618571037217247100952142369648308641025928874579993223749551912219519034244523075351338068568073544649951272031744871954039761073080602699062580760202927314552520780799141842906388443734996814582733720726639176702011830046481900024130835088465841521489912761065137415394356572113903285749187690944137020905170314877734616528798482353382972601361109845148418238081205409961252745808810994869722161285248974255555160763716750548961730168096138038119143611439921063800508321409876045993093248510251682944672606661381517457125597549535802399831469822036133808284993567055755247129027453977621404931820146580080215665360677655087838043041343105918046068008345911366408348874080057412725867047922583191274157390809143831384564241509408491339180968402511639919368532255573389669537490266209232613188558915808324555719484538756287861288590041060060737465014026278240273469625282171749415823317492396835301361786536737606421667781377399510065895288774276626368418306801908046098498094697636673356622829151323527888061577682781595886691802389403330764419124034120223163685778603572769415417788264352381319050280870185750470463129333537572853866058889045831114507739429352019943219711716422350056440429798920815943071670198574692738486538334361457946341759225738985880016980147574205429958012429581054565108310462972829375841611625325625165724980784920998979906200359365099347215829651741357984910471116607915874369865412223483418877229294463351786538567319625598520260729476740726167671455736498121056777168934849176607717052771876011999081441130586455779105256843048114402619384023224709392498029335507318458903553971330884461741079591625117148648744686112476054286734367090466784686702740918810142497111496578177242793470702166882956108777944050484375284433751088282647719785400065097040330218625561473321177711744133502816088403517814525419643203095760186946490886815452856213469883554445602495566684366029221951248309106053772019802183101032704178386654471812603971906884623708575180800353270471856594994761242481109992886791589690495639476246084240659309486215076903149870206735338483495508363660178487710608098042692471324100094640143736032656451845667924566695510015022983307984960799498824970617236744936122622296179081431141466094123415935930958540791390872083227335495720807571651718765994498569379562387555161757543809178052802946420044721539628074636021132942559160025707356281263873310600589106524570802447493754318414940148211999627645310680066311838237616396631809314446712986155275982014514102756006892975024630401735148919457636078935285550531733141645705049964438909363084387448478396168405184527328840323452024705685164657164771393237755172947951261323982296023945485797545865174587877133181387529598094121742273003522965080891777050682592488223221549380483714547816472139768209633205083056479204820859204754998573203888763916019952409189389455767687497308569559580106595265030362661597506622250840674288982659075106375635699682115109496697445805472886936310203678232501823237084597901115484720876182124778132663304120762165873129708112307581598212486398072124078688781145016558251361789030708608701989758898074566439551574153631931919810705753366337380382721527988493503974800158905194208797113080512339332219034662499171691509485414018710603546037946433790058909577211808044657439628061867178610171567409676620802957665770512912099079443046328929473061595104309022214393718495606340561893425130572682914657832933405246350289291754708725648426003496296116541382300773133272983050016025672401418515204189070115428857992081219844931569990591820118197335001261877280368124819958770702075324063612593134385955425477819611429351635612234966615226147353996740515849986035529533292457523888101362023476246690558164389678630976273655047243486430712184943734853006063876445662721866617012381277156213797461498613287441177145524447089971445228856629424402301847912054784985745216346964489738920624019435183100882834802492490854030778638751659113028739587870981007727182718745290139728366148421428717055317965430765045343246005363614726181809699769334862640774351999286863238350887566835950972655748154319401955768504372480010204137498318722596773871549583997184449072791419658459300839426370208756353982169620553248032122674989114026785285996734052420310917978999057188219493913207534317079800237365909853755202389116434671855829068537118979526262344924833924963424497146568465912489185566295893299090352392333336474352037077010108438800329075983421701855422838616172104176030116459187805393674474720599850235828918336929223373239994804371084196594731626548257480994825099918330069765693671596893644933488647442135008407006608835972350395323401795825570360169369909886711321097988970705172807558551912699306730992507040702455685077867906947661262980822516331363995211709845280926303759224267425755998928927837047444521893632034894155210445972618838003006776179313813991620580627016510244588692476492468919246121253102757313908404700071435613623169923716948481325542009145304103713545329662063921054798243921251725401323149027405858920632175894943454890684639931375709103463327141531622328055229729795380188016285907357295541627886764982741861642187898857410716490691918511628152854867941736389066538857642291583425006736124538491606741373401735727799563410433268835695078149313780073623541800706191802673285511919426760912210359874692411728374931261633950012395992405084543756985079570462226646190001035004901830341535458428337643781119885563187777925372011667185395418359844383052037628194407615941068207169703022851522505731260930468984234331527321313612165828080752126315477306044237747535059522871744026663891488171730864361113890694202790881431194487994171540421034121908470940802540239329429454938786402305129271190975135360009219711054120966831115163287054230284700731206580326264171161659576132723515666625366727189985341998952368848309993027574199164638414270779887088742292770538912271724863220288984251252872178260305009945108247835729056919885554678860794628053712270424665431921452817607414824038278358297193010178883456741678113989547504483393146896307633966572267270433932167454218245570625247972199786685427989779923395790575818906225254735822052364248507834071101449804787266919901864388229323053823185597328697809222535295910173414073348847610055640182423921926950620831838145469839236646136398910121021770959767049083050818547041946643713122996923588953849301363565761861060622287055994233716310212784574464639897381885667462608794820186474876727272220626764653380998019668836809941590757768526398651462533363124505364026105696055131838131742611844201890888531963569869627950367384243130113317533053298020166888174813429886815855778103432317530647849832106297184251843855344276201282345707169885305183261796411785796088881503296022907056144762209150947390359466469162353968092013945781758910889319921122600739281491694816152738427362642980982340632002440244958944561291670495082358124873917996486411334803247577752197089327722623494860150466526814398770516153170266969297049283162855042128981467061953319702695072143782304768752802873541261663917082459251700107141808548006369232594620190022780874098597719218051585321473926532515590354102092846659252999143537918253145452905984158176370589279069098969111643811878094353715213322614436253144901274547726957393934815469163116249288735747188240715039950094467319543161938554852076657388251396391635767231510055560372633948672082078086537349424401157996675073607111593513319591971209489647175530245313647709420946356969822266737752099451684506436238242118535348879893956731878066061078854400055082765703055874485418057788917192078814233511386629296671796434687600770479995378833878703487180218424373421122739402557176908196030920182401884270570460926225641783752652633583242406612533115294234579655695025068100183109004112453790153329661569705223792103257069370510908307894799990049993953221536227484766036136776979785673865846709366795885837887956259464648913766521995882869338018360119323685785585581955560421562508836502033220245137621582046181067051953306530606065010548871672453779428313388716313955969058320834168984760656071183471362181232462272588419902861420872849568796393254642853430753011052857138296437099903569488852851904029560473461311382638788975517885604249987483163828040468486189381895905420398898726506976202019955484126500053944282039301274816381585303964399254702016727593285743666616441109625663373054092195196751483287348089574777752783442210910731113518280460363471981856555729571447476825528578633493428584231187494400032296906977583159038580393535213588600796003420975473922967333106493956018122378128545843176055617338611267347807458506760630482294096530411183066710818930311088717281675195796753471885372293096161432040063813224658411111577583585811350185690478153689381377184728147519983505047812977185990847076219746058874232569958288925350419379582606162118423687685114183160683158679946016520577405294230536017803133572632670547903384012573059123396018801378254219270947673371919872873852480574212489211834708766296672072723256505651293331260595057777275424712416483128329820723617505746738701282095755443059683955556868611883971355220844528526400812520276655576774959696266126045652456840861392382657685833846984997787267065551918544686984694784957346226062942196245570853712727765230989554501930377321666491825781546772920052126671434632096378918523232150189761260343736840671941930377468809992968775824410478781232662531818459604538535438391144967753128642609252115376732588667226040425234910870269580996475958057946639734190640100363619040420331135793365424263035614570090112448008900208014780566037101541223288914657223931450760716706435568274377439657890679726874384730763464516775621030986040927170909512808630902973850445271828927496892121066700816485833955377359191369501531620189088874842107987068991148046692706509407620465027725286507289053285485614331608126930056937854178610969692025388650345771831766868859236814884752764984688219497397297077371871884004143231276365048145311228509900207424092558592529261030210673681543470152523487863516439762358604191941296976904052648323470099111542426012734380220893310966863678986949779940012601642276092608234930411806438291383473546797253992623387915829984864592717340592256207491053085315371829116816372193951887009577881815868504645076993439409874335144316263303172477474868979182092394808331439708406730840795893581089665647758599055637695252326536144247802308268118310377358870892406130313364773710116282146146616794040905186152603600925219472188909181073358719641421444786548995285823439470500798303885388608310357193060027711945580219119428999227223534587075662469261776631788551443502182870266856106650035310502163182060176092179846849368631612937279518730789726373537171502563787335797718081848784588665043358243770041477104149349274384575871071597315594394264125702709651251081155482479394035976811881172824721582501094960966253933953809221955919181885526780621499231727631632183398969380756168559117529984501320671293924041445938623988093812404521914848316462101473891825101090967738690664041589736104764365000680771056567184862814963711188321924456639458144914861655004956769826903089111856879869294705135248160917432430153836847072928989828460222373014526556798986277679680914697983782687643115988321090437156112997665215396354644208691975673700057387649784376862876817924974694384274652563163230055513041742273416464551278127845777724575203865437542828256714128858345444351325620544642410110379554641905811686230596447695870540721419852121067343324107567675758184569906930460475227701670056845439692340417110898889934163505851578873534308155208117720718803791040469830695786854739376564336319797868036718730796939242363214484503547763156702553900654231179201534649779290662415083288583952905426376876689688050333172278001858850697362324038947004718976193473443084374437599250341788079722358591342458131440498477017323616947197657153531977549971627856631190469126091825912498903676541769799036237552865263757337635269693443544004730671988689019681474287677908669796885225016369498567302175231325292653758964151714795595387842784998664563028788319620998304945198743963690706827626574858104391122326187940599415540632701319898957037611053236062986748037791537675115830432084987209202809297526498125691634250005229088726469252846661046653921714820801305022980526378364269597337070539227891535105688839381132497570713310295044303467159894487868471164383280506925077662745001220035262037094660234146489983902525888301486781621967751945831677187627572005054397944124599007711520515461993050983869825428464072555409274031325716326407929341833421470904125425335232480219322770753555467958716383587501815933871742360615511710131235256334858203651461418700492057043720182617331947157008675785393360786227395581857975872587441025420771054753612940474601000940954449596628814869159038990718659805636171376922272907641977551777201042764969496110562205925024202177042696221549587264539892276976603105249808557594716310758701332088614632664125911486338812202844406941694882615295776253250198703598706743804698219420563812558334364219492322759372212890564209430823525440841108645453694049692714940033197828613181861888111184082578659287574263844500599442295685864604810330153889114994869354360302218109434667640000223625505736312946262960961987605642599639461386923308371962659547392346241345977957485246478379807956931986508159776753505539189911513352522987361127791827485420086895396583594219633315028695611920122988898870060799927954111882690230789131076036176347794894320321027733594169086500719328040171638406449878717537567811853213284082165711075495282949749362146082155832056872321855740651610962748743750980922302116099826330339154694946444910045152809250897450748967603240907689836529406579201983152654106581368237919840906457124689484702093577611931399802468134052003947819498662026240089021501661638135383815150377350229660746279529103840686855690701575166241929872444827194293310048548244545807188976330032325258215812803274679620028147624318286221710543528983482082734516801861317195933247110746622285087106661177034653528395776259977446721857158161264111432717943478859908928084866949141390977167369002777585026866465405659503948678411107901161040085727445629384254941675946054871172359464291058509099502149587931121961359083158826206823321561530868337308381732793281969838750870834838804638847844188400318471269745437093732983624028751979208023218787448828728437273780178270080587824107493575148899789117397461293203510814327032514090304874622629423443275712600866425083331876886507564292716055252895449215376517514921963671810494353178583834538652556566406572513635750643532365089367904317025978781771903148679638408288102094614900797151377170990619549696400708676671023300486726314755105372317571143223174114116806228642063889062101923552235467116621374996932693217370431059872250394565749246169782609702533594750209138366737728944386964000281103440260847128990007468077648440887113413525033678773167977093727786821661178653442317322646378476978751443320953400016506921305464768909850502030150448808342618452087305309731894929164253229336124315143065782640702838984098416029503092418971209716016492656134134334222988279099217860426798124572853458013382609958771781131021673402565627440072968340661984806766158050216918337236803990279316064204368120799003162644491461902194582296909921227885539487835383056468648816555622943156731282743908264506116289428035016613366978240517701552196265227254558507386405852998303791803504328767038092521679075712040612375963276856748450791511473134400018325703449209097124358094479004624943134550289006806487042935340374360326258205357901183956490893543451013429696175452495739606214902887289327925206965353863964432253883275224996059869747598823299162635459733244451637553343774929289905811757863555556269374269109471170021654117182197505198317871371060510637955585889055688528879890847509157646390746936198815078146852621332524738376511929901561091897779220087057933964638274906806987691681974923656242260871541761004306089043779766785196618914041449252704808819714988015420577870065215940092897776013307568479669929554336561398477380603943688958876460549838714789684828053847017308711177611596635050399793438693391197898871091565417091330826076474063057114110988393880954814378284745288383680794188843426662220704387228874139478010177213922819119923654055163958934742639538248296090369002883593277458550608013179884071624465639979482757836501955142215513392819782269842786383916797150912624105487257009240700454884856929504481107380879965474815689139353809434745569721289198271770207666136024895814681191336141212587838955773571949863172108443989014239484966592517313881716026632619310653665350414730708044149391693632623737677770958503132559900957627319573086480424677012123270205337426670531424482081681303063973787366424836725398374876909806021827857862165127385635132901489035098832706172589325753639939790557291751600976154590447716922658063151110280384360173747421524760851520990161585823125715907334217365762671423904782795872815050956330928026684589376496497702329736413190609827406335310897924642421345837409011693919642504591288134034988106354008875968200544083643865166178805576089568967275315380819420773325979172784376256611843198910250074918290864751497940031607038455494653859460274524474668123146879434416109933389089926384118474252570445725174593257389895651857165759614812660203107976282541655905060424791140169579003383565748692528007430256234194982864679144763227740055294609039401775363356554719310001754300475047191448998410400158679461792416100164547165513370740739502604427695385538343975505488710997852054011751697475813449260794336895437832211724506873442319898788441285420647428097356258070669831069799352606933921356858813912148073547284632277849080870024677763036055512323866562951788537196730346347012229395816067925091532174890308408865160611190114984434123501246469280288059961342835118847154497712784733617662850621697787177438243625657117794500644777183702219991066950216567576440449979407650379999548450027106659878136038023141268369057831904607927652972776940436130230517870805465115424693952651271010529270703066730244471259739399505146284047674313637399782591845411764133279064606365841529270190302760173394748669603486949765417524293060407270050590395031485229213925755948450788679779252539317651564161971684435243697944473559642606333910551268260615957262170366985064732812667245219890605498802807828814297963366967441248059821921463395657457221022986775997467381260693670691340815594120161159601902377535255563006062479832612498812881929373434768626892192397778339107331065882568137771723283153290825250927330478507249771394483338925520811756084529665905539409655685417060011798572938139982583192936791003918440992865756059935989100029698644609747147184701015312837626311467742091455740418159088000649432378558393085308283054760767995243573916312218860575496738322431956506554608528812019023636447127037486344217272578795034284863129449163184753475314350413920961087960577309872013524840750576371992536504709085825139368634638633680428917671076021111598288755399401200760139470336617937153963061398636554922137415979051190835882900976566473007338793146789131814651093167615758213514248604422924453041131606527009743300884990346754055186406773426035834096086055337473627609356588531097609942383473822220872924644976845605795625167655740884103217313456277358560523582363895320385340248422733716391239732159954408284216666360232965456947035771848734420342277066538373875061692127680157661810954200977083636043611105924091178895403380214265239489296864398089261146354145715351943428507213534530183158756282757338982688985235577992957276452293915674775666760510878876484534936360682780505646228135988858792599409464460417052044700463151379754317371877560398159626475014109066588661621800382669899619655805872086397211769952194667898570117983324406018115756580742841829106151939176300591943144346051540477105700543390001824531177337189558576036071828605063564799790041397618089553636696031621931132502238517916720551806592635180362512145759262383693482226658955769946604919381124866090997981285718234940066155521961122072030922776462009993152442735894887105766238946938894464950939603304543408421024624010487233287500817491798755438793873814398942380117627008371960530943839400637561164585609431295175977139353960743227924892212670458081833137641658182695621058728924477400359470092686626596514220506300785920024882918608397437323538490839643261470005324235406470420894992102504047267810590836440074663800208701266642094571817029467522785400745085523777208905816839184465928294170182882330149715542352359117748186285929676050482038643431087795628929254056389466219482687110428281638939757117577869154301650586029652174595819888786804081103284327398671986213062055598552660364050462821523061545944744899088390819997387474529698107762014871340001225355222466954093152131153379157980269795557105085074738747507580687653764457825244326380461430428892359348529610582693821034980004052484070844035611678171705128133788057056434506161193304244407982603779511985486945591520519600930412710072778493015550388953603382619293437970818743209499141595933963681106275572952780042548630600545238391510689989135788200194117865356821491185282078521301255185184937115034221595422445119002073935396274002081104655302079328672547405436527175958935007163360763216147258154076420530200453401835723382926619153083540951202263291650544261236191970516138393573266937601569144299449437448568097756963031295887191611292946818849363386473927476012269641588489009657170861605981472044674286642087653347998582220906198021732116142304194777549907387385679411898246609130916917722742072333676350326783405863019301932429963972044451792881228544782119535308989101253429755247276357302262813820918074397486714535907786335301608215599113141442050914472935350222308171936635093468658586563148555758624478186201087118897606529698992693281787055764351433820601410773292610634315253371822433852635202177354407152818981376987551575745469397271504884697936195004777209705617939138289898453274262272886471088832701737232588182446584362495805925603381052156062061557132991560848920643403033952622634514542836786982880742514225674518061841495646861116354049718976821542277224794740335715274368194098920501136534001238467142965518673441537416150425632567134302476551252192180357801692403266995417460875924092070046693403965101781348578356944407604702325407555577647284507518268904182939661133101601311190773986324627782190236506603740416067249624901374332172464540974129955705291424382080760983648234659738866913499197840131080155813439791948528304367390124820824448141280954437738983200598649091595053228579145768849625786658859991798675205545580990045564611787552493701245532171701942828846174027366499784755082942280202329012216301023097721515694464279098021908266898688342630716092079140851976952355534886577434252775311972474308730436195113961190800302558783876442060850447306312992778889427291897271698905759252446796601897074829609491906487646937027507738664323919190422542902353189233772931667360869962280325571853089192844038050710300647768478632431910002239297852553723755662136447400967605394398382357646069924652600890906241059042154539279044115295803453345002562441010063595300395988644661695956263518780606885137234627079973272331346939714562855426154676506324656766202792452085813477176085216913409465203076733918411475041401689241213198268815686645614853802875393311602322925556189410429953356400957864953409351152664540244187759493169305604486864208627572011723195264050230997745676478384889734643172159806267876718380052476968840849891850861490034324034767426862459523958903585821350064509981782446360873177543788596776729195261112138591947254514003011805034378752776644027626189410175768726804281766238606804778852428874302591452470739505465251353394595987896197789110418902929438185672050709646062635417329446495766126519534957018600154126239622864138977967333290705673769621564981845068422636903678495559700260798679962610190393312637685569687670292953711625280055431007864087289392257145124811357786276649024251619902774710903359333093049483805978566288447874414698414990671237647895822632949046798120899848571635710878311918486302545016209298058292083348136384054217200561219893536693713367333924644161252231969434712064173754912163570085736943973059797097197266666422674311177621764030686813103518991122713397240368870009968629225464650063852886203938005047782769128356033725482557939129852515068299691077542576474883253414121328006267170940090982235296579579978030182824284902214707481111240186076134151503875698309186527806588966823625239378452726345304204188025084423631903833183845505223679923577529291069250432614469501098610888999146585518818735825281643025209392852580779697376208456374821144339881627100317031513344023095263519295886806908213558536801610002137408511544849126858412686958991741491338205784928006982551957402018181056412972508360703568510553317878408290000415525118657794539633175385320921497205266078312602819611648580986845875251299974040927976831766399146553861089375879522149717317281315179329044311218158710235187407572221001237687219447472093493123241070650806185623725267325407333248757544829675734500193219021991199607979893733836732425761039389853492787774739805080800155447640610535222023254094435677187945654304067358964910176107759483645408234861302547184764851895758366743997915085128580206078205544629917232020282229148869593997299742974711553718589242384938558585954074381048826246487880533042714630119415898963287926783273224561038521970111304665871005000832851773117764897352309266612345888731028835156264460236719966445547276083101187883891511493409393447500730258558147561908813987523578123313422798665035227253671712307568610450045489703600795698276263923441071465848957802414081584052295369374997106655948944592462866199635563506526234053394391421112718106910522900246574236041")); Apcomplex invZ = new Apcomplex(new Apfloat("0.15915494309189533576888376337251436203445964574045644874766734405889679763422653509011380276625308595607284272675795803689291184611457865287796741073169983922923996693740907757307774639692530768871739289621739766169336239024172362901183238011422269975571594046189008690267395612048941093693784408552872309994644340024867234773945961089832309678307490616698646280469944865218788157478656696424103899587413934860998386809919996244287558517117885843111751876716054654753698800973946036475933376805930249449663530532715677550322032477781639716602294674811959816584060601680303599813391198749883278665443527975507001624067756438884957131088012219937614768137776473789063306804645797848176131242731406996077502450029775985708905690279678513152521001631774602092481160624056145620314648408924845919143521157540755620087152660680221715914075747458272259774628539987515532939081398177240935825479707332871904069997590765770784934703935898280871734256403668951166254570594332763126865002612271797115321125995043866794503762556083631711695259758128224941623334314510612353687856311363669216714206974696012925057833605311960859450983955671870995474651043162381551758083944297997099950525438756612944588330684605078529151514104048929885063881607761969930734103899957869189059809373777206187543222718930136625526123878038753888110681406765434082827852693342679955607079038606035273899624512599574927629702359409558430116482964118557771240575444945702178976979240949032729477021664960356531815354400384068987471769158876319096650696440477697068768365677810477979545035339575830188183868793776612481495305996558021908359875103512712904323158049871968687775946566346221034204440855497850379273869429353661937782928735937843470323023714583792355711863634192946018318229196416500878307933135349779099745864929026745060989368909458830503370305380547312321580943197676032283131418980974982243833517435698984750103950068388003978672359960802400273901087495485478792356826113994890326899742708349611492082890377678474303550456845608367147930845672332703548539255620208683932409956221175331839402097079357077496549880868606636096866196703747454210283121925184622483499116114956655603796967613993128299607760827799010078303600233827298790854023876155744543092601191005433799838904654921248295160707285300522721023601752331317317975931105032815510937391363964530579260718008361795487672464598047397729244810920093712578691833289588628399043586866663975673445140950363732719174311388066383072592302759734506054821277803706533778303217098773496656849080032698850674179146468350828161685331433616073099514985311981973375844420984165595415225064339431286444038388356150879771645017064706751877456059160871685785793922623475633171113299865594159689071985068874423005751919770569003821839256220338742353625680835415651729710881172179593683256488518749974870855311659830610139214454460161488452770251141107024852173974510386673640387286009967489317356181207117404788993688865569230784850230570571440636386320236852010741005748592281115721968003978247595300166958522123034641877365043546764645656597190112308476709930970859128364666919177693879143331556650669813216415210089571172862384260706784517601113450800699476842235698962488051577598095339708085475059753626564903439445420581788643568304200031509559474343925254485067491429086475144230332133245695116349456775393942403609054383355282924342203494843661514663228602477666660495314065734357553014090827988091478669343492273760263499782995701816196432123314047576289748408289117409747826378991816999394874977151989818726662946018305395832752092363506853889228468247259972528300766856937583659722919824429747406163818311395830674434851692859738323739266240243450199780994040218961348342736136764499138271541660634248293637418506122610861321199863346284709941839942742955915628333990480382117501161211667205191257930355292924113440311613411249531838592695849044384680784909739828088552970451530539914009886988408836548366522246686240872540140400911787421220452307533473972538149403884190586842311594632274433906612516239310628319532388339213153455638151175203510874595582011237543597681553401874073943403633978038817210045316918295194879591767395417787924352761740724605939160273228287946819364912894971495343255272359165929807247998580612690073321884452679433504558019524925663062048766161343653399202875452085553441440990512982727454659118132223284051166615650709837557433729548631204112171638091560616116573200008330611460618128032625869595160246321661385766148047199327077713164412015949601106328305207595834850305079095584982982186740289838551383239570208076397550429225984764707101642697438450430916586452836032493360435465723755791613663241204578099697156634022158805457943132827800552461320889018742121092448910410052154968097113720754005710963406643135745439915976943578892079342561778302223701148642492523924872871313202176673607566455982726095741566023437874362913210974858971507130739104072643541417970572226547980381512759579124002534468048220261734229900102048306246303379647467819050181183037515380287952343341955021356897709129056143178787920862057449992578975690184921032420647138519113881475640209760554895793785141404145305151583964282326540602060331189158657027208625026991639375152788736060811455694842103224077727274216513642343669927163403094053074806526850930165892136921414312937134106157153714062039784761842650297807860626696996080918422347633504774671901745045144616638284620824086735951023713029044437794085350344544263341306263074595138303102293146934466832851766328241515210179422644395718121717021756492196444939653222218765848824451190940134050443213985862862108317939396084438980191478738977233102863101314869552126205182780634945711866277825659883100535155231665984394090221806314454521212978973447148874125826822386023602710998119152056882347239835801336606837863288679286197323672536066852168563201194897807339584191906659583867852941241871821727987506103946064819585745620060892122841639437384654958993202848123643346611970732430954585907336187862906318501651062675768512163575886963074519992200107766768309469814975622682434793671310841210219520899481912444048751171059184413990788945577518462161904153093454380280893862807323757861526779711433232419698578056376301808843866406071753683213626296712242609428540110963218262765120117022552929289655594608204938409069076069200395464619164002156733601790963187289199863434108690320057966371031286123569888176403642525408370981081483519031213186247228181050845123690190646632235938872454630737272808789830041018948591367374258941812405672919123800330634499821963158038638105424578934500845532803135118843410073730605956544373624887712926289807423539074061786905784443105274262641767830058221486462289361929669299203304669332843815805356486407318444059954968935377318367266131301086235880212880432893445621404797894542337360585063270439981932635916687341943656783901281912202816229500333012236091858755920195908122415367949909544888109975891989081158116353889163394029237220498483752242362091008340975667917100841679570223317897107102928884897013099533995424415335060625843921452433864640343244065731747755340540448100617761256908474646143297654390000838265211452101623664311197987319027511914412136169620456936026336102355962140467029012156796418735746835873172331004745963339773247704491888513441536376009153756426743845016622139371930674870628815954648197751922077102367432890626907091179194127762122451172354677115640433357720616661564674474627305622913332030953340551384171819460532150142632800087955181329675497284670188365742534250169942310691563431066260434122052138315879711150754540632906570248488648697402872037259869281149360627403842332874942332178578775073557185704378737969340233690291144696144864976971943452746744296030894371925405266588907106620625755099303799766583679361128137451104971506153783743579555867972129358764463093757203221320246056566112997131027586911284604325184343269155292845857349597150425653993021121849472321323805165498029099196768151180224831925127372199792134331067642187484426215985121676396779352982985195854539210695788058685312327754543322916198905318905372539158222292325972781334278182560648823337607196810144814531983362379107671255017528826351836492103572587410356573894694875444694018175923060937082814650185742532496921276462424783221076547375056819883456410354580272612522855031543250395918489189826304987591154063210354263890012837426155187877318375862355175378506956599570028011584125887015003017025916746302084241244912839238052577251473714123102301725639683055535832628403836381576868284643304568059940187001071952092970177990583216417579868116586547147748964716547948831214043183607984431405573117934967776373989893022776560705853040837477526409474350703952145247016838840709087061471944372256502823145872995869738316897126851939042297110721350756978037262545814109503827038898736451628482018046828820582913533901383564914430040157065098879267154174507066868887834380555835011967458623408059532724727843829259395771584036885940989939255241688378793572796795165407667392703125641876096219024304699348598919906001297774692145329704216778172615178506530085525599979402099694554315452745856704403686680428648404512881182309793496962721836492935516202987246958329948193297833580345902322705261254211443708435958494433836383883177518411608817112512792333745772193398208190054063292937775306906607415304997682647124407768817248673421685881509913342207593094717385515934080895712441063472089319491288078357631158294005497089180233665960770709275990105270281508688978285494340372642729262103487013992868853550062061514343078665396085995005871493914165206530207008526562407470366073660533380526376675720188394972770472221536338511354834636246198554259938719333674820422097449956672702505446423243957506869591330193746919142980999342423055017266521209241455962596055442759095199682431308427969371132070210498232381957471759855195018646309402975943631944500919150616049228764323192129703446093584259267276386814363309856853278602433214105233076065884149585871819707124299595922678117279644388537967631392743142279531145000649221265001332686230215508373001756887779405293922189029424143891860902523020125072081914513559252448175874191530285421032688755719724975463913213416650130089984858004988184539712256278637424126038402626928051361641332991194822906711506766502171984061981065252133878916262149742374847011302186990595582230140544519769218504088109866949722922088405432386591444077613593583977043162030198483687580783576429997384823060264097533891101537850288850208875452232316008470588468561438287055426578280588833996325463499127274201470388306349081714134544089291185028874099319952275905464542169235856036455129086436256830037214489582463463010911271935780422308203367573822202173963037384430357318747050709862946814186132911304352890724468689732842917280819233086617509641888502351666154124836167509421386532027958735884076218465024752214216006343124636083236846164408779345151046756110838674267901803569874943470363501020585861081379083328000450979761530404125029486318117174817838352800558398999904445335622512187782107356141197355485008078033722598929661207534586689194387026678701288235883661632206543667404027766354617520034284643729617064606010906465199030828152320178953367763499425648462967104953266723853904704937155459977223244359796704827248971177536576290495873282263979918608190185511935160957384245746193381018864540398341443436533794465262922870048336387630526474342434263492652939493937651558624005989912216084504237590530711424650102655299280994514986083383571564960853124164235244436418839471473944496583057057034126813678308616528510619213892914048179549332402960640814505103060473822729466747251091470938852715189704510903960069811099490561638179486071758425024112534307738806074627942710452584860382311418063616144670592786423022671878159420103387312236631641711565532384256016200055689990584850129614652403821718135404439939767455202147332201283897294683888991005191291681454544002802167882207080005379644281146076436811762252658697119084492232425967729532174944633069141466335696546210141637869295979380854984963288125832241613124908276514019822229902646896039733957070812119028686326137009638968436489077956313426920368199567596428576484886965373813120547380940758060791114396835798478889574202010394322644725932906550201938457089314396776199419230289067663807121779719696901986559084891516381324373872236574715900584088615980357198551814210081812709096071968326771380197511471144465824919283431439056546492279930152267942565150539544200689702523323921822542038882844715943684624104551827218334305559448316047742263873886047591632964026986643545610882926765585970956603378896581991747781168854913408532900306153854396889935716898788575384050149102375541735824374537629428754826710372969543274397792392280461782749854973868350413491458156904982330874385219664224959847715814815062706953375070797976022372569401691461374860095711922469228633128182687160159530822351748137454909809152290645895627021926526821573140360451847516620129376490520083105472967144371464788001888492767297732235305345095500099492568227839118072495134061931255331151369899255407534880858224444053927989329248877022137179052502751258103252877702152267073091243326679210110418381501739688041273383675434041752960485760040017205524549427482219234334245813743685502854868344594789826372474263384509459695000655718942975450917713445196880141258838983675590521239174962863542990657827429051833901384906970752823142116372645404586445634982957782376851603582706319559030459884878893335522399761398761675651669293819494189702204104055268172558117235459023653463904099051025828748982910473603873010140762927526864852738425659885920252228789612974764937984795128415446342496152015624584115723787430082351815151255483594577612834618334622458482425398960372059218207360467258453432348303024442922663551805927135907926458375065236610158705254420454427522399655918830598735800263484619358743583256039455770309665487608388839384373260593852766040391273789411845700468215083948377918584844252865857287541308158746962694464141982897858294679010335037765149290471990782228087484538463335994139875981935635595426094920021730282219291324610755034159723829784846735527316719499323774546101622154870667279654356889082750750385194364946461236421512237418239271076098118331165295952658857274986983349418174089463129164070470548239619996798378868374539679750722686025782433366536376048673771131619789162239321366833518612554248017772967038503289610060749515117568533833292101202911263748484763456287411828132173343055844411560985666312156750326304287262340215248778463994174203213186650730369807172498498530681398098707319409035845739814534039663873374980703942427975613598554206180580884925369866302690447390838349456334676718973333924898623831892805218091285187433667529017454054252600093320411156172367368088284607647496901787959927706320192284084421978708945298041959046916619176371836587466193465333597502489729784022696453686109615430801440877469875616727793287519251679638698687900105304899754152761928390384470591250502517721519181962635604911315371330390311544271312342509883739263727815007299780456497001552069286120427670813732628087406296079812707254081876582464008952529687990334347900909203036043681831055435175824977675284303811721391490221569035451503210741745997033257588836022746502930319742498660601623225569817090589136874195761344240977427674139865890480005809616523467250728010089811009065805578250348897369804636718251689565258448927370134133982044113868614568727887224903992294702605854343762487477342279111689592419760893193225114890176946635066301166883795731595667330500768497190567470905412957443010936499375408355670789570337778370321074482375374328699166793180310272410493276087581996767531352745364535800721367067365699411257212702227042069567226340208296011979565359615884428002882707898499538280053959919917494069303743540452523475352859835214270471396676956007137824367641047605020174081896422787957053812579637376541631047638980190601858743867858812089653378519146180507022618780263604368519294452416168652942199116952875926940308706060386289333855000555122745730526677540485512473707921273149232186276677411300097049533840799029876219798525798368377095034636446448389409460950156394827234182855341941024839124776836861446268995517276017210563092724653274594593884451709649405235168641272028775255035407215490698363949392451498685722939605724396108464408554158559355034963463681123907851539352267710090903118879564105734898433771385785234851422149083852636035419102663667724205976410551797630607255427800647213717346802149366018351580009547218890244396064884455195726319747214318281976387675907783428604693721805882299074821345901392973245807157950995813597977424904993670795527508308733445446573034723401896349618212253522518707157169130095463231915682070542750113877671754930532451488793919063143540607236796063137084898659860266496345162140297100248022017828040214350228801504060370924148729967351077410391455589236515892113625962948793578570907950007751252346265239812104220432084979737199714688045451271985666268027554027139241939527770864407486197233608417286516751218338078288087760289791191900286340895738514132564429686183854830825454532705485640040023648389127800685482685995520717716168699652852961031372516480825576231951140724399817560344873246859759275545425633444756081243688267604099015388058364149140163145863939802447021142224377191387130673624313426131898140272148472881743314261346515565441170763698868857118202441272935554272910205267078504466957682463383931434000081624082786850079095974704954643691338365214611148983844618968759988161668298955681662038733610407062684266219716746123536760620181116114551066460054572158976689657257370009722049072247517470037480577647805014161875741284165509450172506752928904791710069615272817894480556262662929275351089070605997166657654519676273178286475339174722918507638462280281054636832384189980484324160842479978258553509844381304520574865613364790045667924045491191063455973729115937854067338918313155567509004447443405376827759035968354045722720840983290794074426480423852283340803333850527847864064351934635094412845862413784114356434520367994162151354681697249887433953129154475298072500159730879828949048386112126446048152797582262056499653208918037513401702823112060569239119425381155906602935749616545385592402902986508397949806546208843483800441154054815129449860966310789040980284024073229933141743202883478824307422201251926515428429654317180984917510753492103216229559546746189234448922707900136955622396563734449724290094610156353436536934322450615018252887381345830125159268242135019171242880098145823317099938161239062744165096463476639916668845258498282782933200831213226714219626043508562449500071733176344021264524887023055935990918328153426643910132149357586946210184843569567858815666441935284534702812745040933746856393062399159701935259683850480109744498112892029721046247122858851766785444468414690449927428507272926169460812263104349599680544672819493773082628797165444600320373512445373855641619556699634425532428794658853425688754301734140966410944348170917237011835445449938700910454196460870206678224060546855803736809971496665086721113965568318370053617453043774552676303432075652930078336237475888141059765387876335569657825810200485685667569840114955194674334480448424604326304613670627563587307331729172362126988603910899665413682818986955949457226452651801278442185531160371246500299426901571437702099165812157653439242537518589554735252811332195410596355910394762558574318708926759446156265855181733243081877410054844715888651743344229449504348737486087615699262029157072507740245952280267849972132416551111222482951675008148607902496676190427824042669429212087099421047053381576519296465649542068499257850353555262124980813257530719612931570822324054189599577963566003944845865826569320531238715098369723969667018744611548016810952905099664784490509541809986372822352389351398549070547399213768857530630551048135924837849341951162499016279757756444141694891216457024746830939472472558318298511336170455221048438314967260772830546096163718731492000723680765376845351550447398868298811833750514600244822640747969692950890572799458552301748447354727097366674834706360880354558055975159758681731451309724176078572216704487460714953268048254391300801342304850524495028714792255878707079855682470190570724315342405086481460863153219862168296875578761821173883151334076536080159717801720639067537594803642916047563317560424255157433633267016725429821100072767613486912253163513445740579690032225474336244373590076985643184619635538794060627347036751655973937702459851979620650211329438683403631255380826502227542954198862804695005027355198130905023718790539564068835671704811171713971818230794022222949682042097031703067746719182745393042248731952224218434673334681428213356005757567324992732670335201562147303962184677067060119549903702856585116169224129153317412931365022469645385832975346425179639488091603463742381677543266093151038735960096430800471303980666061811309321734228473748305372396746905078121691192948286707750332675765623877762106922959181992713914016365508744309165143096216104384981232284167897516967760174337493405437012038441433462911968048552405254210309472994067752144205198561793143425039277635448562516010286370725635169713439323165420117843466174251385542867592341587231623519139729934734600228091859321390885287987019762290607124862469540231628345627871105578952331805156768008110721206775971325862127617737662222649290244555883290644997992422449648585204061333688959255376258732227120904878638290896418205044870583080625276569012677470548730386042260283980234926338232098076426664291945681577938985721106079390310214778134510488476502280465284996513080029880372455200462264916190269178971081589375890148194222530466513865690433479753830740538708744584748474170230678295524740736696701358581850783912460407438803851246314812156925515998485235329242665402644887381247387173712320986205744549629273853493023556003990941627836049062092375013697355177759868150779860027636650142014069126811799797053655371205479749164709272079542259884559654327198216359928183932753080550927824736772125546018868719716646270247968719866116356257626289835921612556381433462103191579188179895281391124532092652674291214106054192301007859712355622083814030687437156356241630428390870582209810294150736120855862752370631399081647899267337288424998647380959175174541696404766458748506256536038743339929973226966698197987524427429308641638670490060513840613845790885524410920394410862706288136259086575926369358322558943973099376048975314348688259966542698303243139184571676607111639029176637536280373728618859790576512250267004233095263441666959315847610684427207819305320997552104927412149769190259956637321446415948934207024837995806648608513373269490303109445035641956364938778615763710948580960412223637089767620119109382011012376518094635320015904919404624982362101814416641771785342081935125066829731629919658521196527504757982147423632513427390487223108789398780286299599565587113602427931236056186394327904271642442219329178210219377938494700575438674954316766348205991537579017664937439661851963299565557195910756574392370283938952637970039189118814492432345838612966708830454850885904101504465894375639230531370415421275531749855295347885782182098802217338561171152886971675999774825587348686317189102244115861602888498603655315759283660884665242192241406882393051559877682075272759667838988129353998432249960412477828986598669259796483309298869473919357076118149362088771908395861619282498471925898153186794809535642227129813609624003227959528573392368018301829622800630214644812312148456560195984082387047742743352904114911724891171997336166506821399422921448074552499923843632605225112777410439072668862078721462551484263232470476233075241709810857114107419261435657559191043270729312928344523585732115996240831623766393970383483316622480110947567398963567346035793755348877362288517380930458021038700098637422397513709404944639442950091254885614154234489775154098222565687150452162348604196421067111545727644616093010337591264051520064888867680894200306147909618019482690086747289872697813628466054185366697685409969547854328744187941723495604372839844375587797380795219717058755952759990369219172140689053315888619175279362845871523679162379980376717704795255012451574691501714237044922632797724273869333720589379491670574255518181183525512678365749236104804577876611572624101910900110211423898759868989017422869169872376924733762900817930883407240567921739244384617661949368060452415450168286615456023317327355252667688380068322056414786712804894975114796998372867390845377918647882913242891563207911998370666677743156244699718141236145578991521692783881635283809768411153731157014725591895771063616148136967310521813808835535874348368723389221603034667397227372418947523619639280281894445742976672558648383173108431880484814854692490088282519055914354110879747484442248122036360539357621613279040115278974055098067283411300003634133936060729918236164783519098630180255888154885797626773076012729787228261350713193411341025607930525951577347424638361223734952881255482513077390970381451955925948544297944709516421180704977426079339395522806795754199135202708990931667722773717018402541916405485607871933782190706149528185397429439710491793081436098030860657971369543992820550819856043716152378574113270643337602300187576785338059934724938388358908392082970269800162070470136797690009154485764619981282917508171229339537379941839512485340905187785860236060106779805737894646439877656511183409571876094327470800684586601296808735981879168588290407004908457254503127282163452920169435658008227603047530377852153512078506518275707987343736266150005184781412872698625827755944131188137245250931470944692273901613975953181940505585066462600673221872282420934872582822524464117145017339324983217829898766470675953873110925091149208264765484781677123642068532676257146090995177368221222076333514891942607361976614988509297497247047901771692117338673558630674416600265770977274425840769935846468868623720391374629890798082074556234539152238944652256748272395314888306443249487981366405346169068655941814843686097921997299683123571163930317642935169843866129564124705044002861993255503913284130487744659344793157017332955535633732311078461707545828973778617115999271848064677929093529956484338182564513742084644901161640928540373076599618499834351750522249726905116488487507284431867515931391742306480138108723856836056538952147597309680121195188245726745552009833863782509983785780450579980240843441864259643480088888211215272244518475825041804925249387548134194365560589385728049311612638655177929317129275948658370395014837593331320293902638042133738859358988190639849372698803817717396077918704335492051130595110891512766619076067148050861542082149913076341009646057645149675213049825823593771927370906460302033981035472344292867359895076436181942005147915034953277296746590023056642028444188463212877931480317003578769660994826546840582765564930769688592971134126121753684184516176342587321012078123534622914877693250364292656478267884126295589053109931435221802972027127306759262347849710214394198289895976478916837324143979267037086783827916231350069378897392087206505936191099644554769975862315545272051813846646581016664708546561992831104177479045039580403920112711890506543197058247900578930676429385049046720546301501470831992839740901638060955586421506287026323091624161155784927562542076028595617272523369044099138823065110909753140287494105573660519899043744007444076855540410658926474353808668364500255631681598282741611492860722275956921709175936680979239650757684499587586905168980844072605053548208905447940665643973229931920243293625403421445623160714784852883302078351627520913127792909618830568170296476431721954372988442999993385835723900176277137338203965727546006652827398444408593411487066752245358907979159149942836946507110928665768963247230129603765720141589357911081959028892341336053175567527681186345036075810463571011017758747759221847835248913877438080271341695962027010466354196130614111039672587950160102020348137498903790171282965513521741883356790759846284309129084593993003680295829871793367832562284486727215200262989667784070386267553775209612475012779180665649058595518432862400471938803244459150811187358913001631858333531380562127493821384016892187131526021989251416554383949706372475102423846782561740007514815266976467891865309220796186609256477828391733424965639848485018890966111411531272723960466038732481298109007454249872445714964309121504268923583694207779258602937220195518262312593353838292964119259273942104708865544255941886561896388314163251277980293081625387297113565270875029812892791796713806215079541420584155081653621272281045578835010987988769510341390441589472235564980292143469576197750229264425655224649696708095839719640568163824302770623517122119064991226847735788706281901059826922459215872920661395098177392094460667560790631267611024459636539836241433424539094354464335531453548867207391487846891781368648054049393027691279927489369529857480795393459585734183664500570139183732751532861856226905933231404109531707586521724926302397917275664364119535513154181705516443869670945649537166893375386990187677318022007172080382860202180065435902647423187698508267941223168537934452889094078626079386451141473212895739053435515810049596570049120013887044136319710574030517331915898636785546360830036600755414094101832626329670817973095735835633875731016843506175922085825625567790918419196328362422751668867569671009756715183730881832194647471420409697644515541431879225764539021180084718062422744951422437049671934010045749930022382500228400895117881728732043209203040419843245376695085916560654250029978997073164125519452733143962391871838908857152038647955564269054804862391681717329747921734072843743880084476468358661616865585709541969265293110005668786962677830083433200118503810366916033183222976709303885579956590828377382473517757644282050908528372707287477184315532786908952537518168956384557607764923261603976347502906622333704433368614042979349288367279085645195906876492646269959598811228696236644844214768047500613106524962133217169233675544322733015764452803459079242638080628971856843766418853391290461729435282208909064553396428821021686447862592606607067310065583204544641909168417678149435570220325159688206332396208679776291992282528704385119920914242275420381472815753727992979315843405969418277994253242158604164160963162837545548631121008137485889076818716739201234696062299521622590284326900631742352655591884981331800031475025079256993449360464556986940744976622404044704004586401404533692552329437194198895151332310748863926042415118526953426230377200886801840201125649629252004034173503112189307766641273998015798409511273908239678337727431927408226980327946091912801883737612054047711781237159771571422953529956181507461731931727818677916823243079126407041772641406777188432609929892141510572407771669949664931583344755836063133784626996183911438430036550856828419349748142086850095406328032345056890936176975580462571962263372810018067201792415720107972424517778935722042122067535757005764105492899250475080031184315668208127359798285138674508500342539200305576041937466284384630387106528601958722227701401679448464347858804116725005528604931393922296165003633044540169867915311913902084772450923235810885646628549111400946201887046483583199826593566576787179538537524087442481785687229192404375960783644328851206702150712226596023090750364638965140663128568735852840250643807415166994143888036267744459502985137777161655674667571114163762952290811296871371856001505427451732818030671600549039870613624142169702351432749114964296772385729654454385400023362334683068656486518970938191890459394883324936806110855317817072236840009759118395231993832171262021316914682020021152720481750082602152793204899640748035335680796441768352145148858624449187188492935013540912992664324790826906945809472578323157096216778765200723362891550688278185253214038720404220309564049510697230722057493834344347345612991767010146114010241410024484777915353433948473517108024054394262536228683912166125034979660058697687371216495036631028471741230388377908266707197018937269697414856922152586798184512969598864679814264184332658674764507971691154564676991163811421719586970822758516383758807858576174533727276586267737914983510978360019994290144109039273268580624145532100481164300090299871279844783449599210700589250100479953687561212571737812151396770013337959461141753167074272427242205091559704241858424575278352280772557697739091284439919653520454884182642532038039529141231714407184096557780459349945256612318611962581939187616629915577509343250968581849293597680272385976431075335150284489722205750866611508021826538278160253875164984284150073107838296929080962162142401322272527002813395854726935943051786865856278031952037846440535962813831454471803660730222053585552995441328481911290572228002761624429436941560649885212260007337843074312759443142492210170156685398079086663722797976035180974757869840254117844882139576325403705584231403062117216228161186783097343803423943298407515529031487222949869840985765178647313636799737791982247478402964695999946002252216638813528648883798886097835599203320105657187708439235413660350508387678822446494220229229090738234261857776590981448736667759127163754454657506510665443956295306961123676489505180826522996779317802324958762305471603172449923572985710834684327664393850141980313440209278405499954218540148009534210050875299645162637173224208472075290850379663595633053153272996345241182611028936178721426021938376350316678359889670959338033121974325760030300520333234963383867107817485673119846024251969017036398980210644689770000605078527429898489573151467461897393808614224451760169362713478084109758951723977054835978984410168767249994594624654019809412010905822812663277894753884927262295012844074450296732248982120762126828218365259311530520538045991659567349259390608414749642315542503420632040347232507310817256797541339552683857894336713552283859875901674974168938058908999329069639880906337526036570117199894953562599389498307367803242710424905723413354569340628481807299874261262081084448911354384465902096974664584001525476337789892858440363668798194526260795835945583263375791502537160473368792475698855240003510484909855356659678932456024609112592123860270073621632153302605827128887403419943918950064253028133104886616096915091487577261692553152701437736395815890930396883022781288168474069748684514204110305910648989307101741491540600781258360478763282487602462405705334328685955154299530568753742381819449718482914298788381312100806152393221706222301564415382381847157634357684001759515757436539763794218441130456807742493582112210627908174131123462234100063281658196908991203702368832358952096969686524377022773223364201437278961857235160197999308143541663029676034283825385167600161326785203133410029528783189528747976748894000694989877227702108543591486205546650478895510897726640945918106141157298720325863376660880267518545172821988803555183494388674652999206509725767810183458734734605211895034335056042244412076926639895046503509751847835402568395847493326151084851119493297713729483071120202170389205033053075194977785234207315472456405938518038947124316652502513967901291269462577870734131847871026156402721744636822988872773694391725831662716281659890049866144300774752573946141642429750582619859814882107196132194367194255426291355416564281180743333094378470301575523390008190131447851658022080984937185796902606092489780986487686349075120549179404600295724016608012167802238180725240832742995823398383979004045433978185908465315230363725199537687915329102657709856865935706280157650732128812584264792554264252809702103125141947118436266531674845056294043219148756291594327502141470212187436138517849871717035153813338591160907168703199165531437845763376799836951551872264504931266940284831908230638422045278313750765721061919361825109850265753724808341297151330159772441143105894213717225305754134940269059818897146807906501195267394438759814690110933640516119928236755033389350475933526571483084511746906508203191710065319395774540892266484859689343784744878936800491144418848068548546405907872074512690725303468095256743900942072943600508630010851122995453551596367340199524720697806972165130694494313399787297500627266375769552915032206495804445341056672586854978495792892906046353810026579201046889548791448210587242342985714006586603601087039976063135031757053209175050555397708393609742737513392572067736554938298131437895865377952698899771552636597191542696577821767219470879561427531536178933334027846070362932039156542547741891705788781712078965823139159721491067805343902687323819916534014274634544417941205434328049562758421326807858439845202350291376757007612053982663589486607013519081532395784224656899814369160847662485080655936469034371903753583987015657943838077605991457900250737286514980949786281850215248111532353082225458828970802749393691869793537672972065277717847739628131728725067566379958648452423903939169664944392622878909177651127858021581413363773495556728864201091640785574217563989971436293624278292495778364404771781811971341582611670324785987043156931635210707362668194857416154264391022183411943236478195521811966416662830683989676691528399555777355244178669231813809141401705723762762548289728399486281827662822304382625219718650920659147397235188163060052940763468278680701160937918632283532728195958976608277942047924056754441956914702074589053980493989188343822339118472781312793242742863455064382547866676617993850852636875455894033134176548274627394062554275640430362593871188018363663134071170193597340796053063345659262050567499337862979165784566519407322986005107222768365593766243641623417928872079924620216959395684151706533337739052982382918198668314550034882358898387578476052407549119882325728436920554531295442074390324991531190976294954576241839856948857831040703680188595099398579777675791353272515026479935060977725211711814671271100064952097996194344421433110350941783117988224268733074907659157967486580773348293838799112749948512365129879587397047068980476814920522411534991627225793606735799096462965511687510020011179098776974335764464266948212131919495296197154429109417518010308363867680676347196245403580270347678770334093277938723810830489612150010961708674774675122613597474956457071599898406571058603854867213151864037020242344879081895881228255249165058308361998124735847296529834751385670488873767100677450646901653313926412254789044042218643433222051687316293350780034360104971899262901765904832524941283907790423617466168827754936443571534784485223208418739918961324581422421259967731691470748517187020658059198743749547105859425140589104435479734780007467744469643790298666557306345693129125199292658867134802230890707370569851451745882376437317145269653761045073020341933389592194831115441888671560011922412645239422166532658001070184905653106063152916638705151214733569932330856586315475663909369439875068786199249192204537386753306346771344887767930890675773388875392976263846501891855612173173163388910110478243750901865177696882584708491490974713380782901152636584274648339843443114857936204719639832751855191237669745004384035107606280390504688409526294183326451210859981390675691454370189022599531958613039169736017850949128004594980473701864510706721938809276073025115741976484355829289447809652394774011967652378527464951610723318265727733506235006034930681292093571389004407121321282369532270130383717165527828980349394087895366207179014066830522664458654290856996560340131370830000893287893042522472948921971308044440205849096327480717691091951345160380600191131068463116216849307199988519593377700692606885063917517523800316491000234858373682715785627380273832938120398080866571288299053227063913315387648160268369682047438106695172304072914285641113575978026841477421665734516402043670408961095786786447188413864262556220715213871852190156217408017764818807110018262936444053051763274571562538550894797940268249478406259301766851743494770226993416872265580395198700304636441851017485230932281579833179472133117778325710799333565440949304790379260646727093020172653397716730831137624284031805143175575691891503525060361079542250480460108435280665578023254658679017618946247247573131651209542413100132008369047364165319853790514948965875010728174837086755365109294661610857916142739140164261109405738215571278005554036960427821981916149734868453306194177482148454599841800377065136280549404117579034050975063370262270197403754496106011930855484579497919575285463608949198978309057256178599859653093214550107833122342776155824490964555482125947833477860877629308113013805369250762068406132233294052761029094218787141281575616366346952793716157164694262408966023104658944120991664949062508856519774071638580061762505247868775545376429648617181620882117957225354855754672736290091400251467130172685429937186091083607915482678807005161282482183834573778700962752504253564944044304881200624645053574146250462316146137343930624589695166816900009012743806568877316380974607483832448471476224592628031548305893405009155501146669900238617084584290567237053687726812602786545533267863120057890118514356961541308514820717672379841260908720537794002798311061075034886504079407392366517116651712625316095278743906128983657011968854416787975954326562928044715676243274294477187219552724071509266777909672489051004985987425196816497625858160407295727733990991995661138092090368803342809821715773444330055490382289873524773308315104408819473785738436466844772087323254732837200499870310796138033173891711195706973441642537318132986420209247333130132502515018285489995264683725856369549494782040706757380009610998073507688115469057123609703310391552677470932921591217895802553355762464966432575924382782044176869653348659634993914986261139847908566974539265919931267161340701775971400837796757121393628277035626392271114704095056536322204531002687018076444462481060768844860491995135167265160899227179263059250636720839576873053317083307332577045155219182703892518702835164125385466614504022625456066553081102028238562620957989978814573708438186198150847323476681890256264428554538073387204865520531136806698381709848409647186073494714725361487135139270928349644492149338058943048941911812991168965602514271349991995891786149203609111559850894125658238027280279218627291965954442780796947870130521706067136229616141501529360732361877226388085546579500268822821353498569806810984543933373113891781101897413857244574677914158161642430512886960182760375156107023658532697332607063085096659294586650521595203875500086136774572119599487916066259875387398283805517679588532479331468421493614254852598847878680353487851235667458467535255299098221976445689726239033409412619313350061001389274457217438842646827715417984701679524700634807058795181028082341840352948073174801245657209392962316619114734331084671575413435991809837974437434264442988139786620617409270506793101860875979513302885932755545584444964396479482817339620032385678447201706394798910834831026851987446651363878915982646966447765679986130910382853197229018802161165197669737060704932567951532906076272939086925802787884417127155288957790775094623773951189345354675711606700617530961080585498426749681990167297374915659380085041974651195996489331911261823734411731731024097816700916973230986389351015789572555088777410794240717344815892680483857274193267895708502102287120728364301381969010336227892886553972107958222479877046323795468244003832149093952420031449916255849026186781606029603653130353549470839018598373913240912881598071797603384440236383544022909385280109259344942015290249368575323804307636751023829935792131419503452607609778290947352545772986193217052774985351638712074965100705160259932099787688505987520701073124634758014732783899182384302491689000622438581286294342850711882402238564480253693247805282364608938240402599610637123849259931196574383169060653995690606823988655691709578747059269653149569501720913638508738797156249932452814632042123543280934897893663122157181080254013209676189550205604925659240240657655555538852291227145021880428393392114070674817906296372721655486720296113957026402928501995561953407894661051802928180355733708904988300101471096225463097420340853209299367790473611488742647829825696528658851674786096041986579060857836773395536366059923987750382930377286261107412194875349050559108555236933470374478198959105052354953157442664445631459865854991665190516347987515656739667921481825490121320609871419911977469111683337121991522679608127698125914982665157102027387120699487802931415331685233050866882021473242575556249878092849014852673278135321730818403105060482196980019673579973898168392330754318433474394700633696386080077466906249105071524836205035172122744100452721353204069013509984357639198356778770374876669559836409147539245526371573235421387697786589431819872282474021432045916423505729594587156096452238282248509828978324579174407720565034636214732761459488582780651785828715701538287778471287969938738787092464887090821699717799823503990451237317101380061365320988556415264355889968537255037829767960446249020048793969635136380864080861770731225669242697613534653964520589541429738979101542140454504926147693231851246631078753449031960637072063890481632744706980233253887210241035923101942384333200352295068416655009199730502323510449883320093182152201924860349402967552873201782116280121239287626286489005626863942970453167195664048534088631941705570535038604624112075899209977486491787632937004402164640641356448174698618716608130949171807004991530441014774625652155952448155022458953863954554752732355676064687625138579581158663686593821786514517430373461657532898134097604051674742934336915793035314463892445209987849763760576296818980478791460456808396880526096626479262240184942531330951586605311364522694918929709230095346041626465198412087782311512150100791809314142295257752424989657659790099472067253470413617259747646213998708886791057984854235727661323381876329366402745291679634650670891612339293852509779520212317515273813161198670718415873193775226951879966567561925206955442094308400474842163825943172843522171275280151054228044429609356426701609127369783113727117086823624592757444467903935420461571322508846432431385504217477834421698043508582295927436495923749450542034567066927578930924788017506989027336648955614098289904049901892331132032579446716643873731874774112223401828929357727231648218545896723125396133573191161751111181996097583387395938010424745028062902370422050478519719083131318875991802431679717321635682426592498732571109232877944945249655260405291073188576736402311656335543297059421221915134425790576246887613474047445490879158347536571047931193713727595397505790093525448864870096623611930528041879270374709624579284886221048087937420010531448517897698874260852707733874761588124765239408116523387530870080613281384033560134305941525547905300496824104202708328859570095007525269624312215416386138443538334631786002590100953562218177873256775039458588741267498970305790224611359729813760255467877639973695886273460732928874925361778452637531664245508445457984557971932615040628294950069599895024885381030696943286336947121976090748411685507031740746819213121513132787490555761211819259623720033365812504349431231978296386447544645580559961361987940158977389625060099386921582429182762084272213717720366742955569470519163842031702271457516243413268873369979633440697207493301299192296087911852579769656466753526118330141492415800323463209196324827064208697211880588164054508748500461580291049120123296807537561744942430175727604024922889627425837438783515058926513621780768188574004881750283600870069849111826857455732095764600676146418910502372448957121364905159625187037491705621269664755117417353397087881065807278840878336668674950138249579869599329308103265226412878813706023903251401981245680900685451235027421021067002058043092046945112415014832219138162294496618075970741281653820921783708919411397756961102859357551303927638995428756561099262920573793367638241253753342603942637461599016036138144383347794909220198433020261170501012438738700118546987890835783028089795038724083882486417315903625282608830135410104827175934438477870364160821986699209282929104785006061058137147159423087320087098769130146608407270107291220518602024207525543717147489733902753420317634852342566354712499228055731210920173780009245512363914903645134121944351948478764498502893039169035729868212205965205692115138795297037544347041920099929302781042828072823724778542890192061073939696156759305072649503151491797730534265819777106794995565803953061152615357913948525937615935500598768401278533659476586758378532047974146726204124318147599653362651196397260685046028276871994633468211187660981215237944355537198689704512890732018519383692608737708058492314644371493154799056094997111406738550409973082824776640294881185828135397240491292772133453215592526506806894225496478822607334666621730030386474187021173331605841047912546268930115374212701575024742909195596313881695795898350175891131613530071804418059162704841639136712506159720598419883107458549506317220820883610130647028638304587818190682803895787588119485751655638238879128351211017971321337335587741878946239972168146862130084949356853319727895019787918954277413680657013550432121080747469331472325912039829666338045363711465402046641545257152456331842369796115970946322734748743127205753305486516451260022898898875640529724700269793962751475302943631296960473267795252829303109886937615597759212644401739887398755621272932755385195078572917353356952459115657688903753760962395027506109726925509814825646648465725411900119852767566145761832868928208095557476487020496797905991117504937316994313786365436081804581153699116072564578341157819143247562212245442732602804460708201762279505213947658196573272495909431680842970002627448899897019479185024957803257253905996963312944045377810985431972211637859263599453940448874068140959254239942425704834375933192732905950968498661492071549845472787663849668497523970298323404"), new Apfloat("-0.15915494309189533576888376337251436203445964574045644874766734405889679763422653509011380276625308595607284272675795803689291184611457865287796741073169983922923996693740907757307774639692530768871739289621739766169336239024172362901183238011422269975571594046189008690267395612048941093693784408552872309994644340024867234773945961089832309678307490616698646280469944865218788157478656696424103899587413934860998386809919996244287558517117885843111751876716054654753698800973946036475933376805930249449663530532715677550322032477781639716602294674811959816584060601680303599813391198749883278665443527975507001624067756438884957131088012219937614768137776473789063306804645797848176131242731406996077502450029775985708905690279678513152521001631774602092481160624056145620314648408924845919143521157540755620087152660680221715914075747458272259774628539987515532939081398177240935825479707332871904069997590765770784934703935898280871734256403668951166254570594332763126865002612271797115321125995043866794503762556083631711695259758128224941623334314510612353687856311363669216714206974696012925057833605311960859450983955671870995474651043162381551758083944297997099950525438756612944588330684605078529151514104048929885063881607761969930734103899957869189059809373777206187543222718930136625526123878038753888110681406765434082827852693342679955607079038606035273899624512599574927629702359409558430116482964118557771240575444945702178976979240949032729477021664960356531815354400384068987471769158876319096650696440477697068768365677810477979545035339575830188183868793776612481495305996558021908359875103512712904323158049871968687775946566346221034204440855497850379273869429353661937782928735937843470323023714583792355711863634192946018318229196416500878307933135349779099745864929026745060989368909458830503370305380547312321580943197676032283131418980974982243833517435698984750103950068388003978672359960802400273901087495485478792356826113994890326899742708349611492082890377678474303550456845608367147930845672332703548539255620208683932409956221175331839402097079357077496549880868606636096866196703747454210283121925184622483499116114956655603796967613993128299607760827799010078303600233827298790854023876155744543092601191005433799838904654921248295160707285300522721023601752331317317975931105032815510937391363964530579260718008361795487672464598047397729244810920093712578691833289588628399043586866663975673445140950363732719174311388066383072592302759734506054821277803706533778303217098773496656849080032698850674179146468350828161685331433616073099514985311981973375844420984165595415225064339431286444038388356150879771645017064706751877456059160871685785793922623475633171113299865594159689071985068874423005751919770569003821839256220338742353625680835415651729710881172179593683256488518749974870855311659830610139214454460161488452770251141107024852173974510386673640387286009967489317356181207117404788993688865569230784850230570571440636386320236852010741005748592281115721968003978247595300166958522123034641877365043546764645656597190112308476709930970859128364666919177693879143331556650669813216415210089571172862384260706784517601113450800699476842235698962488051577598095339708085475059753626564903439445420581788643568304200031509559474343925254485067491429086475144230332133245695116349456775393942403609054383355282924342203494843661514663228602477666660495314065734357553014090827988091478669343492273760263499782995701816196432123314047576289748408289117409747826378991816999394874977151989818726662946018305395832752092363506853889228468247259972528300766856937583659722919824429747406163818311395830674434851692859738323739266240243450199780994040218961348342736136764499138271541660634248293637418506122610861321199863346284709941839942742955915628333990480382117501161211667205191257930355292924113440311613411249531838592695849044384680784909739828088552970451530539914009886988408836548366522246686240872540140400911787421220452307533473972538149403884190586842311594632274433906612516239310628319532388339213153455638151175203510874595582011237543597681553401874073943403633978038817210045316918295194879591767395417787924352761740724605939160273228287946819364912894971495343255272359165929807247998580612690073321884452679433504558019524925663062048766161343653399202875452085553441440990512982727454659118132223284051166615650709837557433729548631204112171638091560616116573200008330611460618128032625869595160246321661385766148047199327077713164412015949601106328305207595834850305079095584982982186740289838551383239570208076397550429225984764707101642697438450430916586452836032493360435465723755791613663241204578099697156634022158805457943132827800552461320889018742121092448910410052154968097113720754005710963406643135745439915976943578892079342561778302223701148642492523924872871313202176673607566455982726095741566023437874362913210974858971507130739104072643541417970572226547980381512759579124002534468048220261734229900102048306246303379647467819050181183037515380287952343341955021356897709129056143178787920862057449992578975690184921032420647138519113881475640209760554895793785141404145305151583964282326540602060331189158657027208625026991639375152788736060811455694842103224077727274216513642343669927163403094053074806526850930165892136921414312937134106157153714062039784761842650297807860626696996080918422347633504774671901745045144616638284620824086735951023713029044437794085350344544263341306263074595138303102293146934466832851766328241515210179422644395718121717021756492196444939653222218765848824451190940134050443213985862862108317939396084438980191478738977233102863101314869552126205182780634945711866277825659883100535155231665984394090221806314454521212978973447148874125826822386023602710998119152056882347239835801336606837863288679286197323672536066852168563201194897807339584191906659583867852941241871821727987506103946064819585745620060892122841639437384654958993202848123643346611970732430954585907336187862906318501651062675768512163575886963074519992200107766768309469814975622682434793671310841210219520899481912444048751171059184413990788945577518462161904153093454380280893862807323757861526779711433232419698578056376301808843866406071753683213626296712242609428540110963218262765120117022552929289655594608204938409069076069200395464619164002156733601790963187289199863434108690320057966371031286123569888176403642525408370981081483519031213186247228181050845123690190646632235938872454630737272808789830041018948591367374258941812405672919123800330634499821963158038638105424578934500845532803135118843410073730605956544373624887712926289807423539074061786905784443105274262641767830058221486462289361929669299203304669332843815805356486407318444059954968935377318367266131301086235880212880432893445621404797894542337360585063270439981932635916687341943656783901281912202816229500333012236091858755920195908122415367949909544888109975891989081158116353889163394029237220498483752242362091008340975667917100841679570223317897107102928884897013099533995424415335060625843921452433864640343244065731747755340540448100617761256908474646143297654390000838265211452101623664311197987319027511914412136169620456936026336102355962140467029012156796418735746835873172331004745963339773247704491888513441536376009153756426743845016622139371930674870628815954648197751922077102367432890626907091179194127762122451172354677115640433357720616661564674474627305622913332030953340551384171819460532150142632800087955181329675497284670188365742534250169942310691563431066260434122052138315879711150754540632906570248488648697402872037259869281149360627403842332874942332178578775073557185704378737969340233690291144696144864976971943452746744296030894371925405266588907106620625755099303799766583679361128137451104971506153783743579555867972129358764463093757203221320246056566112997131027586911284604325184343269155292845857349597150425653993021121849472321323805165498029099196768151180224831925127372199792134331067642187484426215985121676396779352982985195854539210695788058685312327754543322916198905318905372539158222292325972781334278182560648823337607196810144814531983362379107671255017528826351836492103572587410356573894694875444694018175923060937082814650185742532496921276462424783221076547375056819883456410354580272612522855031543250395918489189826304987591154063210354263890012837426155187877318375862355175378506956599570028011584125887015003017025916746302084241244912839238052577251473714123102301725639683055535832628403836381576868284643304568059940187001071952092970177990583216417579868116586547147748964716547948831214043183607984431405573117934967776373989893022776560705853040837477526409474350703952145247016838840709087061471944372256502823145872995869738316897126851939042297110721350756978037262545814109503827038898736451628482018046828820582913533901383564914430040157065098879267154174507066868887834380555835011967458623408059532724727843829259395771584036885940989939255241688378793572796795165407667392703125641876096219024304699348598919906001297774692145329704216778172615178506530085525599979402099694554315452745856704403686680428648404512881182309793496962721836492935516202987246958329948193297833580345902322705261254211443708435958494433836383883177518411608817112512792333745772193398208190054063292937775306906607415304997682647124407768817248673421685881509913342207593094717385515934080895712441063472089319491288078357631158294005497089180233665960770709275990105270281508688978285494340372642729262103487013992868853550062061514343078665396085995005871493914165206530207008526562407470366073660533380526376675720188394972770472221536338511354834636246198554259938719333674820422097449956672702505446423243957506869591330193746919142980999342423055017266521209241455962596055442759095199682431308427969371132070210498232381957471759855195018646309402975943631944500919150616049228764323192129703446093584259267276386814363309856853278602433214105233076065884149585871819707124299595922678117279644388537967631392743142279531145000649221265001332686230215508373001756887779405293922189029424143891860902523020125072081914513559252448175874191530285421032688755719724975463913213416650130089984858004988184539712256278637424126038402626928051361641332991194822906711506766502171984061981065252133878916262149742374847011302186990595582230140544519769218504088109866949722922088405432386591444077613593583977043162030198483687580783576429997384823060264097533891101537850288850208875452232316008470588468561438287055426578280588833996325463499127274201470388306349081714134544089291185028874099319952275905464542169235856036455129086436256830037214489582463463010911271935780422308203367573822202173963037384430357318747050709862946814186132911304352890724468689732842917280819233086617509641888502351666154124836167509421386532027958735884076218465024752214216006343124636083236846164408779345151046756110838674267901803569874943470363501020585861081379083328000450979761530404125029486318117174817838352800558398999904445335622512187782107356141197355485008078033722598929661207534586689194387026678701288235883661632206543667404027766354617520034284643729617064606010906465199030828152320178953367763499425648462967104953266723853904704937155459977223244359796704827248971177536576290495873282263979918608190185511935160957384245746193381018864540398341443436533794465262922870048336387630526474342434263492652939493937651558624005989912216084504237590530711424650102655299280994514986083383571564960853124164235244436418839471473944496583057057034126813678308616528510619213892914048179549332402960640814505103060473822729466747251091470938852715189704510903960069811099490561638179486071758425024112534307738806074627942710452584860382311418063616144670592786423022671878159420103387312236631641711565532384256016200055689990584850129614652403821718135404439939767455202147332201283897294683888991005191291681454544002802167882207080005379644281146076436811762252658697119084492232425967729532174944633069141466335696546210141637869295979380854984963288125832241613124908276514019822229902646896039733957070812119028686326137009638968436489077956313426920368199567596428576484886965373813120547380940758060791114396835798478889574202010394322644725932906550201938457089314396776199419230289067663807121779719696901986559084891516381324373872236574715900584088615980357198551814210081812709096071968326771380197511471144465824919283431439056546492279930152267942565150539544200689702523323921822542038882844715943684624104551827218334305559448316047742263873886047591632964026986643545610882926765585970956603378896581991747781168854913408532900306153854396889935716898788575384050149102375541735824374537629428754826710372969543274397792392280461782749854973868350413491458156904982330874385219664224959847715814815062706953375070797976022372569401691461374860095711922469228633128182687160159530822351748137454909809152290645895627021926526821573140360451847516620129376490520083105472967144371464788001888492767297732235305345095500099492568227839118072495134061931255331151369899255407534880858224444053927989329248877022137179052502751258103252877702152267073091243326679210110418381501739688041273383675434041752960485760040017205524549427482219234334245813743685502854868344594789826372474263384509459695000655718942975450917713445196880141258838983675590521239174962863542990657827429051833901384906970752823142116372645404586445634982957782376851603582706319559030459884878893335522399761398761675651669293819494189702204104055268172558117235459023653463904099051025828748982910473603873010140762927526864852738425659885920252228789612974764937984795128415446342496152015624584115723787430082351815151255483594577612834618334622458482425398960372059218207360467258453432348303024442922663551805927135907926458375065236610158705254420454427522399655918830598735800263484619358743583256039455770309665487608388839384373260593852766040391273789411845700468215083948377918584844252865857287541308158746962694464141982897858294679010335037765149290471990782228087484538463335994139875981935635595426094920021730282219291324610755034159723829784846735527316719499323774546101622154870667279654356889082750750385194364946461236421512237418239271076098118331165295952658857274986983349418174089463129164070470548239619996798378868374539679750722686025782433366536376048673771131619789162239321366833518612554248017772967038503289610060749515117568533833292101202911263748484763456287411828132173343055844411560985666312156750326304287262340215248778463994174203213186650730369807172498498530681398098707319409035845739814534039663873374980703942427975613598554206180580884925369866302690447390838349456334676718973333924898623831892805218091285187433667529017454054252600093320411156172367368088284607647496901787959927706320192284084421978708945298041959046916619176371836587466193465333597502489729784022696453686109615430801440877469875616727793287519251679638698687900105304899754152761928390384470591250502517721519181962635604911315371330390311544271312342509883739263727815007299780456497001552069286120427670813732628087406296079812707254081876582464008952529687990334347900909203036043681831055435175824977675284303811721391490221569035451503210741745997033257588836022746502930319742498660601623225569817090589136874195761344240977427674139865890480005809616523467250728010089811009065805578250348897369804636718251689565258448927370134133982044113868614568727887224903992294702605854343762487477342279111689592419760893193225114890176946635066301166883795731595667330500768497190567470905412957443010936499375408355670789570337778370321074482375374328699166793180310272410493276087581996767531352745364535800721367067365699411257212702227042069567226340208296011979565359615884428002882707898499538280053959919917494069303743540452523475352859835214270471396676956007137824367641047605020174081896422787957053812579637376541631047638980190601858743867858812089653378519146180507022618780263604368519294452416168652942199116952875926940308706060386289333855000555122745730526677540485512473707921273149232186276677411300097049533840799029876219798525798368377095034636446448389409460950156394827234182855341941024839124776836861446268995517276017210563092724653274594593884451709649405235168641272028775255035407215490698363949392451498685722939605724396108464408554158559355034963463681123907851539352267710090903118879564105734898433771385785234851422149083852636035419102663667724205976410551797630607255427800647213717346802149366018351580009547218890244396064884455195726319747214318281976387675907783428604693721805882299074821345901392973245807157950995813597977424904993670795527508308733445446573034723401896349618212253522518707157169130095463231915682070542750113877671754930532451488793919063143540607236796063137084898659860266496345162140297100248022017828040214350228801504060370924148729967351077410391455589236515892113625962948793578570907950007751252346265239812104220432084979737199714688045451271985666268027554027139241939527770864407486197233608417286516751218338078288087760289791191900286340895738514132564429686183854830825454532705485640040023648389127800685482685995520717716168699652852961031372516480825576231951140724399817560344873246859759275545425633444756081243688267604099015388058364149140163145863939802447021142224377191387130673624313426131898140272148472881743314261346515565441170763698868857118202441272935554272910205267078504466957682463383931434000081624082786850079095974704954643691338365214611148983844618968759988161668298955681662038733610407062684266219716746123536760620181116114551066460054572158976689657257370009722049072247517470037480577647805014161875741284165509450172506752928904791710069615272817894480556262662929275351089070605997166657654519676273178286475339174722918507638462280281054636832384189980484324160842479978258553509844381304520574865613364790045667924045491191063455973729115937854067338918313155567509004447443405376827759035968354045722720840983290794074426480423852283340803333850527847864064351934635094412845862413784114356434520367994162151354681697249887433953129154475298072500159730879828949048386112126446048152797582262056499653208918037513401702823112060569239119425381155906602935749616545385592402902986508397949806546208843483800441154054815129449860966310789040980284024073229933141743202883478824307422201251926515428429654317180984917510753492103216229559546746189234448922707900136955622396563734449724290094610156353436536934322450615018252887381345830125159268242135019171242880098145823317099938161239062744165096463476639916668845258498282782933200831213226714219626043508562449500071733176344021264524887023055935990918328153426643910132149357586946210184843569567858815666441935284534702812745040933746856393062399159701935259683850480109744498112892029721046247122858851766785444468414690449927428507272926169460812263104349599680544672819493773082628797165444600320373512445373855641619556699634425532428794658853425688754301734140966410944348170917237011835445449938700910454196460870206678224060546855803736809971496665086721113965568318370053617453043774552676303432075652930078336237475888141059765387876335569657825810200485685667569840114955194674334480448424604326304613670627563587307331729172362126988603910899665413682818986955949457226452651801278442185531160371246500299426901571437702099165812157653439242537518589554735252811332195410596355910394762558574318708926759446156265855181733243081877410054844715888651743344229449504348737486087615699262029157072507740245952280267849972132416551111222482951675008148607902496676190427824042669429212087099421047053381576519296465649542068499257850353555262124980813257530719612931570822324054189599577963566003944845865826569320531238715098369723969667018744611548016810952905099664784490509541809986372822352389351398549070547399213768857530630551048135924837849341951162499016279757756444141694891216457024746830939472472558318298511336170455221048438314967260772830546096163718731492000723680765376845351550447398868298811833750514600244822640747969692950890572799458552301748447354727097366674834706360880354558055975159758681731451309724176078572216704487460714953268048254391300801342304850524495028714792255878707079855682470190570724315342405086481460863153219862168296875578761821173883151334076536080159717801720639067537594803642916047563317560424255157433633267016725429821100072767613486912253163513445740579690032225474336244373590076985643184619635538794060627347036751655973937702459851979620650211329438683403631255380826502227542954198862804695005027355198130905023718790539564068835671704811171713971818230794022222949682042097031703067746719182745393042248731952224218434673334681428213356005757567324992732670335201562147303962184677067060119549903702856585116169224129153317412931365022469645385832975346425179639488091603463742381677543266093151038735960096430800471303980666061811309321734228473748305372396746905078121691192948286707750332675765623877762106922959181992713914016365508744309165143096216104384981232284167897516967760174337493405437012038441433462911968048552405254210309472994067752144205198561793143425039277635448562516010286370725635169713439323165420117843466174251385542867592341587231623519139729934734600228091859321390885287987019762290607124862469540231628345627871105578952331805156768008110721206775971325862127617737662222649290244555883290644997992422449648585204061333688959255376258732227120904878638290896418205044870583080625276569012677470548730386042260283980234926338232098076426664291945681577938985721106079390310214778134510488476502280465284996513080029880372455200462264916190269178971081589375890148194222530466513865690433479753830740538708744584748474170230678295524740736696701358581850783912460407438803851246314812156925515998485235329242665402644887381247387173712320986205744549629273853493023556003990941627836049062092375013697355177759868150779860027636650142014069126811799797053655371205479749164709272079542259884559654327198216359928183932753080550927824736772125546018868719716646270247968719866116356257626289835921612556381433462103191579188179895281391124532092652674291214106054192301007859712355622083814030687437156356241630428390870582209810294150736120855862752370631399081647899267337288424998647380959175174541696404766458748506256536038743339929973226966698197987524427429308641638670490060513840613845790885524410920394410862706288136259086575926369358322558943973099376048975314348688259966542698303243139184571676607111639029176637536280373728618859790576512250267004233095263441666959315847610684427207819305320997552104927412149769190259956637321446415948934207024837995806648608513373269490303109445035641956364938778615763710948580960412223637089767620119109382011012376518094635320015904919404624982362101814416641771785342081935125066829731629919658521196527504757982147423632513427390487223108789398780286299599565587113602427931236056186394327904271642442219329178210219377938494700575438674954316766348205991537579017664937439661851963299565557195910756574392370283938952637970039189118814492432345838612966708830454850885904101504465894375639230531370415421275531749855295347885782182098802217338561171152886971675999774825587348686317189102244115861602888498603655315759283660884665242192241406882393051559877682075272759667838988129353998432249960412477828986598669259796483309298869473919357076118149362088771908395861619282498471925898153186794809535642227129813609624003227959528573392368018301829622800630214644812312148456560195984082387047742743352904114911724891171997336166506821399422921448074552499923843632605225112777410439072668862078721462551484263232470476233075241709810857114107419261435657559191043270729312928344523585732115996240831623766393970383483316622480110947567398963567346035793755348877362288517380930458021038700098637422397513709404944639442950091254885614154234489775154098222565687150452162348604196421067111545727644616093010337591264051520064888867680894200306147909618019482690086747289872697813628466054185366697685409969547854328744187941723495604372839844375587797380795219717058755952759990369219172140689053315888619175279362845871523679162379980376717704795255012451574691501714237044922632797724273869333720589379491670574255518181183525512678365749236104804577876611572624101910900110211423898759868989017422869169872376924733762900817930883407240567921739244384617661949368060452415450168286615456023317327355252667688380068322056414786712804894975114796998372867390845377918647882913242891563207911998370666677743156244699718141236145578991521692783881635283809768411153731157014725591895771063616148136967310521813808835535874348368723389221603034667397227372418947523619639280281894445742976672558648383173108431880484814854692490088282519055914354110879747484442248122036360539357621613279040115278974055098067283411300003634133936060729918236164783519098630180255888154885797626773076012729787228261350713193411341025607930525951577347424638361223734952881255482513077390970381451955925948544297944709516421180704977426079339395522806795754199135202708990931667722773717018402541916405485607871933782190706149528185397429439710491793081436098030860657971369543992820550819856043716152378574113270643337602300187576785338059934724938388358908392082970269800162070470136797690009154485764619981282917508171229339537379941839512485340905187785860236060106779805737894646439877656511183409571876094327470800684586601296808735981879168588290407004908457254503127282163452920169435658008227603047530377852153512078506518275707987343736266150005184781412872698625827755944131188137245250931470944692273901613975953181940505585066462600673221872282420934872582822524464117145017339324983217829898766470675953873110925091149208264765484781677123642068532676257146090995177368221222076333514891942607361976614988509297497247047901771692117338673558630674416600265770977274425840769935846468868623720391374629890798082074556234539152238944652256748272395314888306443249487981366405346169068655941814843686097921997299683123571163930317642935169843866129564124705044002861993255503913284130487744659344793157017332955535633732311078461707545828973778617115999271848064677929093529956484338182564513742084644901161640928540373076599618499834351750522249726905116488487507284431867515931391742306480138108723856836056538952147597309680121195188245726745552009833863782509983785780450579980240843441864259643480088888211215272244518475825041804925249387548134194365560589385728049311612638655177929317129275948658370395014837593331320293902638042133738859358988190639849372698803817717396077918704335492051130595110891512766619076067148050861542082149913076341009646057645149675213049825823593771927370906460302033981035472344292867359895076436181942005147915034953277296746590023056642028444188463212877931480317003578769660994826546840582765564930769688592971134126121753684184516176342587321012078123534622914877693250364292656478267884126295589053109931435221802972027127306759262347849710214394198289895976478916837324143979267037086783827916231350069378897392087206505936191099644554769975862315545272051813846646581016664708546561992831104177479045039580403920112711890506543197058247900578930676429385049046720546301501470831992839740901638060955586421506287026323091624161155784927562542076028595617272523369044099138823065110909753140287494105573660519899043744007444076855540410658926474353808668364500255631681598282741611492860722275956921709175936680979239650757684499587586905168980844072605053548208905447940665643973229931920243293625403421445623160714784852883302078351627520913127792909618830568170296476431721954372988442999993385835723900176277137338203965727546006652827398444408593411487066752245358907979159149942836946507110928665768963247230129603765720141589357911081959028892341336053175567527681186345036075810463571011017758747759221847835248913877438080271341695962027010466354196130614111039672587950160102020348137498903790171282965513521741883356790759846284309129084593993003680295829871793367832562284486727215200262989667784070386267553775209612475012779180665649058595518432862400471938803244459150811187358913001631858333531380562127493821384016892187131526021989251416554383949706372475102423846782561740007514815266976467891865309220796186609256477828391733424965639848485018890966111411531272723960466038732481298109007454249872445714964309121504268923583694207779258602937220195518262312593353838292964119259273942104708865544255941886561896388314163251277980293081625387297113565270875029812892791796713806215079541420584155081653621272281045578835010987988769510341390441589472235564980292143469576197750229264425655224649696708095839719640568163824302770623517122119064991226847735788706281901059826922459215872920661395098177392094460667560790631267611024459636539836241433424539094354464335531453548867207391487846891781368648054049393027691279927489369529857480795393459585734183664500570139183732751532861856226905933231404109531707586521724926302397917275664364119535513154181705516443869670945649537166893375386990187677318022007172080382860202180065435902647423187698508267941223168537934452889094078626079386451141473212895739053435515810049596570049120013887044136319710574030517331915898636785546360830036600755414094101832626329670817973095735835633875731016843506175922085825625567790918419196328362422751668867569671009756715183730881832194647471420409697644515541431879225764539021180084718062422744951422437049671934010045749930022382500228400895117881728732043209203040419843245376695085916560654250029978997073164125519452733143962391871838908857152038647955564269054804862391681717329747921734072843743880084476468358661616865585709541969265293110005668786962677830083433200118503810366916033183222976709303885579956590828377382473517757644282050908528372707287477184315532786908952537518168956384557607764923261603976347502906622333704433368614042979349288367279085645195906876492646269959598811228696236644844214768047500613106524962133217169233675544322733015764452803459079242638080628971856843766418853391290461729435282208909064553396428821021686447862592606607067310065583204544641909168417678149435570220325159688206332396208679776291992282528704385119920914242275420381472815753727992979315843405969418277994253242158604164160963162837545548631121008137485889076818716739201234696062299521622590284326900631742352655591884981331800031475025079256993449360464556986940744976622404044704004586401404533692552329437194198895151332310748863926042415118526953426230377200886801840201125649629252004034173503112189307766641273998015798409511273908239678337727431927408226980327946091912801883737612054047711781237159771571422953529956181507461731931727818677916823243079126407041772641406777188432609929892141510572407771669949664931583344755836063133784626996183911438430036550856828419349748142086850095406328032345056890936176975580462571962263372810018067201792415720107972424517778935722042122067535757005764105492899250475080031184315668208127359798285138674508500342539200305576041937466284384630387106528601958722227701401679448464347858804116725005528604931393922296165003633044540169867915311913902084772450923235810885646628549111400946201887046483583199826593566576787179538537524087442481785687229192404375960783644328851206702150712226596023090750364638965140663128568735852840250643807415166994143888036267744459502985137777161655674667571114163762952290811296871371856001505427451732818030671600549039870613624142169702351432749114964296772385729654454385400023362334683068656486518970938191890459394883324936806110855317817072236840009759118395231993832171262021316914682020021152720481750082602152793204899640748035335680796441768352145148858624449187188492935013540912992664324790826906945809472578323157096216778765200723362891550688278185253214038720404220309564049510697230722057493834344347345612991767010146114010241410024484777915353433948473517108024054394262536228683912166125034979660058697687371216495036631028471741230388377908266707197018937269697414856922152586798184512969598864679814264184332658674764507971691154564676991163811421719586970822758516383758807858576174533727276586267737914983510978360019994290144109039273268580624145532100481164300090299871279844783449599210700589250100479953687561212571737812151396770013337959461141753167074272427242205091559704241858424575278352280772557697739091284439919653520454884182642532038039529141231714407184096557780459349945256612318611962581939187616629915577509343250968581849293597680272385976431075335150284489722205750866611508021826538278160253875164984284150073107838296929080962162142401322272527002813395854726935943051786865856278031952037846440535962813831454471803660730222053585552995441328481911290572228002761624429436941560649885212260007337843074312759443142492210170156685398079086663722797976035180974757869840254117844882139576325403705584231403062117216228161186783097343803423943298407515529031487222949869840985765178647313636799737791982247478402964695999946002252216638813528648883798886097835599203320105657187708439235413660350508387678822446494220229229090738234261857776590981448736667759127163754454657506510665443956295306961123676489505180826522996779317802324958762305471603172449923572985710834684327664393850141980313440209278405499954218540148009534210050875299645162637173224208472075290850379663595633053153272996345241182611028936178721426021938376350316678359889670959338033121974325760030300520333234963383867107817485673119846024251969017036398980210644689770000605078527429898489573151467461897393808614224451760169362713478084109758951723977054835978984410168767249994594624654019809412010905822812663277894753884927262295012844074450296732248982120762126828218365259311530520538045991659567349259390608414749642315542503420632040347232507310817256797541339552683857894336713552283859875901674974168938058908999329069639880906337526036570117199894953562599389498307367803242710424905723413354569340628481807299874261262081084448911354384465902096974664584001525476337789892858440363668798194526260795835945583263375791502537160473368792475698855240003510484909855356659678932456024609112592123860270073621632153302605827128887403419943918950064253028133104886616096915091487577261692553152701437736395815890930396883022781288168474069748684514204110305910648989307101741491540600781258360478763282487602462405705334328685955154299530568753742381819449718482914298788381312100806152393221706222301564415382381847157634357684001759515757436539763794218441130456807742493582112210627908174131123462234100063281658196908991203702368832358952096969686524377022773223364201437278961857235160197999308143541663029676034283825385167600161326785203133410029528783189528747976748894000694989877227702108543591486205546650478895510897726640945918106141157298720325863376660880267518545172821988803555183494388674652999206509725767810183458734734605211895034335056042244412076926639895046503509751847835402568395847493326151084851119493297713729483071120202170389205033053075194977785234207315472456405938518038947124316652502513967901291269462577870734131847871026156402721744636822988872773694391725831662716281659890049866144300774752573946141642429750582619859814882107196132194367194255426291355416564281180743333094378470301575523390008190131447851658022080984937185796902606092489780986487686349075120549179404600295724016608012167802238180725240832742995823398383979004045433978185908465315230363725199537687915329102657709856865935706280157650732128812584264792554264252809702103125141947118436266531674845056294043219148756291594327502141470212187436138517849871717035153813338591160907168703199165531437845763376799836951551872264504931266940284831908230638422045278313750765721061919361825109850265753724808341297151330159772441143105894213717225305754134940269059818897146807906501195267394438759814690110933640516119928236755033389350475933526571483084511746906508203191710065319395774540892266484859689343784744878936800491144418848068548546405907872074512690725303468095256743900942072943600508630010851122995453551596367340199524720697806972165130694494313399787297500627266375769552915032206495804445341056672586854978495792892906046353810026579201046889548791448210587242342985714006586603601087039976063135031757053209175050555397708393609742737513392572067736554938298131437895865377952698899771552636597191542696577821767219470879561427531536178933334027846070362932039156542547741891705788781712078965823139159721491067805343902687323819916534014274634544417941205434328049562758421326807858439845202350291376757007612053982663589486607013519081532395784224656899814369160847662485080655936469034371903753583987015657943838077605991457900250737286514980949786281850215248111532353082225458828970802749393691869793537672972065277717847739628131728725067566379958648452423903939169664944392622878909177651127858021581413363773495556728864201091640785574217563989971436293624278292495778364404771781811971341582611670324785987043156931635210707362668194857416154264391022183411943236478195521811966416662830683989676691528399555777355244178669231813809141401705723762762548289728399486281827662822304382625219718650920659147397235188163060052940763468278680701160937918632283532728195958976608277942047924056754441956914702074589053980493989188343822339118472781312793242742863455064382547866676617993850852636875455894033134176548274627394062554275640430362593871188018363663134071170193597340796053063345659262050567499337862979165784566519407322986005107222768365593766243641623417928872079924620216959395684151706533337739052982382918198668314550034882358898387578476052407549119882325728436920554531295442074390324991531190976294954576241839856948857831040703680188595099398579777675791353272515026479935060977725211711814671271100064952097996194344421433110350941783117988224268733074907659157967486580773348293838799112749948512365129879587397047068980476814920522411534991627225793606735799096462965511687510020011179098776974335764464266948212131919495296197154429109417518010308363867680676347196245403580270347678770334093277938723810830489612150010961708674774675122613597474956457071599898406571058603854867213151864037020242344879081895881228255249165058308361998124735847296529834751385670488873767100677450646901653313926412254789044042218643433222051687316293350780034360104971899262901765904832524941283907790423617466168827754936443571534784485223208418739918961324581422421259967731691470748517187020658059198743749547105859425140589104435479734780007467744469643790298666557306345693129125199292658867134802230890707370569851451745882376437317145269653761045073020341933389592194831115441888671560011922412645239422166532658001070184905653106063152916638705151214733569932330856586315475663909369439875068786199249192204537386753306346771344887767930890675773388875392976263846501891855612173173163388910110478243750901865177696882584708491490974713380782901152636584274648339843443114857936204719639832751855191237669745004384035107606280390504688409526294183326451210859981390675691454370189022599531958613039169736017850949128004594980473701864510706721938809276073025115741976484355829289447809652394774011967652378527464951610723318265727733506235006034930681292093571389004407121321282369532270130383717165527828980349394087895366207179014066830522664458654290856996560340131370830000893287893042522472948921971308044440205849096327480717691091951345160380600191131068463116216849307199988519593377700692606885063917517523800316491000234858373682715785627380273832938120398080866571288299053227063913315387648160268369682047438106695172304072914285641113575978026841477421665734516402043670408961095786786447188413864262556220715213871852190156217408017764818807110018262936444053051763274571562538550894797940268249478406259301766851743494770226993416872265580395198700304636441851017485230932281579833179472133117778325710799333565440949304790379260646727093020172653397716730831137624284031805143175575691891503525060361079542250480460108435280665578023254658679017618946247247573131651209542413100132008369047364165319853790514948965875010728174837086755365109294661610857916142739140164261109405738215571278005554036960427821981916149734868453306194177482148454599841800377065136280549404117579034050975063370262270197403754496106011930855484579497919575285463608949198978309057256178599859653093214550107833122342776155824490964555482125947833477860877629308113013805369250762068406132233294052761029094218787141281575616366346952793716157164694262408966023104658944120991664949062508856519774071638580061762505247868775545376429648617181620882117957225354855754672736290091400251467130172685429937186091083607915482678807005161282482183834573778700962752504253564944044304881200624645053574146250462316146137343930624589695166816900009012743806568877316380974607483832448471476224592628031548305893405009155501146669900238617084584290567237053687726812602786545533267863120057890118514356961541308514820717672379841260908720537794002798311061075034886504079407392366517116651712625316095278743906128983657011968854416787975954326562928044715676243274294477187219552724071509266777909672489051004985987425196816497625858160407295727733990991995661138092090368803342809821715773444330055490382289873524773308315104408819473785738436466844772087323254732837200499870310796138033173891711195706973441642537318132986420209247333130132502515018285489995264683725856369549494782040706757380009610998073507688115469057123609703310391552677470932921591217895802553355762464966432575924382782044176869653348659634993914986261139847908566974539265919931267161340701775971400837796757121393628277035626392271114704095056536322204531002687018076444462481060768844860491995135167265160899227179263059250636720839576873053317083307332577045155219182703892518702835164125385466614504022625456066553081102028238562620957989978814573708438186198150847323476681890256264428554538073387204865520531136806698381709848409647186073494714725361487135139270928349644492149338058943048941911812991168965602514271349991995891786149203609111559850894125658238027280279218627291965954442780796947870130521706067136229616141501529360732361877226388085546579500268822821353498569806810984543933373113891781101897413857244574677914158161642430512886960182760375156107023658532697332607063085096659294586650521595203875500086136774572119599487916066259875387398283805517679588532479331468421493614254852598847878680353487851235667458467535255299098221976445689726239033409412619313350061001389274457217438842646827715417984701679524700634807058795181028082341840352948073174801245657209392962316619114734331084671575413435991809837974437434264442988139786620617409270506793101860875979513302885932755545584444964396479482817339620032385678447201706394798910834831026851987446651363878915982646966447765679986130910382853197229018802161165197669737060704932567951532906076272939086925802787884417127155288957790775094623773951189345354675711606700617530961080585498426749681990167297374915659380085041974651195996489331911261823734411731731024097816700916973230986389351015789572555088777410794240717344815892680483857274193267895708502102287120728364301381969010336227892886553972107958222479877046323795468244003832149093952420031449916255849026186781606029603653130353549470839018598373913240912881598071797603384440236383544022909385280109259344942015290249368575323804307636751023829935792131419503452607609778290947352545772986193217052774985351638712074965100705160259932099787688505987520701073124634758014732783899182384302491689000622438581286294342850711882402238564480253693247805282364608938240402599610637123849259931196574383169060653995690606823988655691709578747059269653149569501720913638508738797156249932452814632042123543280934897893663122157181080254013209676189550205604925659240240657655555538852291227145021880428393392114070674817906296372721655486720296113957026402928501995561953407894661051802928180355733708904988300101471096225463097420340853209299367790473611488742647829825696528658851674786096041986579060857836773395536366059923987750382930377286261107412194875349050559108555236933470374478198959105052354953157442664445631459865854991665190516347987515656739667921481825490121320609871419911977469111683337121991522679608127698125914982665157102027387120699487802931415331685233050866882021473242575556249878092849014852673278135321730818403105060482196980019673579973898168392330754318433474394700633696386080077466906249105071524836205035172122744100452721353204069013509984357639198356778770374876669559836409147539245526371573235421387697786589431819872282474021432045916423505729594587156096452238282248509828978324579174407720565034636214732761459488582780651785828715701538287778471287969938738787092464887090821699717799823503990451237317101380061365320988556415264355889968537255037829767960446249020048793969635136380864080861770731225669242697613534653964520589541429738979101542140454504926147693231851246631078753449031960637072063890481632744706980233253887210241035923101942384333200352295068416655009199730502323510449883320093182152201924860349402967552873201782116280121239287626286489005626863942970453167195664048534088631941705570535038604624112075899209977486491787632937004402164640641356448174698618716608130949171807004991530441014774625652155952448155022458953863954554752732355676064687625138579581158663686593821786514517430373461657532898134097604051674742934336915793035314463892445209987849763760576296818980478791460456808396880526096626479262240184942531330951586605311364522694918929709230095346041626465198412087782311512150100791809314142295257752424989657659790099472067253470413617259747646213998708886791057984854235727661323381876329366402745291679634650670891612339293852509779520212317515273813161198670718415873193775226951879966567561925206955442094308400474842163825943172843522171275280151054228044429609356426701609127369783113727117086823624592757444467903935420461571322508846432431385504217477834421698043508582295927436495923749450542034567066927578930924788017506989027336648955614098289904049901892331132032579446716643873731874774112223401828929357727231648218545896723125396133573191161751111181996097583387395938010424745028062902370422050478519719083131318875991802431679717321635682426592498732571109232877944945249655260405291073188576736402311656335543297059421221915134425790576246887613474047445490879158347536571047931193713727595397505790093525448864870096623611930528041879270374709624579284886221048087937420010531448517897698874260852707733874761588124765239408116523387530870080613281384033560134305941525547905300496824104202708328859570095007525269624312215416386138443538334631786002590100953562218177873256775039458588741267498970305790224611359729813760255467877639973695886273460732928874925361778452637531664245508445457984557971932615040628294950069599895024885381030696943286336947121976090748411685507031740746819213121513132787490555761211819259623720033365812504349431231978296386447544645580559961361987940158977389625060099386921582429182762084272213717720366742955569470519163842031702271457516243413268873369979633440697207493301299192296087911852579769656466753526118330141492415800323463209196324827064208697211880588164054508748500461580291049120123296807537561744942430175727604024922889627425837438783515058926513621780768188574004881750283600870069849111826857455732095764600676146418910502372448957121364905159625187037491705621269664755117417353397087881065807278840878336668674950138249579869599329308103265226412878813706023903251401981245680900685451235027421021067002058043092046945112415014832219138162294496618075970741281653820921783708919411397756961102859357551303927638995428756561099262920573793367638241253753342603942637461599016036138144383347794909220198433020261170501012438738700118546987890835783028089795038724083882486417315903625282608830135410104827175934438477870364160821986699209282929104785006061058137147159423087320087098769130146608407270107291220518602024207525543717147489733902753420317634852342566354712499228055731210920173780009245512363914903645134121944351948478764498502893039169035729868212205965205692115138795297037544347041920099929302781042828072823724778542890192061073939696156759305072649503151491797730534265819777106794995565803953061152615357913948525937615935500598768401278533659476586758378532047974146726204124318147599653362651196397260685046028276871994633468211187660981215237944355537198689704512890732018519383692608737708058492314644371493154799056094997111406738550409973082824776640294881185828135397240491292772133453215592526506806894225496478822607334666621730030386474187021173331605841047912546268930115374212701575024742909195596313881695795898350175891131613530071804418059162704841639136712506159720598419883107458549506317220820883610130647028638304587818190682803895787588119485751655638238879128351211017971321337335587741878946239972168146862130084949356853319727895019787918954277413680657013550432121080747469331472325912039829666338045363711465402046641545257152456331842369796115970946322734748743127205753305486516451260022898898875640529724700269793962751475302943631296960473267795252829303109886937615597759212644401739887398755621272932755385195078572917353356952459115657688903753760962395027506109726925509814825646648465725411900119852767566145761832868928208095557476487020496797905991117504937316994313786365436081804581153699116072564578341157819143247562212245442732602804460708201762279505213947658196573272495909431680842970002627448899897019479185024957803257253905996963312944045377810985431972211637859263599453940448874068140959254239942425704834375933192732905950968498661492071549845472787663849668497523970298323404")), invSqrtZ = new Apcomplex(new Apfloat("0.43831154566767452033809937113724517918329797653879412078581592646466080448431552635817577776183752602140390120485511565996678561570417671460338414022447635348292881303321592116885117977991089906328816769108576652843641724078240740756330975654117597697860252078371643026148568319643017721235202767127271567977230498816951428740242825881300946335387922796476382481919087748230195527906845189297121011239814379097652925429697423695064745186914632634282936290207393484170136730797785283485138799463474853279113716617864951042534870533131769946790464244641397572446340701892225335365509694462646376741127526639598684566767739631852943419183324459311709988810339267555796922783520108593085399113129960554191286390194139776179179090480534351586148512970698326695772581093016744263589241527033204910534116802590312751892987202035313724429606502630963993169957390824710131749537737897194153370174604819937797047095172386230150057592275565241840374237527300335173501487991093902079984318185613739139182083935672230815249514797949446736522441626064496004185907321063000297695670347944466607747584991518427873595322396063266095768894223703239348999714048603738668574161529893362300091247525701589531718866460048500890675066357049661517394708143649732778433991647001451719454055615954417821771773167609542389527137677172386862156197498695990303859546807406391737261361879893238443236025947952915401454555892580695878629961187998700810172520213405851693109969322818516364104489021155564940317414567578908168815615723387056545110669137353631325852123554091891547119191706738068525338748567310984208004965911499159962346217934600269269577059667647869472021508158784396911370764751820053692715602286155756544552585654075900466534380245892003587563345257988719532643655470069913002722026685350551432589450585979723476811344911403900174446327395390075359699050596256432240639159850390659526881966372081843575342575213473499489423703254552830908191025011574595487178800250989237737086429701580753626633762649798341606046916010776483559822806490613248057836779271308802764423891143225009312691300360979752432004109221726811873739633115202712884839522670131260233533943250833201496255922201423035077079576101240670226591766997822385374378141564683689860716230399290851396062275890246291621542669672438457782128177433057753250494418064797134577801970414713798715736353018732360488783139871253750258768445369342080873433874475624241079434259358682475957005249217995987931458794051340708988446252726387508535210985718666570158693461844344537212025568572013410098153614956092947896074070295884960244487791054918316568359020237426909441630851559051064468521426629786792711072931764859599508287626335812374622718992500505291884322178613975115196511762324315757012379367029407204376321791558526847759877243463471099220872538114500533784151460001933002994528651184489453816790758609189499509953406912388544594607055964433615292544706770412494929252505848127971236261344952388149399905961911694732487849579771739757299662672820236636068249431933169926580181693034784610208124366324301014966361460653504626917197924871996890871720505312861396666731321916988363461909770075944450373811606111953766384442709714288134559590674600431323734465821372658066913860353327855393897874489382777281797121669169324702523395905998490456347043934969502821644638195407260482392638213923057971578904670151618363075092955986433420543204238644443296271702541875105938439192133630012746558748982443824588117799419567736364229573004844879114980022632076411142899182007245260236075878784769742124781994302673634484999456078701971040628612138274414759345218985348915644644155671071741786003037908492681502801112172537172403620447757191581334375438208343557190463071272522569356513899506016096221333099821933855236733420052366774090997223152379321537222956504615365289189602574027558067206627440834892592001540541185389342467720728858097484634522715957454540578536298270685510532025565479260025225058296621035197881078831706652029454656375786101832022121719464934733878967435270433735246129793661820776480026805319571035546240254104582391384797610519950542536497607400886579743259776398238845729335881797595334885296158879108536690293133351491840595670169832920293407826547907570649061513306611950166198090238451753947143358545639096750119101083224612154038958503033730831300022361891878981198054175297278615425236525429067094111694353729409258533621730511621253577971662142402310143591944197661743196798125339279953596538124065179735239549374664256712396757195070543124463497463984689731698530546387369708597331987692619815880161344249894611829193603559318499893083399481438901493423401907335862418830562549423440126785205643437257297976332802193147624236158091138899634093141863108493072856979478291251659294305977661831552063865026565321769203111023650075212272439907693961328111698835113845735014362562643135085362225893267912682366554730120394559381863451868142844083904686274861670891297971834887553953281779930787290842706469039592882360111143567515568558080446763021986380295621154759959076997697916896976310770419642315110437363865573364789816797606432569985159047933992366730881955695741345460892995257660015894276782351869734989720604229890926375638345063189645831367269299838784242720824776585733511117474575189140953387936266942453741709262061073186841349614147764772836166225811789222320646698495828038938094012321456410289479707102861758861202344805246461991425721902242822691549297145288744762372960763729970889288401539554124377600995553087641561846455032759995727656599847062810912013810584510272739954263572594049648512887028637867188769347437195844027342654954776680549439833703895672290926035992302072061789481062822725650064823768027195808424005247611496975372283497144180119255345210850955573415206229323244115956298948532773151713230615912742843514202361609010068747243033545979969243890020428485067594103138635848373589755925533236691954483744530883848820163367720408560714099548793254274588815773359489852637180859703875632926780857624446079162062497933949981423493718920050777513815034743020624710805062984663346811718637093599416784764157851417379001905748758497611208007410427445069027931470103903443456115485635674595108167512465239559951962962526889314627486975530501669827552255077735020616914605416712507269568579984513773949186078051661845817481781444805107204262301265963719612687697506995705630481940119468553962020792263346718201160941717777525511616498984391294475428505099808437436667751939070158660669354563072155116681271969753960055457242461197888797081576521281040685076853411754310459788199767415515961152459130992176802409945989738383901332717760041799243017136476063473169357663686072936851889668712766906749956552605323564451682381219509757899487099959404982769104952573760578674311480654134308346705991778318474399520129249815317780395951115765556370662875024121070093771281253900972784297197363143964169659271634244705595236688766502610188451497591341885499907004644527216050390912837431655194821203693996265603568520719194131781773736277081594756869997648433237566169053762601596371481981229884525115990557852629523872624475957988765036238149031924306313062403312093696158897612925978521804836060179709447551984755094449037849145699730886722892979135037235395977895053517906034425480133168633998173201123735107624996193579757989650246160053029484259020718682961296861626399990740497683895445678444356914451709601238394536965354838234684816009238594043454806127142801613983866119595177520667518392103786334844341284555315608596016572423250361300637973168096711228521475916075644934235111369093304640716669900525924169633982406787253724626975123179596108521138421200318440536407595705433799639314488044454887626342291768972602228255558098209448634969240892365757961646508927833422888696380160900766602768157663289862691834972385218875174288270685930177298336684062972970541898180263193230097183995770727950288538941426290519076922825764265905481362920087936192002035676322208960614420356442480581269313708865779293045415742159603657854148621335906269187462861759442493933217824542298337705692842314676227713142477975245116148894303504756844381384743435700756459411702997153291099596679753135223394724750219109416634222597004697421928302612654694004987653843310198566832892473511268714490057409994699556905985437519334823257600401871555154414864205813483208130683060335265061259917063562719382937756405775728402459380407866710922317846460285330638143418923978022729923712864495950882195910179981247672974085838890283736021046222238099829972144708259819535802972478247441012261571562559810910160362814591063267754486775361393316097662779629564447039946780160107523944668236577725017496454601866877270890733928105479829258561467622518176026912009698065930497759977465724210373805890965498099529369202970469873750493652504036810908521979856037301889144931310795656671387979811041112261476515536454924590784133501282637494990403977805491103089855301496194865618092592030294118700731456847976201965808650244069728149781791510952359226284058420489956431853456100630780195446282582560129394624567811599526125269382858320049446943783528920872433863364244169018351444415122067898078755024903957125010630564669086693808378024611732372537046944542853709789696099988027526696679350593569079866104948562960959462476961696960478534440369427340163134304983188676073726564103698246174273747798844056762754484369288011143926349326129646279511761504187976476853843488042462992439144488927576643076097685436214958270988466948457177859970044806363149322266801562517672329820671502073023162402294132590383832908409180469510697090305925140806546979320873356877700945189293244054006492028122397150826381989670232220643876028409895440399738147024992524603682000813230543789450632650953527145898011085508803829117453712806794326988990682767483670970421518473044162255108966891045321053969547011996469360628228973262888571502581007957330860232034618113996920148804859224929233512140530968394777941525374906404477386768236485408027741964992866833839418482635398593315243663855409600373072941706596253401952569515194618391930579800065627451303610510257521416070631681252031484319440518193636216734321873079468802000449902996533961953525501983859201430445629946343004972921652867340097404536321409172082930718164636992702919989830198061380101014140671056774565636690007577121967232679040619084558444244480112330539212387889539157049403297187406010008143004790080330799816612758529280458482114761646223388516521951079786457485132260079509759667301274875895762493494852979050845521819578131001809685611516137296262241698405839445524504826336253752624720400956097652191923738462272845458142675440962186327675858153849386070017569889845357495653630826572114528855640455503204467110134678092902581993271198000355587780639616511390711614776754706066390657962022417558927698209667178950627135984063012878090613532850961686376665372551760029626454677690264118265718354289063608596464536564528257150002991247007281414748772536551905013356837040342261339128533883054220726672778298825788510007498864867556936893095559348578109247969926860611309225035393023981724448920190704020928843975206393687039753857651113961547910484215650865396761469985556047728263150253136993011869719695713170277596230155797129636271367164535745716257138055845970233240417841238784009491291879381392380830472192937572678228621083779718723611953902833794015614011009557929687525370612213353234958718409687779694821958373946508134881918860184484650369439388053153051268383478083939929582411558305457388684834667981483317666268571711913584980615581910369067455862772334522842899864776159884811870809285727470882568006923498598914008897175886937413752096103582961001844444127980540353977799835299191474375438662977668982833450418283677997360239335846736009872126770173539320799650438898573120629975544150496047914134733859922187384762107637889232165989782311462265669437027255783349897631619340904530798660795846249846780049478064806658577469647793272408201003665109246338600415231917424187232816949873572747425977719253433184818676984537938883069311266214907736362216107643048680977117435152716237536426600976572495272369147584452724222443619258472952651385864088408577082264048713707172568831788346069339021091151320099734325971796790371616877821711470258264989582624273089885051784488610562937390137496186247744144754065261670301958183676749467002716939115928207783980930635822788657306441222147274919388058257520483529132691286140427323251821222330508922688370284317617320652178600193178482879603801698577213479783559038899279957016183441597537979034039555810201540536390080684842180166699697835947857463230775469263990335774529087246041686183680977406498850735316489140348618294039714515488585696257215080874536373762656054868265112297748865274692155459951207617341160558206732618948883984028588605727103370654370781412707306739470886264606009629958245379729893218516761277519906186825389038829195404913598072574881089701648051982630812429996020776295056277929793520899659853981030078045825473679270256715213600001634531590427759396172956111347135115166712396035643705325005650764541865669799173601255263443478391696993185185199448510170431239680569016708771943443098090865402824391647684403203186691064740879000670612203951871650147731408297749510018208638095745326855988661538609618692257320779429123330800244320105136547453445503145384908484989524765836990709686376628650694463937691158658550950004090776143965090789897173178091602923092424996659952502292583301557222837004536536506602217996193541664454438190977068911576318681969374151437682199169576807472788219392285684380916806393205689726247150698581882081990516188616682748326751625856126710329753570545421878225902905029214744698161447080278377373422025749299844880401965528115549093950030082862044705276619580355871826563331958456164563268683289941209916705735848884642739123896726909222519414315007315895415358266988340658192088776121249356276457445375035411456033505971173642321138068781892893727661531756847098094708066720099069435179476439607562164734856584070390364652831812796903183517105152375487940282351286658403333926995450062867956343273480592901044586565377288167733093445044431398884307349558814747920300411640079322084779400740841990494657827517635402733376762962369256420606146459001541031166441678796051174909914401964504892237086462603630248805648247484963599251605084742558705605574776625202076108848945283957495640817455282294166926971519344625627788777009546244997653786635797160309218059085327581271208292861146650363678109721197860913843296292563309601322718239288972606375469700544656037013097679843538993772111492058978745580811345819051002346623940861551831799786529922408406370434288017714160023618504084846051049966060973919331280038211749470340811681921334876873668076868041533514874462650391921726770442384976130205854838347877432637414751063370393855276688978852521072716829438037978261330420056982061658824660210070223997873475980700321714441962317272930533130745420811872326701467114270884354495678382455694118660189026561983070129466252330771209296975913657845763312465658424452980482843117522904106734636970928733283532716352805640278840883605335579574064224443924462242056222138744899395566467261316516345393722020141055669616789530059586046677289240242553072826138643988385098361682642053716541758268735266725451377773519700604680497085104363979655039534966376178305728768303682123297978546002516858081949160173892407364554722125939187458546157581096225447226405216984542723171441858191971368607331539647783133183121127073881212545279978896322176634354153417945613520457945608156548579291340467061378577407161282190851363750131633119875460711496243175311584785383782960534964297948755733171062100082667842680493202207628704116159440343251438709793681702896208612886816219867916684076213418394074830052790960926976099496583356916470725385720789276448422129501738152700112108840557141665346613072216226648147160328747889888313410282624899705163590948331673122350734756426577815800952656163703989170744397221617169665632729327310762151523544828471692749955212410504191779444493728424363763675901198803914967844847575728858027665480558572226743699624080262651118423113192672525207390765565215009894437630695255565533854539344645260791248350399388483069438549855137205166230037908792100933218319087437379861486326997851376134390891231590274087041488758928997592400195714210610944430299266543305307269927218984482045221769784688483382949547472804472181144237969192904171569443215016247060036997723184336907854216361381410198337840198698630001350392642725440879638237881474118301352161441400921000041665315848556448116840516352882271082656493027513647034834354503315339440463078828813005268551943682532840305661739039440088923741399497945001219856517738202419039877174868788793002701313836541598711377078987189301362852147001919361689514939761819445522443205617677564611626211044056010660737353883982712741746016456602891754332543548240656403006067031544540489536609283382572711462114944993146682337285944388210233424487235477359188015171613947389762577962548301794355547745462447839992428382451748515267827157557783382427342752425645765658386423820543626627933624292982080472529731079553726648564225807412814766143976589414489954763311924960736536764607122221355240059962549287492968487280844303874151105728674406751259890243652236856834485968018792060377247697662245656639984698938292343016984162488575446717191589718229321689478064387132402097867475440858033373679258791760377883880920659552837281078327045973747765530311633389837718928212044287144427910536810818548463601827167606712651057845458198909581911458766985102737311008263516138516933291064609961947142804724194618577158798682042188763783394247279363414419116960623785687819154961461693845253886659677080860393922539831737971809058614482766308675663814327359598750493550119540393097159814512957224426478989297708002711432885879711251342859140873795063926197359758318417478980332759986050087855212731483585955118514555140014695338620073641043786195872563778342299795171668881722638167264521351356876732063807200022077460773884027979404368976606534475551319551636632213504711312233113138370691399641617729829090581321962793209017514227703343015773641434837889293393482935428498762877731201767346761049257821133014296505723125677151529233026924104018373377063136247505074905733660787024891048295812260739607352621536806413364708882852759908919710620034364437536256044811968577474628694976969884693342524551124929838223175054638592222802329805549880161627382370399150261286484675201323708466619392304841407783095936043394223290635124930672030150601185767686939172433281711181880754422892414514844891332875870538708777306045119702885451002860073466128814879831100979634628763744994639228729533765157485987784850617356761704146828997018071968404887662891524597624142601049211671838205948497035435052414681582266657642358315840787163880229247366437030548188401094732396053589090660667964350093657767459074565009718821515707350877118244388630326766405211604473864467447728011874530850056077806743077971639014898297273213371702645666024905229367139706477406329581307765415621635798254835179457673670697467626176120768021645379984472072514892366235647576749808523407715197903273305451274423079516159318746341156258348851427644661899557134461210749336726863976138561291743940571545624894315354387090024833434264642019053501379707558736016004930799111331023355028406243653294419167258857732592389817598945010360278213574290721334073156929333550785763292568221628024330973482885884308709824257910416515324618964536582830418046126665211143282867398053966629122615953248486909004858829396182417690314339773117606170313159076709990169947676744151335609045979325471397042901735288812883812141548626266631519406018047887034988280643619938330715735236421748322721897751263360444925079516237387487712463568629905033770004785212181667560648268604726791662331754753140213391280473774656512414839147973129162950683557747717927808531004451603697738135176705686704668353550739349874950008640029807681247757591212006000325640548213841040453813346960645241157283818844015944585622286191225122870745775129060541325368745482481284013094257657401353319012013899181286756202474659299375247738359985810716030156211007946299048350576678330326044314018763074348313709116552539285323485982443673965116936252006293005826302716629745333339268979592439476349065649128166938878496710168365955677767184211589143972471467022374028363773168485265452072132720735463391360487030457569750441353210031374935543400761007472884088509730821821656034480600057584851933480111407287982570574914017636281761484700944402422938444895667827488542066621881223910426228889726772472389264264424862395283469217183958567934757371366879439947617000656152952280055326914655953610189653569044744489539227580403595897929330602579707322451163153369458895656149361001958347391841290439435836577964930325630876814127265943930965836664342544061086653412530437272870093018355700930849367003491765590216557065579054595886101839181786852035534885753312831294015382672007478261284730920531431234917448270854895523179520158631256128274531687388363964554409518368260964268576112034436249682744522233806375015998398735102443912189380760372706971816576069463585106282035792480776658606234714736537320668765225046588263030911894596002514449808736375331172535675484671778403939326624504027631090874676498248549034731202295116215886037097042002806078198296011810142028370281755609668680271775906590068088377783662146283545190327493577090409334491679337070370885602925165076744618844367775053243481118264738404314308080319675322792194088324773589695426732953425899295400349792723341442183833460411041600119282631255884293661122426444783992799332499364536044170841499690698034679190595043399802381648598951266963248306191599869584899001986041693867684419410043011287574785383235309603136004096797880075682091737454124964533008719280311596325744348046922877853196034559192773762235312636545432404303366682301541180728527410331265625967377428225936171468369726581825140306881560040263466094516057037466724287081096906237985765709625857165864611731974397444552912178520978840502780358194688456086686168841918052083445578793649552288827363972699093694978035912186545886297431431126761386691338481538167639213227793834064298864415436718630511631467117006355859702524452982411498986793819643801854709264430886422435623791676561882119621122581228328255552446247204130242891833300900914205816084773516361869631812992047296090773466063336397482025027509569015207957763321374686027542777327280801970195084047207923110511885688480809874417381458626034800132889670967519939098144472026604560557767375726602969497311403765347161564771335507425116606790099511591972045291741899948990463614087651973550868264233549418052011556049832280979185192891992043514045970178281135092298846903736060232930901023939130014706413013951918959322138851942675032277285884556386909757219069172379080791898010912254759841772799676796291493610012277812179493775454318940830675592935484853547984278414271097451840539379190047286267532487319184401101964701008267404661896595490491110412881019604951673635496337588363088597457950848904422978243482130662042184193915475647734617839093825191507091612334777516872759608213824450534217704540087297906933079306454920656082441968421781521764283449552539362983320425484005259864384472297893246942257736078719716477200395597399321545631757816681783566176238089396849877880116770027025007960252428306475088981902519926830893849584396455090611735378167945508507644043679679201230576891277452685998081341196357107460736280550132927641306219597600171130836602493546593095297690551521019327587492624938577798669663136504282628365426861661544309863663500017135040018816612060970934384318908519401170496322786617032129346772662620552197405831880237079466793337441972224223408218237954679021559076256303124106223708633757559891025187389298563082830464939487766453127374286089068898701646155174859746172943073294663324911202535403635648689827849245216742567895616331469728112661274654439941059494410782940566879493170398258271216927906158230984742626380674728793659420357634317187461255750998659996562004004863749747761224342425899348436215680587267171240539255358373039040721014417480296880036443229150063511886593628184353879284769831499712592524463062140428431853957809201591629125247356748672973267939961423896730169003900601320640747183936530790112498002572863335980507315439403994826260494892134005857904836658373469590298359526516012819594080408567613933618844535621584569103891277614963876951861301193066622380094245460274877989551595177436862266099035491220700457760401389519873457232591706205425719681762671670666241788473372299636745779288378747055955166023480810699584274814498097384739376607489557147113208819198304116817818355395813376186097481676229445488193193412808713584339865509774184184361012877909627874445080876602139558065720987708343009908309448227546305767376805381319511119825286114613461046442817295004272676229217470603640785836243823168964183015355490082840039788136626162515158407052041105394717072244596822550972974413765850615630242354369461044235842409395569698746143861594315913272113285422215607043456125156230215853170026883526228200641764777001834205738242343617673849962988948417588312059049081345331010311961442613143929941874020276110881052987137965246203989962053436192737815812187546813230523915561540429367284767973146263706554821484832832538185630410521394380083739737762914539411658265231915758515218392780780855726391670222605791025262690412976905998389282769074324448862499046053572730149003519839693367668214411072190189938763105542905418933752406431054308028121616850569542467811879478288549943151458349926617516939840429776436038131350352212946498245003858973667871321816734349180444300910783531956480393158747720449431174218787038626737701999425821957276857987872448537094110160512909029794020075314759109739326489042917523131329031621476431919159834680824936042721733237666118011961534993927600711300179946900652915847214396426393097401659750408655089118857601340745400005921242111594580850526965521612497576666222073775694198559376060042209253076682674569902399639335568424885487784444489219719151050194436587512911619520917137514538881849496013556244282927229095338446760561149061267037739965331070255486347575072134835250039606603707044810929676706456141074884036295238992742174443601955900026251728683384124525945519594767497413520215888912437478627004274672119013087987335000348963780348519817017221317137853362512190022044044929572453810162750306590197256499516828129245072420336785979798040452650061646903792195414626007391047140790043529253147495090315666332936226380439625547172367815124273899985209194015604263660696941281220464587763986831816330329073953888999823011869913962414470825159872717203461802057611813409043703852488444735991689007351340376491249867530169091774681556364644685155325329501911686815855958732686522359203343922080034762818271287113646735943434897257089848457326609157264195880403008365660665877199889095013807523628441554216307891389696652528997920102824993644194329896393733706807451760597946690722507422904556864414691363556017832621728694389139097652647263075465536532610077672855284376067887333956323804699179369403876409345599714498691010887562457503369241245814049926755689650358212031517422210762657604421635503763023641460988529285701558197734218421769579914209870756547126082885510921907702136369659503679323160103481948565629413422764252333255867745659296949951030378268514531324709486332843955640639199080961446284348490799126949602496352027460806324929988058144010069704423485048977263954967852707644647477180421710129192377647805170999201078313587248700614018903117818192875007878856880599082377873633567631463858615375471470895385294789254581687003919659686372016097335283271800592318535258328988801077096387558478084750034250444631883840041339017158095394281042572997871837328157056690317801341701590140178116084676778003893687814208726242342871906753790404153981290401899534090996246387196577091685762995491611529490135711348777526781294617542601312066414506063978452717787040341630116253906695544929647393936394569528518160545985715135884025743042749559403697019247642793850649211256165191514566939062856932626514506966806850632550415721694884720610268314115273254222448999046129784658539255955929369046001584365714581853488573011616858332452180934595875977963500915224004226148206642863826469646318481872276944091553009275880269121837914925391596570144127206650050258723059973862076974320685139055629482334163696066522214349002405679434179445354128190226912210320260025743373306033642051134599514756916860763868825046513141341984677940231172418423602864030555428904887996780418722790922096827818420540795522342867989236262202091183628488641683928229480890102011419650250227888063466734127247036737603063736461546907095829283571854562140609537148259424942190762053882092591776712257271052083767500312629152050151222577998998823849688531175709171826270354963583503524517777214825200865340294306762306408578160200465474015651603301456531789473330419242936173877330301812671916470724651781100802947381403463873170108723305636634991149650271363654714854870951477532526951742392206919680471374199304867153973210619191500624567633016754779285362851139541330356055463497043289125421977788598568738497027535683284429374328270575407446863773326584287279094142658588340462977391696770522090950893664563666469205941098519447320823606466663267637974650286636167283611321102132472485295142022804447378329387912754089290771246527137216929203856150750693092231715256959212836038230049192412266549260327559729741373050573993406641173948172009197580969460562524567268599074387574727581019549995237166564511046249667117249126964541121004758752513879069454546724664569980607200337928070252079703644082325906336445774201309715432812382675108700236251521726350653701080364251302334860439156388629038420328093015412481474241086685365735478888310957166714593528642600932764262834560966217453809356066169220493840286314929888904016784877054559675411135999421145780572338456292738355488052430831258571094872447484305330599801312194391457048227571199031790212348070190499119844035581434381766066419173431348453680176988533803310914610788122886511400788398003468803710555697450243358377088704372002302966138176068226185198541066330738487543131521392200068589411022250692545300427332941807353220997890727387737106287036045248346640483008423263377202197731574705647547893787429983539806739618329751443719031222686867536430794438232196716094565186463167420026155760614806424684858655762267931569179556522565762202336778940569884552667487750184122533194828584275271992779081581150186851734915662685621808181581766212088837155503500873716295315183781988407055281152058285779406516372361929325876955640528653199210531221857931729296058957052025811656140254658246764644433104010366471365279422203202197386512552839167584576822808944120492217366051435599343512016977342268345148728366564895217978391923362096422590615531688403231457080588087674297974074778745999313157743637128110331024238025969603914801388735988915563833320735633714802842716882006417467845692937700135029577430014166178520475853486247604745620952313221519691122831052907769995744131699448114593546216836029988817090248101244279330760608329052643829359282694068628444868901714221037176502417834362055977272751930427549872979349480609919391856425037007890335970399850591292472928561300638602705527742143286574437356084578934902247501505271989877432871084121420140117675002120355092989131908192300324737008914074225249754776361486967376917666201779331549436768856192830931943885532434586674606319101868658106146485574364649678038296171926507828229197960828070305486447729535224167876206914753765527995041456126196186111077747568211019433367842234499980362303246964811937359423195981677645855286313455503215161072522975814351595613351664304373288690329288400735694288236826591484643429841060740040227037122427051367874312752286507534306627865645806336176728983821741358124831586457226207716902480649912260014000872552760364716764721474275576559383463116103657903749429525088587308246131643776233882727874077157100194163782116958605787330524257151131562430925994214974172977646453559964583006365175331769667977788631887290585284766728705576422247407741909148755261903351136031546728500838300084927435713567241738510727442924280870309249579765864305247969655886487935015787588852908792579243536124280325072115838805307565967668405510335514388183207357615297916390061817620852091388273925331871918608330634333931462334994456596535516721438816445609371833714530629805013779103786034984655628536794203620958194694691872777312852334717303790705744946004501578512034013444733989222023833215780097124413355513032694383780786629668829145137935182320350977809569776996565129168338339973753992414849235789513075413599624385029084044879263413002968017163063799278479289653088063945926725183684012343527110300656466491996254403124333577650674090937543636782906868485263465396579160228416803419171763306105195847335720010239611967595134198765630167889822007793137722539919556220800689172944267761468746533277072544520337840447705387802852183085890213151267376861128499756247311613652855604861802248700966721526664915947215997635952046940177748924562199469807415617899184205837386322997284921137822611412068888888716763083929332903738277999696889169815119147816176807781697911475380831495662048750588546543145097294450816104356280488469455349422759529157580898576678507909204010973389683633948780166164711079720968451803808418243863457001378436970639142101752688819373460882804567897679417028021785456329767838197774419415084468196163086196918541518448096832990948184420072750496863694776505375456011530814702484338223821458848545800755003212213815502035660243168239226199448039979860980106122640226799000707856557761163310272901285462662333361123263549026923917906935277436204820866432359539469016282643848038264178885742633975083191917943352527546591023743481312572201295741433030737684816940459181252269656205692335527343302965733306236973386477058233242754903295027302942738261473924214043063645760173671606557336115134963392700000154109882130097941927423046546853156669814810493802719965339885931325458236285215204197322671032833423519172387160970475861035594436231019863858422698591466413533652688633945760484997871174414013694053386777733648550859957600614127595174113163889814100528145339736054689248610828529954194441292676173957708397715649171618284758718680900758724375554636753601381403076772494179255763040856299858875782547164999396820817908368648399753467299448540614222843778697258338406537156462619900248624526563099514161426874414878557293178078237644606467180993976246086213731026759708653876846103835807331259678363820530918267781919558680091477234954262076757839016207925001340082129477775397008871361662688719845405042447518690838237027133296395336660071808464014063984238399285918582970709313251133886907492539459039026193118604024277778942274778733765702095253083394094408979673227923035130812795500803593520425033905219322516564066032250166521991456848124429281214584680016111953422230594924801456112804674635273218136866483000149218799362010640038777172455200052357269945208833306918845122755432571487529917367170140503554056134372194928432809844087877614984958328410066003464409814063387972886339548142888182845278028152588582581567186335929997863945342950430850510935542151909213602647014364904922096301811318959850574989045887254903037426159645723973759873320186577537041828995138326743351288051581071547987683865829456912675479933745140768880347490236858257260055422931261057509752065538846301446847855316377552979917397485485368900334714668892927524158551243902528921458625061578210325769942587570829568240293497446883146414654304338867023189964720874406788936431298225561475938606126177047205334898205476608793116706534763463487785566162379258500124008597229518580476809529639279420261402571398291352770882881945522200019420482331602950389153544350794340923578701287104228093467144395320554537924668499047526916859605308738562810225706715825684866158324451656060288312224150732364580352307952875104764471656006342698061259454490111712893859656200199946992421674624548020388519067820612944858298825596006278656988760185601768046106724886818851838390773270251948836927250384004733584390167219727650183328641169244815591497995567811248917128975334483234296236731056806711484398988479550663862678182774909905275349109124971809617984863737764047270821324853037499040724437243030350344392303340882898099974232133203656296107171415110733817243956847910638113366212263276836185819067837031158033302692382353233101985204036214708440979771789598312065519018886275221202207547878597160749720074280652876539110073977481276293190365020267471577271689687007666550955002674971933760625923791321744178034625357123872214390755315093092628020875627874612306779092652668688854027689401701652272948769784388198867943648385976548202873901959380381121720750763061193523905669023700520944825403252789479333592701389905148983610507856496561156103418433808510479447932782262150544871001870568696079887233019696421554342369739166925574451434531334792678934440436907786198503944039873513641849361098460434069699891434291334920873784717856095208387410612665463257879578405306217260781346136142737144952572301215172241294864230783390603614568385146678763605627790417245139445504786840460937979041011649572277131214064656094227750687611814119831008576026785675962496624351179196212093880891236038919379845845094133429345748619612354173396693459497226214156652946494659263575288998922234963011339130321409457512288102518866117984807287558487931122948333095524171645421348647459161352290357190385748211735391405727961881336722569136344567680344853980303904801693607144093349407442745701030220862375102990906981553930642993063787088255902863895104095274667456616199054713698577182079429792237925953268356503325104484354259864643370434445958747680853010688971400540782753555904501358489157666628779812917401895210737229806560630691495054833683973821634409229697291963076555423451049678277943061118937678194575003997099947303002671098530526968792974164247861655891669493616066596651691575521423199465973040022285609253002851199867209444148511331539963281161685425438431405940133920372040429395791749411352728272192357650525236490380669748530709348664070921300139643026323473050093487026886128533453860451327094742229855894193714239765855529490558316492781567099845597943346534668949311904908189038184883339635818295506773892861844148101816504664369577461047342205095439419751180689386744524929888765408096941866113647571884613826472285589953585846963738522021547327712964341579590789879104617477966678302295365081043990092389655164392909690131698946225642779760573757168064489251827974225156860648420092459949602856256876987358410901647660612949019384628399218968313649934187039835898169915652086151325285591329426862653310503573563147756782090578898521350860494670209171661232359617863599414354460947699885844869077865756624729467951860502430744052687952887592804475379213187540879757085247600852472227420083190426444998076715055849467966434518164628251640503264001544174194511516028908608983323364450301964815853924810394098825967767945637348126318118897294236408672761579446706420830211976618329041538537628856183151548430669218312825542737975650155098730431487579389692091682438728342453708354694705435303277487696505871590913031210474896155902454179394887448190404463820147608336837824732243368194076599285518569828531873051991125962729799518890868813311965386956838735738681770114800075962105030375372156954724035937401293245526109118641989751618459248671876931533226634056510272179126701741799663761806329733693223437088208944733444454912283187709900705644739126365343925894056846107314165639298907174423714398598730761304371240952789296113207758815357632454254390880854955965974155324697232769716430466346641016062703078005507364911893025969932549860158690455349412069543475007411089983602953654570902309716101384195662101451669423745394571455280274535444963913409972326276298743042895870478028177505967221858231127469715430350772221920602888927334726302909202920100569813526249071008552341711618867938177440964830725357137308579695527214246443017971024390181144888794174356714751902948618545768380868578214742984828282709634767093741835902540037861841090106697941205881581439010750887740250759892043574329070614222825727966912513331724545705854204549201686370272153632605372248703727016400977262841663737738427144943037221197487029517097781711236664210825865230077815934035215372944472115348267112932730733332455925206676656067684806613553974943468010000467089813796541341191577698671214223074089199348764524714004891570892812565890828147925697229169342424816478039392191942751110489432188190973526062855534703643234625452345923102347138573751228830934558663397112659958906870564559730414933237177767202059385736129904653754316241217576981030447906466828824289295155953393046309842235564621083105976242573843206020991830735253642127835457201271855627345876195906764958436098721753052480578249422616667141201151131820349572438695128335686027265846543367998112359835176760292030817984850660079918485260770858140539049985717197352615852794627555261253689175296706058301150288029756700630290498217455037492288266137591625852114973620945153894509027707485756593054612318302493868288461338474074178002042468961234227076044023191646405315774374140476659184363931621119597249499599013336869625180518972921918868351397914153452835144006765647938602035837661612414867737028429856125664507801535750929559103395029153818412317147646056176728739697821042400506073177115682094490763821127238435693922982443175526257571541250928885629249207134455551576766320401101645287823213580334217448704404352562449402761476177561582159590026675448711353221768205971520927337500049847769001851509481883233815224854736066178714211915535343913455534403129368495524534780471972901145964446987251236956648162611755931371542599773823431510116979768158484076021808649699519683899905845129749666999862174354593978458503144258547488050622304996146562318876198546991142443629990970944702738974923949340944771799251222483157034133422693857262491666500827925338820962161159145468185129451176654472416047607117783904642475818433074422203979541380824429542019836692739341529581551132068715807588109386324444042809858562739552232228512189038026824665582494192890255006899049429165299060947667033230789032322006663353531704374992353724477379938347131486176642817328480978943416379702987125912360974544339329245682619866867459857735209485721366790162603677583152848336410959144176324230411767948248252458474791063563879176591770725943260940782624368512776070125500419886914525013858621549712076361554296243371205280034889273307338626454482918920998466413023848865149808198746507719820160115207582325266532612680292232066505198390681380470386003235167261131420496754185892914136491691437145507972879131333044622874382029018615288865490981775764081304471505006568519885472198343471639819479192033888177447453040794705199528417364298505157407343226509907269863030872812492232216898051252819131449472259090744725367582186927995468828891448280016380942578911596700172841290397905277925572087502466683350512416827117705409004223910975542441742580325244300191006438486418030962011756518265661821560822206781782803167327137930069373605888684779598050165902207928340712784191842488422675801418780158687997666146052831628190300348416041828771610132633401656619355221345440978826514544681534169832784549482526831736213506001515399957678614907246575990913260689859932506162948592964515336388277621334723471873071213317255080622149200783515512900245959839151155368506661747240697468293797161680831632645056480684148713341687611341180724101672212659531564817303521633388259311111893158241795905118190294954712190720336645062804880127502820106942719475622309823977107156108632954529065509016155136414914344856769606771063124779661005793104949745645202720044382438558113762640520126340847521161305871277091639474887085012764281908675695660137643469829033772745668011513069471102356893655013697521974743903806330849242414219568318222472622183229123145705910833774553314175748529070939444421153755594412877812028097616218268924003940113649785372455805735997781496174946781052346287111453158300643526698356277672812711632622926922794142870222401397357424261261573536054516298314997121058153638109663082792461055050455367453114185481853051089538307471093577283197996828539638191433329757806971722609087447724534337322327188905552868002372640551995606463529670070039540027513085053598524821455484955548988115505921263551558895479897954018753185598311987134982121401614537941248961989858881221610949085737543450684762043871532485657190134695381781604495115379963963841025337522776873113672626628734271966273703024409198929377646825375009206051223599933155899938268800279451903074296779717673542424350560304291361517290846263563938054994376218956818978433149235834198781060242905531434936979069630350523915211515768898391692056302460779268647678495238682007731162730034816496421722854338951294946188842280764274063731471716255244285547845546769191664199229542694999531849982068853277428535017199738784154470464199053836741565746642416171248595127261252423515958805392836081398663701867399987900799337371255458234617796875167160754885115406983908846654201849683073487723269614765106592913422968449897454168078003733182903924969537612819910446445643581386366819013790805614185411876251721317857283683306710669286337763240920068725375405439766504527372505267379510268596001745262408829844033924785467067696626765578071112536377394646421849761244097616480700375018956467324539469592826337406459559483362389708636749512051252775682287931460860169980575458918484375337587134487588760437153907561374210867916751060840127538413817001591461239718362224312862667204917507514864234831946451129863435015490564740192712581872775149724958838220000144449589379744597914789715569460894170692306764349268021575691583305438919830354468595574938805029411907411572809718247902257058335982250210339892034367152134879860139969340420489221647213610166112866215872918401742425029770165283980082404313630996316741965179674556141237317026401569285620435471708522397544401242066048300159115893411200268514773520601004080385427164413199361666493730838459516578230626594795918795537726477231658653948031917768232083633484439039236024566978147235463659836026172471033407967541145447743200549320911070712141510871373234729456364038250084087684719335121135277587817747331632580333749570445247965886772599775393497998588810040440340661060220707753279354059693773986543833936126195889337959526931515863189980840354893757049217682527883671842998188041453328825466577144931641872502850099179792526906019242250911858939377017034232035602942968819696439580672333087787365315256636127063328390814382461063635018355169488366431289895039165389443990291268701550100680694011277869147651010558420755727293222257137117665686816643555305427216109429622212468255373035357760759595795036041800662249839744699939444805453302405330677921387211693558273814205982244243354134703732885030586993567362212225845233766561666952231843256980476661592119454115223346227362910755865569282472242233412492711215829624691932463495792973431059307503470153786969385368869401571574387481792477906472312166374245921054333737003797382860600861159134105344942786054290938712823574963335788442882355099432463537020533010226527973986283920920036437475721160136147690848771648951628800646533969116915024946441713404791487619154620269381668670541070306308364906875298736837365653134093894747401317821503718590011438758432263961249985721862793688359750392255653414819595408128647828945246850908437771691376497606575894014700971980254950026298828068474585805879384572931300021785805574790548700619428637310898907650643541299791090011861122155773399951785391435522998813024170886999415464796673499978308936767658415190297296123415165423266631930634360720412522378493463323967952253314890091337363775619830600736952120035485339455201277488527973021924370352708609213088040355997027930836044732112298850980028547902862002033559713947495283257780307106605472796466413221161421696803704682896925731619805590647802281049474609540822147692575436790539809593898280883932228680367713345705459400524678598898414090555555789118960406676183146594157065479553659867649095627211045830961722093052656576445180470095356102748729149376191714028860746641896687547944545030683414009158418670881774231197926086409132480224379838052885703935121783178714301725647228485812822804693086426971003434440887440619949226790095342354198917223537531971017732155027320130502226106892400215174424211641758573367272555325155877999229342446082037066517272399593992980168503868213762881117874871731262563853735745919893617802048088483864900158930613670538793476697199616414302284137535432027781058104025128950903336519207086112234415413788917578014295545950876186679145781532742384701130004664626402681183420938305162486776246539633512439318694979142745927647377648618211667579656531026611633429498029390404458527129974951643834812228609765407805339166553976067186961280502056165766322827381059638840539853221678396647840683766543408100904625569280823331937268065535481369556874196394807652062586872140141785580260883698805512643737985884998768790055560950005423726707291395191711257957225805953229810282767669435022125252003407591073384761421825469560962759335158359429223642075027412510015255752539168222607935042243704191369064109351568732829530601789353016732303460416243627642303153324129227675910856682750262751361922071432468218229545783258892816091787128121736411281915428515320403197995849111234052317058646504545262974217191074126937082837174822992863547538073468625010608813765297658513967595111487609197822676413138779043476506142928811020447"), new Apfloat("-0.18155458676026499884711022589533728083863967778125233166674670611822891794927332367742707370085156781942564892884080232330139200060369450371393737389785030725616945683609983428704844206842579635599971963298795555228967919840702400864277779438532290092379506662785216021752108940672296274766058169808648784080707751056065613260648102605363242560469448583802459346250763677979212969702486768421381173158609558228997402453309032705199084138326032011741937875530993140777426413928316817215615317863510201443167241303143078675323989485942725785739351743273902651986232180858797871567116337533841033026726482516998292523608135453046954876148639902672248331103454782236925747466760167866319199274277718268377802174175216547239169577776514048562534143267730381545247387529453060108177110120464701437454494857269713185607475812458722401470790071905845314095251144488391971061209941396123917606367389914296275457708307900998542389697910902239091171812558468132118105359367422431515668051014563623578690457169405641916281231020691086154993074410406232285444542355703082627660254975941284883063310321084189857860967898856822214823391382386015402794924565927707735018747771665683268381084142624287436529048481571763298414640247585262877720565579925986929906320045879101860829867330760049275737253158575644644912262631406672199556650532784975626978691804168692896038336075337708628489305468660880161219227562291747147324099087805586665792774524412464710020134134517433563184115041082193309013761954708365230234019912422115275109706350563548233767977347441154699370163188922758277828933314060515588958471925100431930341835549923350217527514591663086960359904715782905593157512985198577558979642572512997260356928133370088965125113362099128259271445391578050067202377371036485703455608493415369152063370709634288736748645323540521724412098198346721356366602357213013521722546500762708156649762034612111970531186764025598255876940367905519391704986734844059191768078451284631684795662721255340875039772854087664929773722189495545368370091145023245593761738390486817827892415962000177834078546519274999905909788115196937461562536702171498558460089152139601818801456459353471097208027148272786161684471268627083657954390155678264558198397080127894250071990735993757551740290512713182793548094593044591689025797552054788949531874382654869836470539750275268558057335728651067715350416705706164491817039446961666834966109736094206081566078046757597916252621137867055466333471227675131896112391964779174525030066314244488738030756081077438051543608840182142188986477765756607817128673293982366452578959681625021152279735482672236670995068233096114729411342010273690828545362956284934820951696006550805395064264292927808285941658041749603289729002745128111413433271185513985010745502975402847606029115884112797924668677079314371116477482747609995394085636479767602808511367113126278575592628573170687670077881650664797066088421672533135432283867094513242371264191289380312773911938335901895833847418388120500990621570831100933375971413024871208706329121425188319099149544355830385086912936466568514004252133465925753016611547912056066532727047871755231649381648323753911945424382878401397829974074396492864459896980089039768193788379491320166591005051417714019790024479996150318581034981759970664945567427894977627252659386155748078834580658773216783912117618935715002879513143512950049930891387455109166624674912728387546802714786252289643295607083608028811854982786670659166378509778987685192939712099815843145980254560954681334318945391810686937051450782466875789080645337725291565715048513639805889174618471218209227537700713135558433615529986019798901291024999559582869653618083553772229075551921257568825016276888388349501490076166339056649628876502223738251794783878591754924100042057610585518283064588698013275025321799737813360410159975569267997433690934955307624113257222732891475822770318883057349875759084128331382773062916897477042204640641861223857987053125668031270152972041707801469088467363008737380179371039246934985318621168945747970721281603553785460616862710613902499867609345661855257190088540762638367902248768636317404661583332191935337766453587064085425719621888095347302150418160501438317975626698230419536974561031858030042528764814490048414335453279755241894816864478801885007080474934378840975699615418181667752237863892892396759200358318354399501075698859049881367433531284705391160098094203155518078074993592906175870010558759117424355721064634912525368648462866258063791582539743443406806142149570624855245036157173500403645444832787632707289607816051748652069882974285948501745892624408408896102655097532923496987723511193686213849017473849707400291151796846598658714909086033419858366264791638340543867669035931313078605966897591416228984655208664310269072192111121638469799304946397735517377569675934711546133533311915437252261127552256009887912788914291896563256769204356259265079828546688860973326899171025140879693289818904345982473229390596731102274767830575627175710189096339678364627003175766051883407264346203399554770010644989885059368552945752715292482587578467042897556232240818136589321921158559757831421384147559338203588562422234719261540175409817413495418492828516710160016825740494963627893331625528507980254883723996537292270505335283140475620721970155282311008668263477059747537068943377948150948557051484361247409115993509041897390194594589031324501490618104318169134543076509224248286423091711131567911898736231645275737127770750252777073449371001149858719971783711957328751727793904411723971131682415876039285774056195916696490196078346952903518150271800148675956131544475311553385386651208912595495560065322458574718006070233161014717423144798830695985019158240033677106587824019625190516450879990835686805418300641391923585732915997046153318438933038316439717010109304702598799194030100448934504759527027281356134800078397194328969993223159547165566234999307697448252811144803426789949164411533888179184033919475521274182755614254169628486699425967145566810095347617078551049857626778194466185163918615478987776148925635176080809481447211713384789231154494906197701831460713479998086677797005378099409033230853124656220011185134723323268040561316113638812902603416356832691865462964090053946946217131042227749685803262590036813259964627999264921766808030904633986353860818302865605563064410787564539102694439287566705605297191301354981371397315876303279876134477720194085387852246015946098344805729532926191229835098591880284099123712759520514714752847527027944776898862146565080687716652099443610073700839803692906615506050990062637105852457873282118634136896785021581817488077463485267323263863309945140157100052571674321626086792711334756928891587548822883612251987825915963452199195625284796904600733461339112231477316627596709072180208051183068348515623426241601707926078894861317166680096525903530663124941893893657903062182922338900072802496255249889887662926747415639995599101044467950099258683232994266718411381900637811009489633276399544965381107113836362023241916230183772692348944834075735180751329619936690818653985846257948501587881316217287890137622508181011581202733141498697416395775834663051647925968788071146731692363381897686266341787148664401870785288817055859648666354079878446338997819466140946659176132465006339159428394946850518637294818795318395631900425754632333442991061194509886494678907041084155623777410891877344117533804042747842238650701159434511383235511057323933032758685349748198963035627442066630152709271817882988154234881114143734363261945688605669770060569098486746666462966427781787413458695874187150523547237954003176688615363229730851551052197245972578548310059136427287614626859345724159848742241226329853464296837063298085191908976982171168962142346817246190083172736683079290775596090496950456163858171916390258903299595623858381752327965935302686587913621691039135955364922649168346589626453029406343205261722029655313452506040717139828959360303475410689702710138794856832300117080618641905425573580616202379277461354147482416119500603450257817330844936179190259020053401372358686849833366727657458217498481735288814290696006946329637694450838326556967572119156984856951937426619474012880886861388881826411724861705355348277098796760374926954563537488549385279303511728382414833896196562884773096762376361832564428047054558010831495618752976581359608526387300465910565912700412364373310601716616567133803380287152240742112054547857277068877443945003275972534759348012543625708768777586996885585399080887435014234656273576598513859358886503095438794049172529850975457125468354236802706846047729879683640262963613420144094954015547578215129512363173429056756037060572492918947840736349619514999784395726868016359610056965350961699354944468941057182562830359004659864976444513397287124457604539671138573674546707381329315837409873247419178577091584451985195208580282134652056284760569322933564466601034914519351445800997333090294440863711009571949614219065285752656843346630001112597611055049183561263092187434590086281831008761241700568175951293204599957027614243188465911652128880042538361346279169319200055898241657559554965535008667956460949670516525965507189134790489925599747869621090146212047684653375178065177920023126479213624054568935302741575675044240401853711446761912162642063009066067020401993727231695666763029890444064173455932429768696352388558789103889505362872464719836489916350917031553688784217623358180515963287497069395443975025604142437522664153767689904583531308584575047172315933438897677417388105281538825252091005177338729067306108021376618576887147064326046032740872702948215326879728040856871816424254588297272294886069690036565677002682916636244026391011233172558379884802619149123121017996850695338682943388417634926436847942508273652772050142431179259224584194593426188502539555507557770157087160681852944832114982807546102762113441322293252961360976809959023618725526483933831411409817784943586547725587971871958780769302445028451090664808907035479353779725152112381099071610718514884211928760123462238246090569533322249275297777459649100957970910305389489441261168087199633896649644174798084804604824163643726222500658856879202287380175985917323503557984373409608603743304121161225279470612072244747379895373781137539993588659461627018782171104667779984412733895493875733264595082559894072119201458092603889166863420230118097612283833996328535397880405015887494060434946433723417075960448624107006978691335782344831958497397038490293282822249795972430525345643079031362792517878782255802047915267939721014861404346613390876376563623519130906385937473747532731456623832584075002996955157942469230469820281185337423483398655502582212463763026889788335704314877665479249967041315305124510080089044955997654026724923206183832923986253889492551933748265594079998401138349889547486628781801829614149959412298435766463302484917993974788010815704632989655493878125458848157130697134831430867699481378124505800858700056228028831223503172547369893295769843297876602797251386658308742309615717884420727782818998233669788688793221508433753582612815973279270659861657821774645165444938883646058760995269378317866128670744176403756075733815078864349194808160894620668624767757604384378543299407206187374122868742678831261404016596428355180214943372229689809617739870973719294614393559065553718093479838657553668590873070811951339128044022667514906035596108127239686051223567954128052541976494808933711411955636978402372167729506733480309357608355149710147927064579255576657128358491742382787403689247898232482644050710970049443544390971620728343226654958078948785859996870760207722120883960745129021927735959897201545553364144438875492596973576982847635213825479011867976444235730597855387130549337644562839766806430104362958867480211501799908081258720232792800379303175848961545225350799762761287057042471303243870015424176521935404657692088863084984027306316955094019770238130086002188897091666124672634411509699205831877078699411488763669922878205725217813826991571002738113563138528066474593704660698793915647322811520292744766368126830963835936340104469904972826944945210604528080937641227073457504280956323716830912929555152570860094460558882123862908473315023661566152142242513162119724303359548935495136168457617185126821464216791518533516158775591557353609680617800346393338401069008430064269370856597249354461020017056044468800137872849897215450069039438995335371006307847672163237343460320114327290579160004366716379549649625274855341005808338706049875167699109910086701331532086116280706791102448900158816602625055298760189595008485412936641846456789104719741420043901180691003526953358252187167279842435209259315072950523111819105706456620210902199341561021847635769474070897414589524020159795815726803692626790766957900329240700925954538749565981282203086035525683522687961928744905519558585951305724421828387856969642694742220815345211626207455895060059357279031564938991581374117193726928243708306833636461608555672568125912428819034196095726999747668385194870046486568033651240825933209779573075079791838400504532288643940238598213069022573401430464686733391342914698845840175384512160244373585836525941827704918487502520148383365022476959791877341131006489779792453555878825740141975913568352706252097996439149046011670487782787446583765733362527918261257889265214002081414303192373631277946133815973223803876537820499659371794796400631786864285523978689891164916928834049958733235263911729465233643630859614084256073119033117462015990548396842459865669898663235518119568094126396620747254430943329672895765262400269391388385622316436702117384819489102155864329869030911865226895104104840118835177454233605618923090640057991079539463344112825147191342862648378016708562141269315890997111511164789993706350105660431220084178143459807738339271401676618786486063764367949694599430680225940365661401661223080391321020580820659026352411498900521113186763046494715748233155788308682957394146422957953736828345637275204873196960429351612618945490413984115141461741756322131375880742108589856329989564002076789434236884035703382325186887312842705653087391480630116393758492187978921194531605095679891691049539819691244480711246373284637938587345612104703760450278233280657700276705299020670238566781054700805762798776183389636471369007575820806538309908903904574043745018735531764821400401721014429909646842012204930637570523681420659242863619484845792857278411056212556419253365938947208048624839392132830807277706209139378378508325878915401027916905122910588941204870429825103829869647032976279065387292216377286458020933791643487905850212486435721629129799687964046021224536623669737235800327172020455363480013254151075683325893671943068489708498256375219737956656973857896540464978305803948264862787056967985607372424203722585447846701106481497563158701150146198671598338914262464330364947912555309478331959444711824177968714195696936612836626612642812905894483405746213186395921237266899614910516778085163442944936548284210982732471798163067357995882443646994479942806404825982070273814469359515621741652852627685635624224060144803995111928878287425703727400075691597962204557598234560160994118524201683814849195595764177868983960195783353270546792069432773576114458767665699811575604575900827420675684318047760308183761267793142818762068743588785177361250825483826366201778382811606559586199555803734060161170689746615035992386253232492657545003243113054116484819316689802098355713828066645716077225175559416038470928795901783834464962857700470075147817357369298043416198429958230871182986898303787486671695284738374515441449507917215264881309804812128887590110705096317781041895678320638798616089268399776038281310468427151851582810128194991285227552257188313315756525790396780237833530803247718763523603152418154246117932031747118335836074535056023928917846792648367982026977313483602416070472410708813906913781775239664946155393260104942496742491377647461649412144630038505558096597797447922494689069098679588943507497417381194005370031102515651954782067224072252458430642336549608320464894400263549893486377611918417715939877124573037647724918743200769736477200975691874119993283275353636969069383634826490397975000450163770657981065762431909845417661237893430848403923479364745999006408802368010814216047165545526964475213958955596356317046552018169059357013967284270302509833123900590320782156589423597727069718856944896903192578916548667294790211890253543980309384509118402670761763277391570067088073370958329654157023581017767831867602657376864220031414746444702900657266720428238021747266958091826914982556788794931396138617766725716464196544064431535306407792664153468400138796413062031605791348514724218282637907284622603565324842870461947570707847296831027365053887001103002536786127820999299008750911171155298260517231200461496972615386426763624479175956571665193648570853980511208729600408103393490707405651232104493888109232290671903596850616737831124356970616513512540858064025190169555819921737815612596383473094793416348558314805171037643605144272486758690016415242159302869023859120323361185947158065874141056212618317579439190777661141064751616181032917451909209355155024043353931669113708171826327139412115330141995520001762765107478566512356908277450678501626126976177671793068762985139114273664912369223714493080366661281257492549074924233410463208842022627816941274122440359935226666216536819713530388040005248625520289966186890780300564301255361137686665057038393418975841219152102211773897120009299759336592630489288499162232037226422269579186371957321603842923443589825671176775126002466213231478362074264954918263794537917414215483251089563255336782080568452721476142519773854587412168072710656758918731621190120141519485204402944180818659424100746035608124331936013483129662228927979746799975288029127499862692207597641874422071184275714392560500746637328389987286175001338526280752461259839924408766733134066866912822650525265958114091975355492581895358541411541105539569364112440025395815183193611462685313137452865802548029739094712461503689797522596643199578782094866665140095382288407048915489326207453197366458280426400173549599188293224333268294141318462793607517619687280398311162182112770063715513024863260288108169301447258418168086959979941897051454615481534159289698585929438682811217169092271420539280099424726029554955950376876088702948199019974760449327044943867140279533134841650217578481953157108468564301344708603729182597662431705260856326889527443907579449277814897150690764814182903712012464853241916442876597653595067108839403029548154180003700960830063483168085162891320130800027074931719000033163579236923852603343020847366091955877417673898101512296483452081560940427300800356826103138444354127890848031950673196841361039175347996162306289673942680202452639572868263128359082867882074327773138145759486474625477558339205527044610338043881577146310874251131265749954959064898832728493119614190313755932626020226909208379527406957688775360072756947990351856874984874329261812757006123041272172091487532709377021255702507000698368230586973099548577633151808584739493195078976625529369619957077975682211898289888048973792749665580130757554439613564613086041186677870293761288560453496110834346740806246365301119645688262480520739838983388792288736610039516999877497707798988898008730406096344341642459123825441704461404987114272842638247759929383718876950808375658932225577512075846598544706199848201668631074643924110614510571977918999509747699802101923023630091009106117480044202059633567219072766920922719013753097892891700592945780937603839126110243207456896342664740757588123567795806191288214539260098814175309133494987664540371561316737880920363961859317317658705695200653467960168168994957752146805748919072400445096163115276859878541088508672155707882379383103128780686340097562323256007860352373089234181081128683854865163330138520971829716484955458695087015710271954295469132448799480394313001693513524793695907405282958793929381382507727575392109697231714135243032706872944249346631157654129159080787316510161594932750330725597701124007521336171300270130734679624691887987833214170387804564373228832698665134835632042220343670993485025051305700047527287745576815342662926287259357747957798785713633697038398018558219234361871610533390302734509853406687230909269493913411864461729974349128837291914195512628290408426767328047757168367431537670250458138678496189987365336426588847766021774849001859674544716563558121649632400071785336689904472519722341716632794477141468915454997507321444012878603514569914911033746163595816571854569064981847647740595590409559824532479347633698217776149775759431715086188599974809327859977997203408944017196483208107604829065707284780681026078612633431141362830684756340847299990994239871832453682094560935254962373661444702351804688756524157157787789267875947094114637834977760663568334592105198268161525611653244650524478390142922841929699821790940501189330211830247968385115059249635885225384536809344226882259490204752603511676084375233460089901657008545132217735484427342242522253058199878950046936087429159188126933375881961538229816976955734704701490676523057685628326501787104024830050405212718470168645225051428921443646641678722678891618090598392362014218335264157702745616869405948585173244661650795356492083044389924417156341419004109316940960350835148655336490190676205657750158263461363985761009252291840326724346476417639018112464787934388553013870489292958908540997305782828802090006493918257481125807197004052677409524114746133619668632562310284932849203514077447563794193202978304605884234666074790738696632976897236096401665028471323030772905462821652913293279127351906215220738625344635623386545216186078061390842595279290073032468294426506303639807804883037039248152252938369913125538435348999289650775799371591309763315148569445501114490555499483735608252174752244819892659051376599173734131753090855945683256772141245140203183453316152493319679450526979969429290046420495544000367701165077533535588803364404888948733338251157504818583688746141991009555703344972100439335169781620274785876544186412222511799263268879571937780624703289660153247089039883236210012713908040782408535266245409607509847938212977408324926062248483596177341571253888028136778613957359446117698711814359168210004975291246149817256676347376531393905345322766962108663626191126491764739053163398424635671902869051004920359888065966618335093645088151223109833202336367874299770913131368085717479812796070253912440024454455327438247634352878363970920897675576217518340986657511117761734003419171950397181194264888769385456728052512664563451790399411274807365847383451981673141897516930952321780617226713150996105241421998776847877998050683911147314005167653939678455883733711276975770868208870775480210311512151592567914611632725118534674817552314277732288387047933573158260771020809396977438151531506394853233872650008152472865850590675916851197903859118730577580692731576028996302240344548517924968649810341087688795082399268813733296364735904786017787022766352929014701163100671205330517337686516725790305283090846425345135588288614722841776675259319573183568879544391873534657032143625141750202296724046395423905518871953741574423981861073051765538074599133474008761223801167534503356832718540066987701318101617861289986974778617454370058694224389667186828711842064986395074077316262157084529570221215845494396306732965192999882503902541808352307390647704611230784584059992411775538490678892869115447253800881220895136168239123645210774752313874005861534097415243270461764816781866151422466806678510160063202336712962361813873385990419986653029939618445479404593084073812518047129517221169352693980274522871349477753689596466814479916426382061010633042926634922811805158721711539136598894752602515055843589573065573263199183532612604579189049901359715243292514668092298048655433048460848760301273267247644838849192369418121367602244566250089574614633835286285400412950871121664932615252673118689802144234351653951032806407737841949426504201418577146185950649957002136958440470833266335475977089183322655892866415236199809028399244619945598296876944164960499540222239590093566135454844672609207196919830212375905486220549622445741715134601071529752649529729107064012381450659235243147525564436980899597704141913656526392818549527028866466900021366105809285073946543929669937129111899854566774660572900064367776787166779436157668622268954786780762324816943540215448952106696896109673372648198789767914153607170632305895314315762279550714908784393560017181569726287139108576297839052784796807472415865576217405282896459463723516328413518503933347783181560716468752371683387111760530277192034345671363191509563225353649242550135384117679050162279716632394132256518801797482177565739906334679102709673061445560302900140225491345362950569572725450952755773232847321666380324505820926860742948622139080275642251701525821075677690881491453808370217101199649702570137014049475286122931835248125243258049188661089733649076335590014732506921390015615919654059894872258889404058197556951209493150589130427695419612995793852570232147798110665069680040402637451795564292559084705969568891958384881973877705852334610775914872319535148286567069679729371701073345832122841914865313293734767760940233411308128076474405584083249573216049202833715699018618470790102720486101991677404272294567598673121991421432871118011553401916372016707495758478473142476598076794891558500037284094404197696734954029858945199676035821633658824060257413599284008394422259675043624956015531360132315783422394510036925331777921385555135774539284875634517503101850950587767121655074413848387525764859848359127417316282553659298863486224698512055544889749225519155850814941562482876747212752856637879729981757178672704816506487659946015581121611674571256734975952320274936136084989801511215262738531610036295395190084356572092678942594860424868723290669121663140269993836726327445833768139668075740104211891630905514222121743623461026916443816345935221797281408038053156296294073119221186683870149493342715052056065031112582283202117248480262939271299338497509966011922323682486896939816142237759307705663353664829470762022366500298247495813025455760474615749651330055773959100619996785258194299936049852795942730390456630048291587690265548556474217102030291618965693169919635097803801805064624098919241702719660607368943499595302466694714420593197482425312048155044828588254631131656008283846675003317293894151791157128346257726859677432670031076266680615085068153764530386260907335826135773173560911218811247217800474015190732715673705129765125173081216096385413000899353798679006929303340700319840383807933552693844529230655671631198501934546508102886109577602410279124675851825799718832320811940482382534333237906368503598164721119634207765910916124111027375240208918122956285295733497108999129657032035713908098761078437864132182334186073032716141166052636331916617781195359133621292129333736938023730591055821318853037264293202662298946960695664970738039556603610263431850137421000232838669153790531799519459287947646363818022895742420233207076989217907952003890742873096051709868037943623816553811379648106171977596544854361878297232689398307592971117067924673079632948017331830568878192681482230878327530290831415226644307138060590021314741664815898512170105480728697243578288951509844503613217033440039876211466627687419272240956448064934129725347016725277877835048801406042569544561165871868873351700181507273705664102523439615193026714126114570498158948167739296465860747384840667845470601893855178464969768903389583020206997330399555383773512842079965541114828079879771814450251918270225226457288675574262720179753001577579792528903907648107042052261731584674041812415745444374196766935835870111190389545846309966954490642756147563849169214145996560301440144022907175717651122952441429335648235303511661765135806315689142677414430286378745928238306695296922396845938541802174615337430147931438396489284227535070082891437315636265211816570903267871623932687576378928244113739696897568374365020953543899922143618307711479314486440697650993671637282905688732988737088416907631546358167383326617460473901453018745026369158102217552329956997188170842538877151905045614671666131095368389256545445703252313937450587338667065567105894359554354828993702963491139433436028271807501599137243505433582036960492378989762229940381092546102621444005548755559192373993141276724703153250387005598866472801037224654898494661177007144119193553859969853796516232332158068582818501304831508576952438008221059924350316211197317762274146125430625853370016594390030839392855016465670313232551928307252182834676187653318615757008513181089264633610393087406270770597614440650912411894337789972506217272292951261897728560276147982752523277978084243142492134937475990892600050639481788739224542219707265659720803877350620615086676765892480713044013935541593719135355634100501680967375749350942531463211191992187495000147512674741690378048221305902149646954961566680362963921305248587253381372649385991991349057798695205856235933526733122907409964640149183450487533248195435230134795989056146995846400916705704346010505008559114697620598831241004620385211829774270963064623340191214683815120574484681715507467070803494696140985366886113865031992351102998542921431144382711390134477439871120371088128713110498603894944875400489404281346034770562759538523928232545132208431963448958979464866970472144233982770812724995211604676988789528854738495952809352568071455791215193753199371933408939549976038411644461012525347396114040676998465890076760398412848106499670107021896647620777840776064924486406528654355768571981764856408753606606052357532348683523801352347094006403985062088264986692280577724676824084743670103397526346722162454147276337633296866357241027374215881800169232789580408899616582849496852232274455265276156328764472985910330731119159207733217214242894633234407408692066598688532069976859217954860655267249496499038732329850131332344486554922117058122038374989333583745299578039537557249658457766209180792892620718184277480509887314231972659848074854963461321966398544967533285833379703641228717610570670660993649247056602796083370451587152852012607178163624400444304155877596238051951734246758072304777775531954880281793851444047371857753409205741788663117309940577466609137830305739109997805413558988804220683797066984323599860735351047256970029208143518538505433638756102987876053481372811630371958738743344601839758460989155521961701509329595306259091713828149960401084586782265392506575068984706516344904762508493193375789796397579022169957364005763463841916003076926203273576907168821527161815768573631001653640584294444506867316732227421952512120909453805977860401096881191844698409767159485145966166037878515557367518154863759017410834359592361268266279779887529701764291186294290864844555660422742953103234776789579063872259738589461149335403497544924411630618414433746426698247292614774392931381125135991868194051849306864652768434594341169488627998232987137157884393473736681267939842151481674898934792832721719615210228456434473077312582373520776710866232826872414036539148972510081221044740675801067699774355467339153725435350723826345778454888377567253799788402663012239878417981490178044544690803937084491960036852590347109028795459394311642678427072269096547012901853632496553908107052757848442247916360114831787846856294420817326072916211974946556906973076490433582983863217759754243101499710259100110011977701427878871567238397162410732401771741075654888844205124801359994485030390614202211514038671372754342667225967797451366147210464464681290267742432257825119798413217758708656755255967342629258921029867497386366750853463895625203156012234738442491775659288119393031421013826934133972196464662883797089308595478714038577989459438836107759306141993446584406269336563696776758442156677207821791786630670291512839299635336567542754605728007870447872954677325894023324926004759802335925566477152460999206816166995231402327397303174831668685036521916647943498811720696225705182117703975038532085536064114958668384466515655943527990557947212013013858212364639795749837695988190390022289594273640901334982930287814768542224035339503280384621662115718167247118324884799698502372593918521356701002384163478856437702886166123249727870148965979736790329313945157046842877816967847312701436845885568017308736100826440278264086328562729539431906422608201462749847654067016751068081994871734940895853129016578503235776039262195565096241065256051746106768207651715953530802808551169224031968887503460174900534491292233617241618071643026189538063508995424670313158836135246379728632982112533797818021083549073693647851781100603560623454994486487304820683257673428711501117935246621080910956529218914586087996215282059759688886400452875528932346026749511685038049465115942533350589437425172742281190867492224356151247074184040001986671112867449092439851115980229407329759759804233561018301204667846851378704173136704619983501467518238094178653430489103699430558384787394920182496323491606337403686064498642025863477285897316830793089612547754783713591085864997163228007381624845755235607822766185381180891800387577563829004259387846738365776446766186468488475887900474365238689197530024259721932912876448516040071943657895715153945901115390208370895844001954870145423102408145425692542059807676819770988851057644487400035073613283095714565851367129137896189997880918091205442321614022008839601860477010838096993578348203385206115498427005297699475550644293371364822477309525614999500005986515516436565045898911496363365283122814463359623506837845799313923370897586609700386309682009254180612156234659663908349485627750364564269760039827781119634137393442147122488023224991199983464198741547823461184440983311092859063315339005856209570774217037563735716525767202146555022835634830394173335846701956090603347993027348943503358988459283180126267229524258589926148054417247211544452012680947961970739427566014231907376004777806027146356673098104051821980813609489620627536318586072902362453001822146836953398711026938314624231118172527404160023662479675591972679463080892870924033390500260912484149710728580399922596811737729933496306407864316279286759308467225586400630712058062669097702930610741950266142986951131473864541346772760763803060336404546192429256660139570339479557058048723300221682130062742082192877293317152000048405763082356842429761275660461823473207814459076898750836740848867906794151648175125343727837463852243291610840693776703896004026903245226739042203315018011723928469119245936172041590507477293955509088990008598863091037064353500783631869397593772370717898887688588656836002080816443697460008562641267127150284717822620976444113210383784337269761228551739538537661771648519656505986689078806853055487415793334545320562269007016578463759972916520814246470659069212589074457381442970249815892442236639833612914028093400563728658690099330077173462953464599938306214364544174318409982374233427001201380610944383326758306643155426759762715096895248897595850591180683986862010984106454398490864610157313808094583469141943493531284574736984840068097800568497689543962031911947367408227594763844091957565106107552153730032737968670898825671936469994812821377371148837811022242318639063512522797025452571858333170997958817988795230522004873545554550282487459644952516376749624663157914902772002822124664066921173041693470279033273487170678300885104689707366128103993312598496630483714838112259393109030130535144009845879915694634267786141263380885785849272906872244664056483955690290055278651899721051918023553310757045708515659594635266177354471360305022071898027450050585431374121948718463407693518602305177427966019074621123632314487234921417610740908947557207513826231873744514086736226235143279308125693108701314688331416463056231330867123540258163072135182575267182190427548515620883347426842739355454752310511865573766860184468595791688099260885444800167193009921183883965820563135726020816703884459589556682160115132810424824252116863915855540451425851381715508993046615859507841678722931154711559350241372172593786348680266168535145295933672774471722344578214689705563351340012396307844383667613171566836460528972255085382673246755302054150197866613699839167088618871297493257010480470455239361070724266161575145504198951866327000624965652889530195949194330816111277963387244202472753221727896667936872408277085170455804035247721214206667804118222678366309127382321473430743182505300094750183501105390685307605020319337760620854469088397002338646173153791285606939422450011302792632370182584037297765211493362061107702329576458675220311461054166606053194526254493310277022880289968536096617791651468640429001141725669363037783525088567347058387512279167476856953351923938798955727765620493388195685958796310798250237155568677912214404559537936231118212271082243617849922989075106329111106572063957896808953038509983200902269366037747622165346861497447179331602930580324150022454102342507835843349197976573287021851331096888382968690184329353251744124436065474015636142607668716392092917268632880110913217427117546679735438455672079917067162120538443971150213375204307156414558816105667545087274132381023468022066316712175812850423340012025864091639920101684176981035329660680045837014982600258305887095020132484753955366969222139647157663437576548452148124229468912960099327079014070632928251812395462385112189819892864694717015076953611613149576949836570935890074526719905624349434306779854987391953235565839847070646609005469284353923989436538555992176865963181235199956060145629695233945542149217483266953743523609953500013879273190416645921891199100962876923624231417488878753148100157917029723601497336622624806763082966696488928823603119853411128160195147064476501628997776459655867429225391299737768182355980214433207049895613039244456016803216551924999502931415811311156454661531023992298329324467877763016879839388147591280860594803347692033418184793039682106635091257031344053862345723881247581268656834354608589094822517266238480843646377599157751739437195375754651872905898013964468475328153117208208719010225797964869052848022342097211379029490253282457508340688574384761289605583949449904571053394039281660964487570054000193697712484682478313845750281326148060436634600190408421951985937574582443631064338643146777317241248138114390808904859659180355816305279541711848045459316278778708587563810575096857466668685437268723884704041210712707941260474160459880877409059661716529058563497149681274770292765153477410334797868895468975002219652166818858750507295074217077771378565682357382646692235465574069382833513216703687463284432410490799068553286410983224530674095298251647419485661227960824588952394673196872070657944880816263971733987254510989703201696536963382040691338799107791181515903205839737181299730926557256483758426657677292876629362784373024520230433768307775430481076916705402148366027762698662843157711052325479790842872339201119829825402079781919936426836667372052118560603502542516929854227081834708421392938123648811993542940105796148158924473176942603591903780457552392852833120082822407307370240446843330795479933686130866313863667356521800069708273793764401331591952924497022864877785118949301478262984007553670621453257650461932344214783208669865394966714981444117630008306894421364005096365216585031796993715399027829945440346288693325830268249652681107760671629888771276083695090436233768009046904528365363234004107251341638439728362773629077299266694331144121545792569495200273018567887609801855990205900886811752701644545124869687236607088696109495418420914460162018787786666211079535069945660089848663998164798075060795225412201924655428643451526420829761531275640771961372103315034401253091875007906339695352019514032013514814139314613175365865262433787168287029001115698997996095251867365205922683714648016009365864724204163270292439504830523673673486175495316774050519360055640404638972105730103866419485787017163430044123031076545988774922413601706324077498870741013977609100683319210182492440669559457941969656416767626506471682689046582636449935510996826450527901963670054947700276995472927964878130257225735305862840471833648520008168518268015648590130251850833942831647252289739876050983171253364514964272315381274621274048451489064721784510316838818309910560545396410048541753019451403429342419803697825873246140818271360975119904456267061847680127857145988155978222327015943577186472292875290282322620059650293921816594324599152516885476989893314314757433965893479557242976903075527231025457730702616869116558807435492663585288768172556480994463241294768316018337488908221737087775414801869344453867456080820088970623048357649619213083805282683821415276018235994272561050710639604902969414356591422883672784985021335756157623183527135610253533681008353989239304392113094778323078548686538614675649008504905250350738703575854081154937955186471606292870710048757745296580622346398728999657024584814242727803281153861543415371577286590441293275568601393566885824607739317675301479685407426171913314160026648204306152345033613536617090828600426561348821856987898401457212727377458505586293246947212627849112496400669439609513852421846880258373836399110071420751796315064294214558415739801981761017292294264076088362374828573114136409107264040790327127424006904453926965605366751038052785526038792063741147124845706254678374647656387024454317210426172517201061304334984590596002863835733568605350684736519945184956358663404400992057541788395429437839910457357818703266019379168920147880552850138176986780608428477884110334948663750105880730934236251821533163043079598314053801836800929343519635593906003871741322361026121581362888445145486293599658109210435137237871060881180313823256611694917814388325735799607697200760016864960905526619587848562550339046701894238104393832996676541742864970467566596608025539468047949345849002606223961065308891531921339931537936842792993998833414004825620659139495509836134898894586607020344204161252221739058043796100034285265299650413233602846928179827210196699532846048076182348834636113562982736523595464523139937006230497014863470909956553755337962055775211408311847504483140081683837403307420100175491533182951692065657499643402349291886677170633176517088857503926810725706765930074004312086119024852504156833505953451541703100917201212623526753251865710466706910837341519774169677105735299938290134706574586048220247411414344140652313940251347128410171542460621524057592652109919482110216578276907675533916706125303731651305900173753457512831384615059102017374373844133913607853274641406700890631174611975848649663001584593756504596652530334122687192959531272741733757148670583333588752284770039177057377888183755055767538896085138291482556099378800583189987799524878310173777242646264902694012276761795774171764579533074680594026080747192003067365210267055463903645114197220528852677758859144852092161048075737704219021730808032990443332057466649775387001822637790663118529008925114040853614512968975675439859877822568599339317170617702363610264932469752759526220732084713654477220615452277507503914967583611987751379885260417852919984857264517205286721026660457961012551308280298124393093398152691906198268301388915992269765873938812194147970919277009090684619146184976165549621598911602800409260472374801041237903334537424933862623920052763473393084867297897752871845085530010136587525521875004610333810492163987761984629555627855250387493294356817216419435832380198937928761010463536580193010540735826433760550212172484543572473756532777331627535138522214809645838502760182558217715164733351364696494231273921817297743357788885645872613102102910792138892462791007437036478573887483521125228591708478049740535996472795082928224154369833138051387863422146528573611914898429145751142659825182601036963196191538408832189418613101951262833286126012469538246543439834289311241917329814066886604301444123671018628504972080101328974176221888356043631716619632757366892133167748666308076171955825734371443919482144616816291717558137679588524161730872519255503371311380625681355046467805586801706706624500902592386391311935078875464234009463443987458645529941370928438543280471652126684390119897825161909762122326852175585939901231148874424331983020522258781070475475291869308587846683765192027821999629748631274122362107893258112586730962757960178003168636096741041545976256113595265376387142801256877272810537002398930350320912008976236818950757012497545263058896202419194556470068313511381761038131409146935613543726647240403940693861855613248095081768699277440858422497896570279386268759594974427725107226145901483215451774447467370352211786290212540792266340478897200310411813580689731742918131726358876414192921328835259430684093225506802242715588237863424275044460721615574837870327822422419299668308268921891592990490044895293126828370872949969379556331044722545336614776566670203350506254506878386897319963671004724887831257440437762231008652071616946090838875702176053791048922073334896935014405676827811664837803603304025299656436639654166962870875846259655682491259867934178703458120975188229588986918044334729397076097819066471160864259513013554259727531399959556228510083799213746121474860552235897964909084800403508742449421066765643533996077611836178897735561516465066516263214543860198903906792595837547401073492923290184069627649030588521249731321813958310077315252888778759139245273336840205090311595462247666003445576340596338401223141962188723910409610468001642950596498737387111905290386017761638576000805218030180504713015062449578789171309781229741593803177353117719231484858963152609008668267842705374415534618247716603724585543379598003324614869660455995756090644490638179111078579993404797553885117284646909087706489097436087487020820933608498602241395457626459241342231022045908637838550784983960212474056015736493807614806449604580025829629436031842855117875875925666228442986795087102635910032906162209069277227445054234233590554113313943706628945649707836323382196419627905936701052523364743111579649604933436154918936492487639494765774775811598525682228953868543866816833787946949656485413832044523653492677174044706940746178760336848898679074330274974225856926781223981432517301037141308643389933304370636855700904845251275254939070514101192332761926234619405927249168289144613863509663266087655507228610483355519839248199962008766776459435741351475312933254743837859465292171211373148145316299922738410132474224244079898866942430276922890790222293443314904996800400341480763379704588408953699881015248963496845146103959525302520873085445080020596133461783025620532591579243749566650805237814782168385169853012729739609145239330381527196187849205511528432406577895361917898312747676354684562145334623677025651716436734462028974671306527905613695497461933604992132056154233431876060400718127699483280221606117696894922006981394575490222214044588446322123729308568213155822885971284233958426897246648897215853516351926860656548745180919789690658194324809766158438588182578298578849370508735546346067691045434723402074833020655376653949731644362676799437251588563324510300040296114182860582602196009925431563838937686088969362436465637535783937456055689795027770545651568273083992418996103669371300691580081429797975769106578339060710818004340404175003065424808872363315337871698653784851602675853831943439513048234685169744318907970917747967861834225346937398560101351445731925447263614250544442859528190956426613717033010864330216076176017701793712935270633432603495197635337898957450842567483078979484040316091497001745228117059526246306650022312407196041774513525975690579105687090666962313662444316622056234639492408883171925334913291885917945755929246969156319469324182773414608879276825510953110172993314290644725530350665835685877671471102555937651402110403234435688176179290895913063657991491574402852279272948459025283230578106633124043094186073080951413677508213163369465249246512604763260087461579148037643388666017380089738893306195833841480508118369407447364266287929101003912133049702099423930169058329909094738293883411694566185578662353302909885152084965137882661582978304149464109737931668326872185361407758772354339124310074144765906903230491351225720932845047869873012072892306168781907303511605743233739434130548145213256720938469429203484882740836515140308810520626435562386474559509452991492590324538793118680865874847930727278699151299723057573501866355327722949008184669796411715515823343785717080153497645025259657503129897112676081367997662504454333581653301715599814865001793080217135581242958117299762124866680247433509910449194010973439660112698147810232027888503158371974400780881902721035200902650658998916364871389026579144825850982480823840679564702428381346068103753771623616384285892556462653252969091624519596307568743523113779778032573467961307353275839992392880608756837385890346947254758221741616802734196939351381394363694462894764379830555383716430885348513935738484117790606097887902756513683914819898331224812865200509817856587757295543357366049734174048564060125254423532422791018033095461532105131564111889052072204470345511975926573513598946603646494565677430255324240761494163947811274793464819139659979366514741912819019789491157559086984274664028947847840463813931985659154362376165194295362244117099776525121140395240925988424508920758345690383950040551083162589034042656389236128965992656531641721355746167102587201791845831197924036956118103134606013991412067650283351308067002339771748028710761313273886439021739986017265221403958762111520449336796839495169748632585499084094817904008859493864850664378327153102056436779822659166065559723327726793693628360583042233776771347245505385084465963435188397560814259955015179053988829497734560666777734469094633214128824508763685875319122842234034995420760096598284147537834357083731581346052885077689131320470207721383005387665515392628439922316403955802020713517810820775026508024207781129326108900191981732550821034652392012874572056678439073849111643494262384013904276749437597263478933998195060733123447146332547052508239853981068470638351152174198942501740466785278909480445403418015716419375")); for (int prec = 25000; prec <= 50000; prec += 1000) { Apcomplex tmpZ = z.precision(prec), expectedInvZ = invZ.precision(prec), expectedInvSqrtZ = invSqrtZ.precision(prec), actualInvZ = ApcomplexMath.inverseRoot(tmpZ, 1), actualInvSqrtZ = ApcomplexMath.inverseRoot(tmpZ, 2); assertEquals("inv prec " + prec + " precision", prec, actualInvZ.precision()); assertEquals("inv prec " + prec + " value", expectedInvZ, actualInvZ, new Apfloat("5e-" + prec)); assertEquals("invsqrt prec " + prec + " precision", prec, actualInvSqrtZ.precision()); assertEquals("invsqrt prec " + prec + " value", expectedInvSqrtZ, actualInvSqrtZ, new Apfloat("5e-" + prec)); } z = new Apcomplex("(3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199,3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199e-20)"); invZ = new Apcomplex("(0.318309886183790671537767526745028724068887460492294518428180911365119092396046181434178376080663353821009173544276311455642405854621090970373833904108972047312915693289356046049118109403439718172703494223105859718781812969543103286206394410806134813539553699626825863476727272799898208392521732801094763613545214073217354874639667048516536717204795290926651190121934930599524109477852654399389412872736085204160015325250614659445812229055084108341819036001796031629129394796573412318684485632518425385830357671174656209774572200992380951793462857729121730710703754813506833901088477689224753400237800184028789349091246281008776667281736464380349416427846404847680388469364742310525487683211843499436782010153659045483125565037272385913106741831620126137301310655977395673814982293995334905769140292085217372834361554984204900827704600919956923458209134644251890168698857503452823024163773233193012892383081929565070416391662340642298133395889765186066818049772720421198307486712656459423699740714924,-3.18309886183790671537767526745028724068887460492294518428180911365119092396046181434178376080663353821009173544276311455642405854621090970373833904108972047312915693289356046049118109403439718172703494223105859718781812969543103286206394410806134813539553699626825863476727272799898208392521732801094763613545214073217354874639667048516536717204795290926651190121934930599524109477852654399389412872736085204160015325250614659445812229055084108341819036001796031629129394796573412318684485632518425385830357671174656209774572200992380951793462857729121730710703754813506833901088477689224753400237800184028789349091246281008776667281736464380349416427846404847680388469364742310525487683211843499436782010153659045483125565037272385913106741831620126137301310655977395673814982293995334905769140292085217372834361554984204900827704600919956923458209134644251890168698857503452823024163773233193012892383081929565070416391662340642298133395889765186066818049772720421198307486712656459423699740714924e-21)"); invSqrtZ = new Apcomplex("(0.564189583547756286948079451560772585844029472219615815983325168731208939469524264130849715258371807352118949175282690765845344942917477845270569742604457351973786191393343714152098802730948710056242456913534549142144868681124341539089763512011185016222112993127514023862896805089668633982814102772802015847857223491343393161133327212199033121274114199242243886056093480418532190764567074258299440784132207644069312567711083044479177537911030563217695713287365789838112929530752269146700963429727905088214177563066678695686031445447823998180399322898599028069989982482713328037727115586100854156652407125940257202088435542491586162644131107913481116958281820113230632775481749843710252733830295427323497470038385845571714020385150993253030073443070150859109512539452193591487227624349141289194482012167462681566049156405755813963874741659799112317643080264922748938583144492735585571155995975646825688024585904442417990229905395179613654357994285027995462492448607663494664326023222904298961716735477,-2.820947917738781434740397257803862929220076837400135610380757333724599600774390820496406021488337914539999917013808424821174183316705600346627044878665321316704542521132711956696115985692225461524144103674892886692811597954261197086278401249934262903436722704995347238317043044430197303220059198367524344827033735111145878843692931588007247802420701476138362763155773255754035575528173694450204821839899996342068039557128799949289686121250460169211402363399566614236747718540967339344797060583864253993886722179688695573684192522504572880979317725720745670246767341402104495822263278183453247632255562470843252936393521379423529102137851920938395838025560822786482305398364309855882826387811383500700796209016865318095637641931144775510847692507725489704866162502275965441880142102620023692574058012436283742735333878669894160523634912142148192752225318741559491075014194590494884342987343226966477362759864182357605917102577568819758568478928831698791913034318162836596723514735177322541225949696045e-21)"); for (int prec = 500; prec <= 1000; prec += 50) { Apcomplex tmpZ = z.precision(prec), expectedInvZ = invZ.precision(prec), expectedInvSqrtZ = invSqrtZ.precision(prec), actualInvZ = ApcomplexMath.inverseRoot(tmpZ, 1), actualInvSqrtZ = ApcomplexMath.inverseRoot(tmpZ, 2); assertEquals("inv prec " + prec + " precision", prec, actualInvZ.precision()); assertEquals("inv prec " + prec + " value", expectedInvZ, actualInvZ, new Apfloat("5e-" + prec)); assertEquals("invsqrt prec " + prec + " precision", prec, actualInvSqrtZ.precision()); assertEquals("invsqrt prec " + prec + " value", expectedInvSqrtZ, actualInvSqrtZ, new Apfloat("5e-" + prec)); } z = new Apcomplex("(3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199e-20,3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199)"); invZ = new Apcomplex("(3.18309886183790671537767526745028724068887460492294518428180911365119092396046181434178376080663353821009173544276311455642405854621090970373833904108972047312915693289356046049118109403439718172703494223105859718781812969543103286206394410806134813539553699626825863476727272799898208392521732801094763613545214073217354874639667048516536717204795290926651190121934930599524109477852654399389412872736085204160015325250614659445812229055084108341819036001796031629129394796573412318684485632518425385830357671174656209774572200992380951793462857729121730710703754813506833901088477689224753400237800184028789349091246281008776667281736464380349416427846404847680388469364742310525487683211843499436782010153659045483125565037272385913106741831620126137301310655977395673814982293995334905769140292085217372834361554984204900827704600919956923458209134644251890168698857503452823024163773233193012892383081929565070416391662340642298133395889765186066818049772720421198307486712656459423699740714924e-21,-0.318309886183790671537767526745028724068887460492294518428180911365119092396046181434178376080663353821009173544276311455642405854621090970373833904108972047312915693289356046049118109403439718172703494223105859718781812969543103286206394410806134813539553699626825863476727272799898208392521732801094763613545214073217354874639667048516536717204795290926651190121934930599524109477852654399389412872736085204160015325250614659445812229055084108341819036001796031629129394796573412318684485632518425385830357671174656209774572200992380951793462857729121730710703754813506833901088477689224753400237800184028789349091246281008776667281736464380349416427846404847680388469364742310525487683211843499436782010153659045483125565037272385913106741831620126137301310655977395673814982293995334905769140292085217372834361554984204900827704600919956923458209134644251890168698857503452823024163773233193012892383081929565070416391662340642298133395889765186066818049772720421198307486712656459423699740714924)"); invSqrtZ = new Apcomplex("(0.398942280401432677941940771336389031865543401129091513282882250179772434419851767808651006965474553450231659632699401869161244597728783897275069734495032085216111887271560916882166876402125564868424323893838395079833719085290052945723478416783792406475917822229067524633036157052429629054952336706428571030187185130368246152628279046184365255879570477684594489756177508286624891300014994270929571804086453067394014233254639503393473181933215576035395390550639697849997906045852679378668246627935464340165981060328216264423323994665445336102173311228974531563690928652600365857426055953950317930869595684120658335492212442508507834457013088943568704831703105447241317646019451168564794944585905138454975351406084372143958122058613660877516675727140023601583669342317551944445825346281293391559591715805382904811500194433043087334063140186294620627312015177933295795822130423296667674673191468264898033406590955879437301865909636832022723153732099412803030603571832486087242410216578677303181161040972,-0.398942280401432677937951348532374705086143940529747694598123913207048338738616221978231886695149332457228174014279359091145043032910761545024527444992360506013704395545023729865459628156657910811196135090840777534898858802933750807644091893566642264434784387109684567850959336493692171697673283014869432855022112957977024436179321320242753133483455376103275583952799802580664801293539197676129806963898925886048129072348894165986263992243095527749288022655331420135724260556412139641344190345395202430297370019028628884610807050626790668495513149123868244378285115997893768231577855442515532795450441140924271501021684964050090674386687217757800362815660179461720592095429628585826372342230264108452648535563601356604345631990883903623336860080341288484907446373257062910833105988975533864466874928921595164065602310594305200462213282003201942543469515879364472417744667720718931280198196245354196327124908226579329264507159226749362033448374883848585906758047055682395695022774374795093935940257888)"); for (int prec = 500; prec <= 1000; prec += 50) { Apcomplex tmpZ = z.precision(prec), expectedInvZ = invZ.precision(prec), expectedInvSqrtZ = invSqrtZ.precision(prec), actualInvZ = ApcomplexMath.inverseRoot(tmpZ, 1), actualInvSqrtZ = ApcomplexMath.inverseRoot(tmpZ, 2); // NOTE: EXTRA ALLOWED ERROR NEEDED FOR CASE prec=1000 assertEquals("inv prec " + prec + " precision", prec, actualInvZ.precision()); assertEquals("inv prec " + prec + " value", expectedInvZ, actualInvZ, new Apfloat("5e-" + prec)); assertEquals("invsqrt prec " + prec + " precision", prec, actualInvSqrtZ.precision()); assertEquals("invsqrt prec " + prec + " value", expectedInvSqrtZ, actualInvSqrtZ, new Apfloat("7e-" + prec)); } assertEquals("1 branch 0", new Apfloat(1), ApcomplexMath.inverseRoot(Apcomplex.ONE, 5, 0)); assertEquals("1 branch 10", new Apfloat(1), ApcomplexMath.inverseRoot(Apcomplex.ONE, 5, 10)); assertEquals("1 branch 4", new Apfloat("-1.000"), ApcomplexMath.inverseRoot(new Apfloat("1.000"), 8, 4), new Apfloat("0.005")); assertEquals("1 branch 6", new Apcomplex("(0,1.000)"), ApcomplexMath.inverseRoot(new Apfloat("1.000"), 8, 6), new Apfloat("0.005")); assertEquals("(18,26) branch 1", new Apcomplex("(-0.2366,-0.2098)"), ApcomplexMath.inverseRoot(new Apcomplex("(18.000,26.000)"), 3, 1), new Apfloat("0.005")); assertEquals("(18,26) branch 2", new Apcomplex("(-0.0634,0.3098)"), ApcomplexMath.inverseRoot(new Apcomplex("(18.000,26.000)"), 3, 2), new Apfloat("0.005")); try { ApcomplexMath.inverseRoot(z, 0); fail("inverse zeroth root accepted"); } catch (ArithmeticException ae) { // OK: inverse zeroth root } try { ApcomplexMath.inverseRoot(new Apcomplex("0"), 2); fail("inverse sqrt of 0 accepted"); } catch (ArithmeticException ae) { // OK: result would be infinite } try { ApcomplexMath.inverseRoot(new Apcomplex(new Apfloat(0), new Apfloat(3)), 2); fail("infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK: can't have infinite memory } } public static void testRoot() { assertEquals("0", new Apfloat(0), ApcomplexMath.root(Apcomplex.ZERO, 3)); assertEquals("1", new Apfloat(1), ApcomplexMath.root(Apcomplex.ONE, 5)); assertEquals("1st root", new Apcomplex(new Apfloat(2), new Apfloat(3)), ApcomplexMath.root(new Apcomplex(new Apfloat(2), new Apfloat(3)), 1)); assertEquals("root(-2, 2)", new Apcomplex(Apfloat.ZERO, new Apfloat(1.4142135623730950488016887242097)), ApcomplexMath.root(new Apfloat(-2.0), 2), new Apfloat(1e-15)); assertEquals("root(-2, -2)", new Apcomplex(Apfloat.ZERO, new Apfloat(-0.70710678118654752440084436210485)), ApcomplexMath.root(new Apfloat(-2.0), -2), new Apfloat(5e-16)); assertEquals("root((-46,9), 3)", new Apcomplex("(2.0,3.0)"), ApcomplexMath.root(new Apcomplex("(-46.000,9.000)"), 3), new Apfloat("0.5")); assertEquals("root((-46,-9), 3)", new Apcomplex("(2.0,-3.0)"), ApcomplexMath.root(new Apcomplex("(-46.000,-9.000)"), 3), new Apfloat("0.5")); //assertEquals("0x7FFFFFFFFFFFFFFFth root of 2", new Apfloat("1.0000000000000000000751511679015"), ApcomplexMath.root(new Apfloat(2, 30), 0x7FFFFFFFFFFFFFFFL), new Apfloat(2e-29)); //assertEquals("0x8000000000000000th root of 2", new Apfloat("0.99999999999999999992484883209847"), ApcomplexMath.root(new Apfloat(2, 30), 0x8000000000000000L), new Apfloat(2e-29)); assertEquals("sqrt(-2)", new Apcomplex(Apfloat.ZERO, new Apfloat(1.4142135623730950488016887242097)), ApcomplexMath.sqrt(new Apfloat(-2.0)), new Apfloat(1e-15)); assertEquals("cbrt(3/4pi theta)", new Apcomplex(new Apfloat(0.70710678118654752440084436210485), new Apfloat(0.70710678118654752440084436210485)), ApcomplexMath.cbrt(new Apcomplex(new Apfloat(-0.70710678118654752440084436210485), new Apfloat(0.70710678118654752440084436210485))), new Apfloat(1e-15)); assertEquals("cbrt(-1)", new Apcomplex(new Apfloat(0.5), new Apfloat(0.86602540378443864676372317075294)), ApcomplexMath.cbrt(new Apcomplex(new Apfloat(-1.0))), new Apfloat(1e-15)); assertEquals("cbrt((-46,9), 3)", new Apcomplex("(2.0,3.0)"), ApcomplexMath.cbrt(new Apcomplex("(-46.0,9.0)")), new Apfloat("0.05")); assertEquals("cbrt((-46,-9), 3)", new Apcomplex("(2.0,-3.0)"), ApcomplexMath.cbrt(new Apcomplex("(-46.0,-9.0)")), new Apfloat("0.05")); assertEquals("cbrt((18,26), 3)", new Apcomplex("(3.0,1.0)"), ApcomplexMath.cbrt(new Apcomplex("(18.0,26.0)")), new Apfloat("0.05")); assertEquals("0 branch 1", new Apfloat(0), ApcomplexMath.root(Apcomplex.ZERO, 3, 1)); assertEquals("0 branch 2", new Apfloat(0), ApcomplexMath.root(Apcomplex.ZERO, 3, 2)); assertEquals("1 branch 10", new Apfloat(1), ApcomplexMath.root(Apcomplex.ONE, 5, 10)); assertEquals("1 branch 4", new Apfloat("-1.000"), ApcomplexMath.root(new Apfloat("1.000"), 8, 4), new Apfloat("0.005")); assertEquals("1st root branch 2", new Apcomplex(new Apfloat(2), new Apfloat(3)), ApcomplexMath.root(new Apcomplex(new Apfloat(2), new Apfloat(3)), 1, 2)); assertEquals("root(-2, 2) branch 1", new Apcomplex(Apfloat.ZERO, new Apfloat(-1.4142135623730950488016887242097)), ApcomplexMath.root(new Apfloat(-2.0), 2, 1), new Apfloat(1e-15)); assertEquals("root(-2, -2) branch -1", new Apcomplex(Apfloat.ZERO, new Apfloat(0.70710678118654752440084436210485)), ApcomplexMath.root(new Apfloat(-2.0), -2, -1), new Apfloat(5e-16)); assertEquals("root(-2, -2) branch 3", new Apcomplex(Apfloat.ZERO, new Apfloat(0.70710678118654752440084436210485)), ApcomplexMath.root(new Apfloat(-2.0), -2, 3), new Apfloat(5e-16)); assertEquals("roots((-46,9), 3) branch 1", new Apcomplex("(-3.598,0.232)"), ApcomplexMath.root(new Apcomplex("(-46.000,9.000)"), 3, 1), new Apfloat("0.005")); assertEquals("roots((-46,9), 3) branch 2", new Apcomplex("(1.598,-3.232)"), ApcomplexMath.root(new Apcomplex("(-46.000,9.000)"), 3, 2), new Apfloat("0.005")); assertEquals("roots((-46,-9), 3) branch 1", new Apcomplex("(-3.598,-0.232)"), ApcomplexMath.root(new Apcomplex("(-46.000,-9.000)"), 3, 1), new Apfloat("0.005")); assertEquals("roots((-46,-9), 3) branch 2", new Apcomplex("(1.598,3.232)"), ApcomplexMath.root(new Apcomplex("(-46.000,-9.000)"), 3, 2), new Apfloat("0.005")); assertEquals("cbrt((18,26), 3) branch 1", new Apcomplex("(-2.366,2.098)"), ApcomplexMath.root(new Apcomplex("(18.000,26.000)"), 3, 1), new Apfloat("0.005")); assertEquals("cbrt((18,26), 3) branch 2", new Apcomplex("(-0.634,-3.098)"), ApcomplexMath.root(new Apcomplex("(18.000,26.000)"), 3, 2), new Apfloat("0.005")); assertEquals("0 radix 12", 12, ApcomplexMath.root(new Apint(0, 12), 3).radix()); assertEquals("-4 real part radix 12", 12, ApcomplexMath.root(new Apfloat(-4, 5, 12), 2).real().radix()); try { ApcomplexMath.root(new Apcomplex("(2.0, 3.0)"), 0); fail("0th root accepted"); } catch (ArithmeticException ae) { // OK: zeroth root } try { ApcomplexMath.root(new Apcomplex("0"), -5); fail("Inverse root of zero accepted"); } catch (ArithmeticException ae) { // OK: inverse root of zero } try { ApcomplexMath.root(new Apcomplex("0"), 0); fail("0th root of 0 accepted"); } catch (ArithmeticException ae) { // OK: result would be undefined } try { ApcomplexMath.root(new Apcomplex(new Apfloat(2), new Apfloat(3)), 2); fail("infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK: can't have infinite memory } } public static void testAllRoots() { Apcomplex[] allRoots = ApcomplexMath.allRoots(Apcomplex.ZERO, 3); assertEquals("0 length", 3, allRoots.length); assertEquals("0[0]", new Apfloat(0), allRoots[0]); assertEquals("0[1]", new Apfloat(0), allRoots[1]); assertEquals("0[2]", new Apfloat(0), allRoots[2]); allRoots = ApcomplexMath.allRoots(new Apcomplex("1"), 4); assertEquals("1 length", 4, allRoots.length); assertEquals("1[0]", new Apcomplex("1"), allRoots[0]); assertEquals("1[1]", new Apcomplex("(0,1)"), allRoots[1]); assertEquals("1[2]", new Apcomplex("-1"), allRoots[2]); assertEquals("1[3]", new Apcomplex("(0,-1)"), allRoots[3]); allRoots = ApcomplexMath.allRoots(new Apcomplex("-1.0"), 2); assertEquals("-1 length", 2, allRoots.length); assertEquals("-1[0]", new Apcomplex("(0,1.0)"), allRoots[0]); assertEquals("-1[1]", new Apcomplex("(0,-1.0)"), allRoots[1]); allRoots = ApcomplexMath.allRoots(new Apcomplex("(0,1.00)"), 2); assertEquals("i length", 2, allRoots.length); assertEquals("i[0]", new Apcomplex("(0.707,0.707)"), allRoots[0]); assertEquals("i[1]", new Apcomplex("(-0.707,-0.707)"), allRoots[1]); allRoots = ApcomplexMath.allRoots(new Apcomplex(new Apfloat(2), new Apfloat(3)), 1); assertEquals("1st root length", 1, allRoots.length); assertEquals("1st root[0]", new Apcomplex(new Apfloat(2), new Apfloat(3)), allRoots[0]); allRoots = ApcomplexMath.allRoots(new Apcomplex("(-46.000,9.000)"), 3); assertEquals("allRoots((-46,9), 3) length", 3, allRoots.length); assertEquals("allRoots((-46,9), 3)[0]", new Apcomplex("(2.000,3.000)"), allRoots[0], new Apfloat("0.005")); assertEquals("allRoots((-46,9), 3)[1]", new Apcomplex("(-3.598,0.232)"), allRoots[1], new Apfloat("0.005")); assertEquals("allRoots((-46,9), 3)[2]", new Apcomplex("(1.598,-3.232)"), allRoots[2], new Apfloat("0.005")); allRoots = ApcomplexMath.allRoots(new Apcomplex("(-46.000,-9.000)"), 3); assertEquals("allRoots((-46,-9), 3) length", 3, allRoots.length); assertEquals("allRoots((-46,-9), 3)[0]", new Apcomplex("(2.000,-3.000)"), allRoots[0], new Apfloat("0.005")); assertEquals("allRoots((-46,-9), 3)[1]", new Apcomplex("(-3.598,-0.232)"), allRoots[1], new Apfloat("0.005")); assertEquals("allRoots((-46,-9), 3)[2]", new Apcomplex("(1.598,3.232)"), allRoots[2], new Apfloat("0.005")); allRoots = ApcomplexMath.allRoots(new Apcomplex("-4.000"), -4); assertEquals("allRoots(-4,-4) length", 4, allRoots.length); assertEquals("allRoots(-4,-4)[0]", new Apcomplex("(0.500,-0.500)"), allRoots[0], new Apfloat("0.005")); assertEquals("allRoots(-4,-4)[1]", new Apcomplex("(-0.500,-0.500)"), allRoots[1], new Apfloat("0.005")); assertEquals("allRoots(-4,-4)[2]", new Apcomplex("(-0.500,0.500)"), allRoots[2], new Apfloat("0.005")); assertEquals("allRoots(-4,-4)[3]", new Apcomplex("(0.500,0.500)"), allRoots[3], new Apfloat("0.005")); allRoots = ApcomplexMath.allRoots(new Apint(0, 12), 2); assertEquals("allRoots(0, 2) length", 2, allRoots.length); assertEquals("allRoots(0, 2)[0] radix", 12, allRoots[0].radix()); assertEquals("allRoots(0, 2)[1] radix", 12, allRoots[0].radix()); try { ApcomplexMath.allRoots(new Apcomplex("(2.0, 3.0)"), 0); fail("0th root accepted"); } catch (ArithmeticException ae) { // OK: zeroth root } try { ApcomplexMath.allRoots(Apcomplex.ZERO, -1); fail("inverse root of zero accepted"); } catch (ArithmeticException ae) { // OK: inverse root of zero } try { ApcomplexMath.allRoots(new Apcomplex(new Apfloat(2), new Apfloat(3)), 2); fail("infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK: can't have infinite memory } try { ApcomplexMath.allRoots(new Apcomplex("1"), 0x80000000); fail("negative array size accepted"); } catch (ApfloatRuntimeException are) { // OK: result would not fit in an array } } public static void testAgm() { Apcomplex a = ApcomplexMath.agm(new Apcomplex(new Apfloat(2, 100), new Apfloat(3, 100)), new Apcomplex(new Apfloat(4, 100), new Apfloat(5, 100))); assertEquals("(2,3), (4,5) precision", 100, a.precision()); assertEquals("(2,3), (4,5) value", new Apcomplex("(2.917544260525786263696583078746606829791948283056476178719125080604001346981059514497122989501231285,3.939113046692836869408348425071199799284873423064425353396384561367021573926690156072311985300901402)"), a, new Apfloat("5e-99")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 1), new Apfloat(2, 1)), new Apcomplex(new Apfloat(2, 1), new Apfloat(1, 1))); assertEquals("(1,2), (2,1), prec 1, precision", 1, a.precision()); assertEquals("(1,2), (2,1), prec 1, value", new Apcomplex("(1,1)"), a, new Apfloat(1)); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 20), new Apfloat(2, 20)), new Apcomplex(new Apfloat(1, 10), new Apfloat(2, 10))); assertEquals("(1,2), (1,2), prec 10-20, precision", 10, a.precision()); assertEquals("(1,2), (1,2), prec 10-20, value", new Apcomplex("(1,2)"), a); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 10), new Apfloat(2, 10)), new Apcomplex(new Apfloat(3, 20), new Apfloat(4, 20))); assertEquals("(1,2), (3,4), prec 10-20, precision", 10, a.precision()); assertEquals("(1,2), (3,4), prec 10-20, value", new Apcomplex("(1.877468123,2.921948542)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-1, 10), new Apfloat(2, 10)), new Apcomplex(new Apfloat(3, 10), new Apfloat(4, 10))); assertEquals("(-1,2), (3,4), prec 10, precision", 10, a.precision()); assertEquals("(-1,2), (3,4), prec 10, value", new Apcomplex("(0.657368426,3.174083677)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 10), new Apfloat(-2, 10)), new Apcomplex(new Apfloat(3, 10), new Apfloat(4, 10))); assertEquals("(1,-2), (3,4), prec 10, precision", 10, a.precision()); assertEquals("(1,-2), (3,4), prec 10, value", new Apcomplex("(2.676463508,0.428671830)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-1, 10), new Apfloat(-2, 10)), new Apcomplex(new Apfloat(3, 10), new Apfloat(4, 10))); assertEquals("(-1,-2), (3,4), prec 10, precision", 10, a.precision()); assertEquals("(-1,-2), (3,4), prec 10, value", new Apcomplex("(2.051752596,-0.072458699)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 10), new Apfloat(2, 10)), new Apcomplex(new Apfloat(-3, 10), new Apfloat(4, 10))); assertEquals("(1,2), (-3,4), prec 10, precision", 10, a.precision()); assertEquals("(1,2), (-3,4), prec 10, value", new Apcomplex("(-0.657368426,3.174083677)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-1, 10), new Apfloat(2, 10)), new Apcomplex(new Apfloat(-3, 10), new Apfloat(4, 10))); assertEquals("(-1,2), (-3,4), prec 10, precision", 10, a.precision()); assertEquals("(-1,2), (-3,4), prec 10, value", new Apcomplex("(-1.877468123,2.921948542)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 10), new Apfloat(-2, 10)), new Apcomplex(new Apfloat(-3, 10), new Apfloat(4, 10))); assertEquals("(1,-2), (-3,4), prec 10, precision", 10, a.precision()); assertEquals("(1,-2), (-3,4), prec 10, value", new Apcomplex("(-2.051752596,-0.072458699)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-1, 10), new Apfloat(-2, 10)), new Apcomplex(new Apfloat(-3, 10), new Apfloat(4, 10))); assertEquals("(-1,-2), (-3,4), prec 10, precision", 10, a.precision()); assertEquals("(-1,-2), (-3,4), prec 10, value", new Apcomplex("(-2.676463508,0.428671830)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 10), new Apfloat(2, 10)), new Apcomplex(new Apfloat(3, 10), new Apfloat(-4, 10))); assertEquals("(1,2), (3,-4), prec 10, precision", 10, a.precision()); assertEquals("(1,2), (3,-4), prec 10, value", new Apcomplex("(2.676463508,-0.428671830)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-1, 10), new Apfloat(2, 10)), new Apcomplex(new Apfloat(3, 10), new Apfloat(-4, 10))); assertEquals("(-1,2), (3,-4), prec 10, precision", 10, a.precision()); assertEquals("(-1,2), (3,-4), prec 10, value", new Apcomplex("(2.051752596,0.072458699)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 10), new Apfloat(-2, 10)), new Apcomplex(new Apfloat(3, 10), new Apfloat(-4, 10))); assertEquals("(1,-2), (3,-4), prec 10, precision", 10, a.precision()); assertEquals("(1,-2), (3,-4), prec 10, value", new Apcomplex("(1.877468123,-2.921948542)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-1, 10), new Apfloat(-2, 10)), new Apcomplex(new Apfloat(3, 10), new Apfloat(-4, 10))); assertEquals("(-1,-2), (3,-4), prec 10, precision", 10, a.precision()); assertEquals("(-1,-2), (3,-4), prec 10, value", new Apcomplex("(0.657368426,-3.174083677)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 10), new Apfloat(2, 10)), new Apcomplex(new Apfloat(-3, 10), new Apfloat(-4, 10))); assertEquals("(1,2), (-3,-4), prec 10, precision", 10, a.precision()); assertEquals("(1,2), (-3,-4), prec 10, value", new Apcomplex("(-2.051752596,0.072458699)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-1, 10), new Apfloat(2, 10)), new Apcomplex(new Apfloat(-3, 10), new Apfloat(-4, 10))); assertEquals("(-1,2), (-3,-4), prec 10, precision", 10, a.precision()); assertEquals("(-1,2), (-3,-4), prec 10, value", new Apcomplex("(-2.676463508,-0.428671830)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 10), new Apfloat(-2, 10)), new Apcomplex(new Apfloat(-3, 10), new Apfloat(-4, 10))); assertEquals("(1,-2), (-3,-4), prec 10, precision", 10, a.precision()); assertEquals("(1,-2), (-3,-4), prec 10, value", new Apcomplex("(-0.657368426,-3.174083677)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-1, 10), new Apfloat(-2, 10)), new Apcomplex(new Apfloat(-3, 10), new Apfloat(-4, 10))); assertEquals("(-1,-2), (-3,-4), prec 10, precision", 10, a.precision()); assertEquals("(-1,-2), (-3,-4), prec 10, value", new Apcomplex("(-1.877468123,-2.921948542)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(0)), new Apcomplex(new Apfloat(1))); assertEquals("0, 1", new Apfloat(0), a); a = ApcomplexMath.agm(Apcomplex.ONE, Apcomplex.ZERO); assertEquals("1, 0", new Apfloat(0), a); a = ApcomplexMath.agm(Apcomplex.ZERO, new Apcomplex("(0,1)")); assertEquals("0, i", new Apfloat(0), a); a = ApcomplexMath.agm(new Apcomplex("(0,1)"), Apcomplex.ZERO); assertEquals("i, 0", new Apfloat(0), a); a = ApcomplexMath.agm(new Apfloat(-1.2, 10), new Apfloat(1.2, 10)); assertEquals("-1.2, 1.2", new Apcomplex("0"), a); a = ApcomplexMath.agm(new Apfloat(1.2, 10), new Apfloat(1.3, 10)); assertEquals("1.2, 1.3 precision", 10, a.precision()); assertEquals("1.2, 1.3 value", new Apcomplex("1.249499750"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apfloat(-1.2, 10), new Apfloat(-1.3, 10)); assertEquals("-1.2, -1.3 precision", 10, a.precision()); assertEquals("-1.2, -1.3 value", new Apcomplex("-1.249499750"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apfloat(-1.2, 10), new Apfloat(1.3, 10)); assertEquals("-1.2, 1.3 precision", 10, a.precision()); assertEquals("-1.2, 1.3 value", new Apcomplex("(0.1302427887,0.3818051176)"), a, new Apfloat("5e-10")); a = ApcomplexMath.agm(new Apcomplex(Apfloat.ZERO, new Apfloat(1, 10)), new Apcomplex(Apfloat.ZERO, new Apfloat(2, 20))); assertEquals("1i, 2i, prec 10-20, precision", 10, a.precision()); assertEquals("1i, 2i, prec 10-20, value", new Apcomplex("(0,1.456791031)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(Apfloat.ZERO, new Apfloat(-1, 20)), new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 10))); assertEquals("-1i, -2i, prec 10-20, precision", 10, a.precision()); assertEquals("-1i, -2i, prec 10-20, value", new Apcomplex("(0,-1.456791031)"), a, new Apfloat("5e-9")); a = ApcomplexMath.agm(new Apcomplex(Apfloat.ZERO, new Apfloat(1, 10)), new Apcomplex(Apfloat.ZERO, new Apfloat(1, 20))); assertEquals("i, i, prec 10-20, precision", 10, a.precision()); assertEquals("i, i, prec 10-20, value", new Apcomplex("(0,1)"), a); a = ApcomplexMath.agm(new Apcomplex(Apfloat.ZERO, new Apfloat(1, 20)), new Apcomplex(Apfloat.ZERO, new Apfloat(1, 10))); assertEquals("i, i, prec 20-10, precision", 10, a.precision()); assertEquals("i, i, prec 20-10, value", new Apcomplex("(0,1)"), a); a = ApcomplexMath.agm(new Apcomplex(Apfloat.ZERO, new Apfloat("1.000000000e10")), new Apcomplex(Apfloat.ZERO, new Apfloat("1.000000000e-10"))); assertEquals("1e10i, 1e-10i, precision", 10, a.precision()); assertEquals("1e10i, 1e-10i, value", new Apcomplex("(0,331126196.7)"), a, new Apfloat("0.5")); a = ApcomplexMath.agm(new Apcomplex(Apfloat.ZERO, new Apfloat("1.0000000000000000000e10")), new Apcomplex(Apfloat.ZERO, new Apfloat("1.000000000e-10"))); assertEquals("1e10i, 1e-10i, precision 10-20", 10, a.precision()); assertEquals("1e10i, 1e-10i, value, precision 10-20", new Apcomplex("(0,331126196.7)"), a, new Apfloat("0.5")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(2, 3000), new Apfloat(3, 3000)), new Apcomplex(new Apfloat(4, 3000), new Apfloat(5, 3000))); assertEquals("(2,3), (4,5) precision 3000", 3000, a.precision()); assertEquals("(2,3), (4,5) value 3000", new Apcomplex("(2.91754426052578626369658307874660682979194828305647617871912508060400134698105951449712298950123128562803369971608115858308936341123999327021346691138617183468446010737173164686210382470722972480385653096197955212595851386829730542017554834566076203624841629838837088111415383201962147391676642929058049817171098768157845839182061367660407624587113859085064455636920311607051981588597485536439305356293985101422595947649995371848599841753952499159126778852783849867972638132163229170462055215173927004466893155827350288414651232923783719736757181961513759146922026017058314213265164777972026914569278829769779023008225176184785498679682429641281302037486486521259687322336298021286618318415793710998463135836032875126545906276937050649443180086254169974282261221943615961474499125922697942531490842409305517925243257370218203245337833554418491842015943129213675762563419679038299132768627013663409472496225092290179397048258626692981873018305739254012305825026785891069123260517749979272211407491610089628959933724343122851980961660974260652181762103017936720767079145977839033281414352440639482552619868342969287513114456467494665868602786146218358077830070649048842337372991463043085279850727992640025660675380800254896810540213312123740821486832723122822609732501981710205986586577716162755069535207170070281037295556916467016669193561963726840316454962656506333047304666768044715822566242597700196677480301214952192861971988192656671744822490672697455664407140156730909231414013792802915135066242203113030716533667093257173402035594912939322282536077875674712764039027921927395197312547828266486016427640712420409764391754400652438995087760043085410360352341590241567046208031995471079328190006083782215711890791023443288680631383270729328245112098679248986918816410547156221869838319395337641455545236996980728609516738564908590670336904562106389447988845227636370340561649189020526564471128076963110284359493508944882615621434470215215697096025821872457004381345157727508034579204708799556234634004705842562329299420551585588232322265609498279231361039397683526002176899737997607538350921282494819816685120478868231090842595792591353576389181664605419273590632452310701393757926374438862479436554656101458985479249471472107699248705141561173712162097645050207626741418394746768164124670747173806773839597678289144754574734901040652010616194325729394023497262795568290483391326776172203388816276143223100903063086097060671378537506215702097576424605396225829921915151624090646742547987876299045332164101681114965791902981323550059875554202160881410486800946958238200767776068800905156439104937878902630802229026038558376052682025048018360113971819953917492535105743883667564195635498783445254231425089663831105369011694312663969400247121569845918627337905950490146786267588981716145101263064118596121741830302772515682282427194397934820742615189129211740981191425117917799767751060222539769267812947175474295243812595876964356919305482207550832587361273920159765406099319385252761850724428775715,3.93911304669283686940834842507119979928487342306442535339638456136702157392669015607231198530090140243949188290043429681557054024497519997714555187094318119446656556235082719330646782894759630438224022549553159147839217538004290128346087094038704007635212437747396661652367449483064282116458523952847341804070956765337261810846795283243730734590753449997447035281029295162928561049306004649118029649069256105503936796313664026977955159526283914846577547135764309851062923566730093681247668624871510666978126929508258099172045717391063101370239395419225705660926248842628084124376628056009064933668417324363913211419327954479103622167143221861590472148278185932670718814750047414193099895865869943477950105875157760091959759003434005966714649800873204258385294726671809906947015516595685711589454524234633598253319737514012268529650713739946676006981825396015444889386661029474872321206464973652372992130362462446398118626962435894308122356649646871349298187623711624971863476352762452221531183277320146100515317455662186611756111268760306975797019057296312184964013993084636666054078035009036249564083908773875800800166359587268483598525125806091226592778234809046332031551598992262638508581536585324305299591750302881483402739828364598398277730258197204969256091757799115119279623658639479367023067719518871651401707913451169051716348607113140192819952450181861796320610091212802617662333291955214929303347143495395840187888757139608191824192807233083558513911809059740349333087862760616275786722727908487366481453538363428895942223277133414813782540149625894704335654023680217631160052319030202630292942814891747431353863732117821363156846713863280617323679888536660636763839907093252497571827138167886149907772607307351368861795816765379220178268412856307579450653416268935107888700416468284108022921355702851498202881502762305540563232079766276637149902654506931054207254907043868092497807310230653405754717803877751418950428686594560372055456167827239476527970744301094268551441890020407558514144268177782841988620322994163840112592854907705270880910991400937352699877335762302999419793473129331441989800560461441763701563331940266726598599293771986578531341036022144096025745155626608882782484494825814636845245413589466189311555767748030432015023292022231992210329782566184971816685421724834819675158353561452463411398141131533561617853176875463475127794571247641075930817108546879442258495905380115608124074575312893808818647331957099686532636924786401829250331323516175691344769031519765960343036596327787933330699717223235941567369627380749831452883229157945444590678814697824995710977262891494397099520222876736838798922496231008700179679987264466109787010313153842130194074782194326215333849204597293821883655534230029263086716683924996834814477422800580002681248614408636157256745534681222987070933199461219239318856812325932811189024056557789637085405421384060709459119263501223615502437218473705700310779175993531915209583296165864005423678994006648697891946757802094451363373198938559)"), a, new Apfloat("5e-2999")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-2, 30), new Apfloat("1.000000000e-40")), new Apfloat(1)); assertEquals("(-2,1e-40), (1,0) precision", 30, a.precision()); assertEquals("(-2,1e-40), (1,0) value", new Apcomplex("(-0.422966208408801687364597406061,0.661266183461804764467239865563)"), a, new Apfloat("5e-30")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-2, 30), new Apfloat("-1.000000000e-40")), new Apfloat(1)); assertEquals("(-2,-1e-40), (1,0) precision", 30, a.precision()); assertEquals("(-2,-1e-40), (1,0) value", new Apcomplex("(-0.422966208408801687364597406061,-0.661266183461804764467239865563)"), a, new Apfloat("5e-30")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(-1, 30), new Apfloat(1, 30)), new Apcomplex(new Apfloat(-1, 30), new Apfloat(-1, 30))); assertEquals("(-1,1), (-1,-1) precision", 30, a.precision()); assertEquals("(-1,1), (-1,-1) value", new Apcomplex("-1.198140234735592207439922492280"), a, new Apfloat("5e-29")); a = ApcomplexMath.agm(new Apcomplex(new Apfloat(1, 30), new Apfloat(1, 30)), new Apcomplex(new Apfloat(1, 30), new Apfloat(-1, 30))); assertEquals("(1,1), (1,-1) precision", 30, a.precision()); assertEquals("(1,1), (1,-1) value", new Apcomplex("1.198140234735592207439922492280"), a, new Apfloat("5e-29")); a = ApcomplexMath.agm(new Apint(1, 12), new Apint(0, 12)); assertEquals("1, 0 radix", 12, a.radix()); a = ApcomplexMath.agm(new Apcomplex(Apint.ZERO, new Apint(1, 12)), new Apcomplex(Apint.ZERO, new Apint(-1, 12))); assertEquals("i, -i radix", 12, a.radix()); try { ApcomplexMath.agm(new Apcomplex(new Apfloat(1)), new Apcomplex(new Apfloat(2), new Apfloat(3))); fail("AGM to infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; can't calculate this to infinite precision } } public static void testLog() { Apcomplex a = ApcomplexMath.log(new Apcomplex(new Apfloat(2, 100))); assertEquals("2, 100 precision", 100, a.precision()); assertEquals("2, 100 value", new Apcomplex("0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687"), a, new Apfloat("5e-99")); a = ApcomplexMath.log(new Apcomplex(new Apfloat(-2, 100))); assertEquals("-2, 100 precision", 100, a.precision()); assertEquals("-2, 100 value", new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067)"), a, new Apfloat("5e-99")); a = ApcomplexMath.log(new Apcomplex(Apfloat.ZERO, new Apfloat(2, 100))); assertEquals("2i, 100 precision", 100, a.precision()); assertEquals("2i, 100 value", new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534)"), a, new Apfloat("5e-99")); a = ApcomplexMath.log(new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 100))); assertEquals("-2i, 100 precision", 100, a.precision()); assertEquals("-2i, 100 value", new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,-1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534)"), a, new Apfloat("5e-99")); a = ApcomplexMath.log(new Apcomplex("(1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573,1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573)")); assertEquals("(sqrt2,sqrt2), 100 precision", 99, a.precision()); assertEquals("(sqrt2,sqrt2), 100 value", new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,0.785398163397448309615660845819875721049292349843776455243736148076954101571552249657008706335529266996)"), a, new Apfloat("5e-99")); a = ApcomplexMath.log(new Apcomplex("(1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573,-1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573)")); assertEquals("(sqrt2,-sqrt2), 100 precision", 99, a.precision()); assertEquals("(sqrt2,-sqrt2), 100 value", new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,-0.785398163397448309615660845819875721049292349843776455243736148076954101571552249657008706335529266996)"), a, new Apfloat("5e-99")); a = ApcomplexMath.log(new Apcomplex("(-1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573,1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573)")); assertEquals("(-sqrt2,sqrt2), 100 precision", 100, a.precision()); assertEquals("(-sqrt2,sqrt2), 100 value", new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,2.356194490192344928846982537459627163147877049531329365731208444230862304714656748971026119006587801)"), a, new Apfloat("5e-99")); a = ApcomplexMath.log(new Apcomplex("(-1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573,-1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573)")); assertEquals("(-sqrt2,-sqrt2), 100 precision", 100, a.precision()); assertEquals("(-sqrt2,-sqrt2), 100 value", new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,-2.356194490192344928846982537459627163147877049531329365731208444230862304714656748971026119006587801)"), a, new Apfloat("5e-99")); a = ApcomplexMath.log(new Apcomplex(new Apfloat(3, 150, 16), new Apfloat(3, 150, 16))); assertEquals("(3,3), 150 precision", 150, a.precision()); assertEquals("(3,3), 150 value", new Apcomplex(new Apfloat("1.71F7B3A6B918664C890B67210734F80D5E8DE46CF12CE907029E7A98171EB2A29E73BDE243BC6E9C7B3CA0B0A9179C5DD8F36C21FF43CD43E2E3768598D9A277261BF9ED2F9A4507D5456", Apfloat.DEFAULT, 16), new Apfloat("0.C90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C43", Apfloat.DEFAULT, 16)), a, ApfloatMath.scale(new Apfloat(5, 1, 16), -148)); a = ApcomplexMath.log(new Apcomplex("1")); assertEquals("1", new Apcomplex("0"), a); a = ApcomplexMath.log(new Apcomplex("-1.1")); assertEquals("-1.1, real precision", 1, a.real().precision()); assertEquals("-1.1, precision", 2, a.precision()); a = ApcomplexMath.log(new Apcomplex("-1.01")); assertEquals("-1.01, real precision", 1, a.real().precision()); assertEquals("-1.01, precision", 3, a.precision()); a = ApcomplexMath.log(new Apcomplex(new Apfloat("-1.1", 3))); assertEquals("-1.1, 3, real precision", 2, a.real().precision()); assertEquals("-1.1, 3, precision", 3, a.precision()); a = ApcomplexMath.log(new Apcomplex("(1.1,0.1)")); assertEquals("(1.1,0.1), precision", 1, a.precision()); a = ApcomplexMath.log(new Apcomplex("(1.01,0.01)")); assertEquals("(1.01,0.01), precision", 1, a.precision()); a = ApcomplexMath.log(new Apcomplex("(0.100000,0.100000)")); assertEquals("(0.1,0.1) precision", 6, a.precision()); assertEquals("(0.1,0.1) value", new Apcomplex("(-1.95601,0.785398)"), a, new Apfloat("5e-5")); a = ApcomplexMath.log(new Apcomplex(Apfloat.ZERO, new Apfloat("2.567534329783818000500533029709932117494558299117260796421579784603311989535237879614227625064708170e2171472", 100))); assertEquals("(0,e^5000000), 100 precision", 106, a.precision()); assertEquals("(0,e^5000000), 100 value", new Apcomplex(new Apfloat(5000000), new Apfloat("1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534")), a, new Apfloat("5e-99")); a = ApcomplexMath.log(new Apcomplex(Apfloat.ZERO, new Apfloat("3.894787261069254290252471079176073765185215930321023940272302235080330044710873765250549604329029361e-2171473", 100))); assertEquals("(0,-e^5000000), 100 precision", 100, a.precision()); assertEquals("(0,-e^5000000), 100 value", new Apcomplex(new Apfloat(-5000000), new Apfloat("1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534")), a, new Apfloat("5e-92")); a = ApcomplexMath.log(new Apcomplex(new Apfloat(-2, 100, 2))); assertEquals("-2, 100 radix 2 precision", 100, a.precision()); assertEquals("-2, 100 radix 2 value", new Apcomplex(new Apfloat("0.10110001011100100001011111110111110100011100111101111001101010111100100111100011101100111001100000000011111100101111011010101111010000001111001101000011001001100111001010011000101101100010110110001010000011010001011101011011100010111010101011111010001010111110011110111000011101100010000001101101111010111010110010011000010101011001", Apfloat.DEFAULT, 2), new Apfloat("11.001001000011111101101010100010001000010110100011000010001101001100010011000110011000101000101110000000110111000001110011010001001010010000001001001110000010001000101001100111110011000111010000000010000010111011111010100110001110110001001110011011001000100101000101001010000010000111100110001110001101000000010011011101111011111001", Apfloat.DEFAULT, 2)), a, new Apfloat("1e-99", 1, 2)); a = ApcomplexMath.log(new Apcomplex(new Apfloat(-2, 100, 2), new Apfloat(-2, 100, 2))); assertEquals("-2-2i, 100 radix 2 precision", 101, a.precision()); assertEquals("-2-2i, 100 radix 2 value", new Apcomplex(new Apfloat("1.0000101000101011001000111111001110111010101101110011011010000001101011101101010110001101011001000000", Apfloat.DEFAULT, 2), new Apfloat("-10.010110110010111110001111111001100110010000111010010001101001111001001110010100110010011110100010100", Apfloat.DEFAULT, 2)), a, new Apfloat("1e-99", 1, 2)); a = ApcomplexMath.log(new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 100, 11))); assertEquals("-2, 100 radix 11 precision", 100, a.precision()); assertEquals("-2, 100 radix 11 value", new Apcomplex(new Apfloat("0.76964056aa1953a291444455a87588497353a063511118935186a366a24a331895629125a9a14432876a887204a134a72a99", Apfloat.DEFAULT, 11), new Apfloat("-1.63080356988524267266268493926a2097433442442708750a82107002329588113725817362690940a8831908396172469a", Apfloat.DEFAULT, 11)), a, new Apfloat("1e-100", 1, 11)); try { ApcomplexMath.log(new Apcomplex("0")); fail("log of zero accepted"); } catch (ArithmeticException ae) { // OK; result would be -infinite } try { ApcomplexMath.log(new Apcomplex(Apfloat.ZERO, new Apfloat(2))); fail("log to infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; can't calculate this to infinite precision } } public static void testLogBase() { Apcomplex a = ApcomplexMath.log(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100)), new Apcomplex(new Apfloat(2, 100), new Apfloat(3, 100))); assertEquals("(3,4) base (2,3), 100 precision", 100, a.precision()); assertEquals("(3,4) base (2,3), 100 value", new Apcomplex("(1.1397284224569002062964218052429388242925638371440336662842481166316121503938668267670478367736422303,-0.1503520693183908310389743432512223715076049306602668639335618106843010268220651900947797357015316935)"), a, new Apfloat("5e-98")); a = ApcomplexMath.log(new Apcomplex("(3.0000,4.0000)"), new Apcomplex("2.000")); assertEquals("(3,4) base 2, precision", 4, a.precision()); assertEquals("(3,4) base 2, value", new Apcomplex("(2.322,1.338)"), a, new Apfloat("0.005")); a = ApcomplexMath.log(new Apcomplex("3.0000"), new Apcomplex("(2.00000,3.00000)")); assertEquals("3 base (2,3), precision", 5, a.precision()); assertEquals("3 base (2,3), value", new Apcomplex("(0.53970,-0.41358)"), a, new Apfloat("0.00005")); a = ApcomplexMath.log(new Apfloat("3.00"), new Apfloat("-2.00")); assertEquals("3 base -2, precision", 3, a.precision()); assertEquals("3 base -2, value", new Apcomplex("(0.0736,-0.3335)"), a, new Apfloat("0.0005")); a = ApcomplexMath.log(new Apfloat("-3.00"), new Apfloat("2.00")); assertEquals("-3 base 2, precision", 3, a.precision()); assertEquals("-3 base 2, value", new Apcomplex("(1.58,4.53)"), a, new Apfloat("0.05")); a = ApcomplexMath.log(new Apfloat(16, 400), new Apfloat(2)); assertEquals("4 base 2, precision 400", 400, a.precision()); assertEquals("4 base 2, value", new Apfloat(4), a, new Apfloat("5e-399")); a = ApcomplexMath.log(new Apfloat(16), new Apfloat(2, 500)); assertEquals("4 base 2, precision 500", 500, a.precision()); assertEquals("4 base 2, value", new Apfloat(4), a, new Apfloat("5e-499")); a = ApcomplexMath.log(new Apcomplex("(2.0000, 4.0000)"), new Apfloat("1.01", 7)); assertEquals("(2,4) base 1.01, precision", 5, a.precision()); assertEquals("(2,4) base 1.01, value", new Apcomplex("(150.53,111.27)"), a, new Apfloat("5e-2")); a = ApcomplexMath.log(new Apfloat("1.01", 7), new Apcomplex("(2.0000, 4.0000)")); assertEquals("1.01 base (2,4), precision", 5, a.precision()); assertEquals("1.01 base (2,4), value", new Apcomplex("(0.0042959,-0.0031753)"), a, new Apfloat("5e-7")); } public static void testExp() { Apcomplex a = ApcomplexMath.exp(new Apcomplex(new Apfloat(2, 100))); assertEquals("2, 100 precision", 100, a.precision()); assertEquals("2, 100 value", new Apfloat("7.389056098930650227230427460575007813180315570551847324087127822522573796079057763384312485079121794"), a, new Apfloat("5e-98")); a = ApcomplexMath.exp(new Apcomplex(new Apfloat(0), new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"))); assertEquals("(0,pi), 100 precision", 100, a.precision()); assertEquals("(0,pi), 100 value", new Apfloat("-1"), a, new Apfloat("5e-98")); a = ApcomplexMath.exp(new Apcomplex(new Apfloat(2, 100), new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"))); assertEquals("(2,pi), 100 precision", 100, a.precision()); assertEquals("(2,pi), 100 value", new Apfloat("-7.389056098930650227230427460575007813180315570551847324087127822522573796079057763384312485079121794"), a, new Apfloat("5e-98")); a = ApcomplexMath.exp(new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534)")); assertEquals("(log2,pi/2), 100 precision", 100, a.precision()); assertEquals("(log2,pi/2), 100 value", new Apcomplex(Apfloat.ZERO, new Apfloat(2)), a, new Apfloat("5e-99")); a = ApcomplexMath.exp(new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,-1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534)")); assertEquals("(log2,-pi/2), 100 precision", 100, a.precision()); assertEquals("(log2,-pi/2), 100 value", new Apcomplex(Apfloat.ZERO, new Apfloat(-2)), a, new Apfloat("5e-99")); a = ApcomplexMath.exp(new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,0.785398163397448309615660845819875721049292349843776455243736148076954101571552249657008706335529266996)")); assertEquals("(log2,pi/4), 100 precision", 100, a.precision()); assertEquals("(log2,pi/4), 100 value", new Apcomplex("(1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573,1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573)"), a, new Apfloat("5e-99")); a = ApcomplexMath.exp(new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,-0.785398163397448309615660845819875721049292349843776455243736148076954101571552249657008706335529266996)")); assertEquals("(log2,-pi/4), 100 precision", 100, a.precision()); assertEquals("(log2,-pi/4), 100 value", new Apcomplex("(1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573,-1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573)"), a, new Apfloat("5e-99")); a = ApcomplexMath.exp(new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,2.356194490192344928846982537459627163147877049531329365731208444230862304714656748971026119006587801)")); assertEquals("(log2,3pi/4), 100 precision", 100, a.precision()); assertEquals("(log2,3pi/4), 100 value", new Apcomplex("(-1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573,1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573)"), a, new Apfloat("5e-99")); a = ApcomplexMath.exp(new Apcomplex("(0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687,-2.356194490192344928846982537459627163147877049531329365731208444230862304714656748971026119006587801)")); assertEquals("(log2,-3pi/4), 100 precision", 100, a.precision()); assertEquals("(log2,-3pi/4), 100 value", new Apcomplex("(-1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573,-1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573)"), a, new Apfloat("5e-99")); a = ApcomplexMath.exp(new Apcomplex(new Apfloat(3, 150, 16), new Apfloat("3.243F6A8885A308D313198A2E03707344A4093822299F31D0082EFA98EC4E6C89452821E638D01377BE5466CF34E90C6CC0AC29B7C97C50DD3F84D5B5B54709179216D5D98979FB1BD1311", 150, 16))); assertEquals("(3,pi), 150 precision", 150, a.precision()); assertEquals("(3,pi), 150 value", new Apfloat("-14.15E5BF6FB105F2D4BDFC53744C3A390585839728AA90A12389790C837E6FF2A68ABFE2D58DAFA5273C74EB175B9D0BD5584DFC81BE96F62CE66F428A2A50FFCBDF4083E8EE811BE42F", Apfloat.DEFAULT, 16), a, ApfloatMath.scale(new Apfloat(5, 1, 16), -147)); a = ApcomplexMath.exp(new Apcomplex(new Apfloat(0, 1, 17), new Apfloat(0, 1, 17))); assertEquals("1 radix", 17, a.radix()); assertEquals("1 prec", Apfloat.INFINITE, a.precision()); assertEquals("1 value", new Apfloat(1), a); a = ApcomplexMath.exp(new Apcomplex(new Apfloat("-100000000000000000000", 20, 17), new Apfloat("0.1", 1, 17))); assertEquals("underflow radix", 17, a.radix()); assertEquals("underflow prec", Apfloat.INFINITE, a.precision()); assertEquals("underflow value", new Apfloat(0), a); a = ApcomplexMath.exp(new Apcomplex("(0.1,3.14159)")); assertEquals("(0.1,pi), precision", 2, a.precision()); a = ApcomplexMath.exp(new Apcomplex("(0.01,3.14159)")); assertEquals("(0.01,pi), precision", 3, a.precision()); a = ApcomplexMath.exp(new Apcomplex(new Apfloat("0.1", 2), new Apfloat("3.14159"))); assertEquals("(0.1,pi), 2, precision", 3, a.precision()); a = ApcomplexMath.exp(new Apcomplex(new Apfloat("1e-10", 32), new Apfloat("3.1415926535897932384626433832795"))); assertEquals("(1e-10,pi)", new Apcomplex("-1.0000000001000000000050000000002"), a, new Apfloat("5e-31")); a = ApcomplexMath.exp(new Apcomplex(new Apfloat(5000000, 21), new Apfloat("1.570796326794897"))); assertEquals("(5000000,pi/2), 15 precision", 15, a.precision()); assertEquals("(5000000,pi/2), 15 value", new Apcomplex(Apfloat.ZERO, new Apfloat("2.56753432978382e2171472")), a, new Apfloat("5e2171458")); a = ApcomplexMath.exp(new Apcomplex(new Apfloat(5000000, 106), new Apfloat("4.712388980384689857693965074919254326295754099062658731462416888461724609429313497942052238013175602"))); assertEquals("(5000000,3pi/2), 100 precision", 100, a.precision()); assertEquals("(5000000,3pi/2), 100 value", new Apcomplex(Apfloat.ZERO, new Apfloat("-2.567534329783818000500533029709932117494558299117260796421579784603311989535237879614227625064708170e2171472")), a, new Apfloat("5e2171373")); a = ApcomplexMath.exp(new Apcomplex(new Apfloat(-5000000, 106), new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"))); assertEquals("(-5000000,pi), 100 precision", 100, a.precision()); assertEquals("(-5000000,pi), 100 value", new Apfloat("-3.894787261069254290252471079176073765185215930321023940272302235080330044710873765250549604329029362e-2171473"), a, new Apfloat("5e-2171572")); a = ApcomplexMath.exp(new Apcomplex(new Apfloat("-1e25", 50), new Apfloat("3.1415926535897932384626433832795028841971693993751"))); assertEquals("(-1e25,pi), 50 value", new Apfloat(0), a); a = ApcomplexMath.exp(new Apcomplex(new Apfloat("-1e25"), new Apfloat("1e100"))); assertEquals("(-1e25,1e100) value", new Apfloat(0), a); a = ApcomplexMath.exp(new Apcomplex("(-21237598959199934509.830775042768,3.1415926535897932384626433832795)")); assertEquals("(-21237598959199934509.830775042768,pi) value", new Apfloat(0), a); a = ApcomplexMath.exp(new Apcomplex("(-2.1237598959199920000000000000000000e19,3.141592653589793)")); assertEquals("(-2.123759895919992e19,pi) precision", 16, a.precision()); assertEquals("(-2.123759895919992e19,pi) value", new Apfloat("-3.462892031805012e-9223372036854769507"), a, new Apfloat("5e-9223372036854769491")); Apfloat r = new Apfloat("-2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069551702761838606261331384583000752044933826560297606737113200709328709127443747047230696977209310141692836819025515108657463772111252389784425056953696770785449969967946864454905987931636889230098793127736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117301238197068416140397019837679320683282376464804295311802328782509819455815301756717361332069811250996181881593041690351598888519345807273866738589422879228499892086805825749279610484198444363463244968487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016768396424378140592714563549061303107208510383750510115747704171898610687396965521267154688957035035"), pi = new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420199"); for (int prec = 500; prec <= 800; prec += 100) { Apcomplex exp = ApcomplexMath.exp(new Apcomplex(new Apfloat(1, prec), pi.precision(prec))); assertEquals("exp prec " + prec + " precision", prec, exp.precision()); assertEquals("exp prec " + prec + " value", r.precision(prec), exp, new Apfloat("5e-" + (prec - 1))); } for (int prec = 900; prec <= 1000; prec++) { Apcomplex exp = ApcomplexMath.exp(new Apcomplex(new Apfloat(1, prec), pi.precision(prec))); assertEquals("exp prec " + prec + " precision", prec, exp.precision()); assertEquals("exp prec " + prec + " value", r.precision(prec), exp, new Apfloat("5e-" + (prec - 1))); } try { ApcomplexMath.exp(new Apcomplex(new Apfloat("50000000000000000000", 500000000), new Apfloat(3, 500000000))); fail("Overflow should have occurred"); } catch (OverflowException oe) { // OK; result would overflow } try { ApcomplexMath.exp(new Apcomplex(new Apfloat(2), new Apfloat(2))); fail("exp to infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; can't calculate this to infinite precision } } public static void testPow() { Apcomplex a = ApcomplexMath.pow(new Apcomplex(new Apfloat(2, 100)), new Apcomplex(new Apfloat("0.5", 100))); assertEquals("2^0.5, 100 precision", 100, a.precision(), 1); assertEquals("2^0.5, 100 value", new Apfloat("1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573"), a, new Apfloat("5e-98")); a = ApcomplexMath.pow(new Apcomplex(new Apfloat(-2, 100)), new Apcomplex(new Apfloat("0.5", 100))); assertEquals("(-2)^0.5, 100 precision", 100, a.precision(), 1); assertEquals("(-2)^0.5, 100 value", new Apcomplex("(0,1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573)"), a, new Apfloat("5e-98")); a = ApcomplexMath.pow(new Apcomplex(new Apfloat(5, 100), new Apfloat(4, 100)), new Apcomplex(new Apfloat(3, 100), new Apfloat(2, 100))); assertEquals("(5,4)^(3,2), 100 precision", 99, a.precision(), 1); assertEquals("(5,4)^(3,2), 100 value", new Apcomplex("(58.2145009705915246565265271223031301774886834072803476475245473202072182772155725270313930579883159,-35.3234369348583753301237874184698198860952187848530861615372916445617840467298560954959137658317125)"), a, new Apfloat("5e-97")); Apfloat r = new Apfloat("1.193EA7AAD030A976A4198D55053B7CB5BE1442D9B7E08DF03D97EEEA5149358CAA9782D20CC698505071F733039A8ED5625C15071EA7BCA1CF37D8F11024C66486D094E21E74D0A547DF6", 150, 16); a = ApcomplexMath.pow(new Apcomplex(r, r), new Apcomplex(r, r)); assertEquals("3, 150 precision", 150, a.precision(), 1); assertEquals("3, 150 value", new Apcomplex(new Apfloat("0.26ea28ff7cb530fc94a0b61e891cb2a15e1c72d7e9421ab41a2d0c46f1ba18f0b43409b5440adf17b33a95646b30b96f44634e286d546b2f543415d6d2deaaf79a715fa30e30cb858edb14", Apfloat.DEFAULT, 16), new Apfloat("0.aae89b585652b078f623e7f850ebc3cd7c87afeb0a32feb1003d57a82352857778a89519b99e0001e1c276d3ddb09e1c07fc6b8129240a724aea584a7283a5e98bba61f57b20926ffac626", Apfloat.DEFAULT, 16)), a, ApfloatMath.scale(new Apfloat(5, 1, 16), -149)); a = ApcomplexMath.pow(new Apfloat(2), new Apfloat(0)); assertEquals("2^0", new Apfloat(1), a); a = ApcomplexMath.pow(new Apfloat(2), new Apfloat(1)); assertEquals("2^1", new Apfloat(2), a); a = ApcomplexMath.pow(new Apfloat(-2), new Apfloat(0)); assertEquals("(-2)^0", new Apfloat(1), a); a = ApcomplexMath.pow(new Apfloat(-2), new Apfloat(1)); assertEquals("(-2)^1", new Apfloat(-2), a); a = ApcomplexMath.pow(Apcomplex.I, new Apfloat(0)); assertEquals("i^0", new Apfloat(1), a); a = ApcomplexMath.pow(Apcomplex.I, new Apfloat(1)); assertEquals("i^1", Apcomplex.I, a); a = ApcomplexMath.pow(new Apfloat(0), new Apfloat(2)); assertEquals("0^2", new Apfloat(0), a); a = ApcomplexMath.pow(new Apfloat(1), new Apfloat(2)); assertEquals("1^2", new Apfloat(1), a); a = ApcomplexMath.pow(new Apfloat(1), Apcomplex.I); assertEquals("1^i", new Apfloat(1), a); try { ApcomplexMath.pow(new Apfloat("1.2"), new Apfloat("57")); } catch (LossOfPrecisionException lope) { // OK } a = ApcomplexMath.pow(new Apfloat("1.02"), new Apfloat("57")); assertEquals("1.02^57, precision", 1, a.precision()); a = ApcomplexMath.pow(new Apfloat("1.2"), new Apfloat("1.0")); assertEquals("1.2^1.0, precision", 2, a.precision()); a = ApcomplexMath.pow(new Apfloat("1.2"), new Apfloat("1")); assertEquals("1.2^1, precision", 1, a.precision()); a = ApcomplexMath.pow(new Apfloat("1.02"), new Apfloat("1.00")); assertEquals("1.02^1.00, precision", 3, a.precision()); a = ApcomplexMath.pow(new Apfloat("1.02"), new Apfloat("1")); assertEquals("1.02^1, precision", 1, a.precision()); a = ApcomplexMath.pow(new Apfloat("1.2"), new Apfloat("0.01")); assertEquals("1.2^0.01, precision", 4, a.precision()); a = ApcomplexMath.pow(new Apfloat("1.02"), new Apfloat("0.01")); assertEquals("1.02^0.01, precision", 5, a.precision()); try { ApcomplexMath.pow(new Apcomplex(new Apfloat(0)), new Apcomplex(new Apfloat(0))); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { ApcomplexMath.pow(new Apcomplex(new Apfloat(0)), new Apcomplex("-0.1")); fail("0^-0.1 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { ApcomplexMath.pow(new Apfloat(0), Apcomplex.I); fail("0^i accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { ApcomplexMath.pow(new Apcomplex(new Apfloat(0)), new Apcomplex("(0,0.1)")); fail("0^0.1i accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { ApcomplexMath.pow(new Apcomplex(new Apfloat(100, 100), new Apfloat(100, 100)), new Apcomplex(new Apfloat(5000000000000000000L, 100), new Apfloat(5000000000000000000L, 100))); fail("Overflow should have occurred"); } catch (OverflowException oe) { // OK; result would overflow } try { ApcomplexMath.pow(new Apcomplex(new Apfloat(3), new Apfloat(3)), new Apcomplex(new Apfloat(-1), new Apfloat(-1))); fail("pow to infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; can't calculate this to infinite precision } } public static void testArg() { Apcomplex a = ApcomplexMath.arg(new Apcomplex("(-2.0000,2.0000)")); assertEquals("(-2,2), precision", 5, a.precision()); assertEquals("(-2,2), value", new Apfloat("2.3562"), a, new Apfloat("0.0005")); } public static void testAcosh() { Apcomplex a = ApcomplexMath.acosh(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(2.30550903124347694204183593813343089732908234612766434427244403789502387715767721380519816885689075,0.9368124611557199029125245765756089164871812290143448233044479241680079302681295000053794681278219233)"), a, new Apfloat("5e-98")); a = ApcomplexMath.acosh(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(2.30550903124347694204183593813343089732908234612766434427244403789502387715767721380519816885689075,-0.9368124611557199029125245765756089164871812290143448233044479241680079302681295000053794681278219233)"), a, new Apfloat("5e-98")); a = ApcomplexMath.acosh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(2.30550903124347694204183593813343089732908234612766434427244403789502387715767721380519816885689075,2.204780192434073335550118806703893967709988170360760997670496668139808476018079498622655357214295145)"), a, new Apfloat("5e-98")); a = ApcomplexMath.acosh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(2.30550903124347694204183593813343089732908234612766434427244403789502387715767721380519816885689075,-2.204780192434073335550118806703893967709988170360760997670496668139808476018079498622655357214295145)"), a, new Apfloat("5e-98")); a = ApcomplexMath.acosh(new Apfloat(2, 10)); assertEquals("(2,0), 10 precision", 10, a.precision(), 1); assertEquals("(2,0), 10 value", new Apcomplex("1.316957897"), a, new Apfloat("5e-9")); a = ApcomplexMath.acosh(new Apfloat(-2, 10)); assertEquals("(-2,0), 10 precision", 10, a.precision(), 1); assertEquals("(-2,0), 10 value", new Apcomplex("(1.316957897,3.141592654)"), a, new Apfloat("5e-9")); a = ApcomplexMath.acosh(new Apcomplex(Apfloat.ZERO, new Apfloat(2, 10))); assertEquals("(0,2), 10 precision", 10, a.precision(), 1); assertEquals("(0,2), 10 value", new Apcomplex("(1.443635475,1.570796327)"), a, new Apfloat("5e-9")); a = ApcomplexMath.acosh(new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 10))); assertEquals("(0,-2), 10 precision", 10, a.precision(), 1); assertEquals("(0,-2), 10 value", new Apcomplex("(1.443635475,-1.570796327)"), a, new Apfloat("5e-9")); a = ApcomplexMath.acosh(new Apcomplex(new Apfloat(1, 100))); assertEquals("1, 100 value", new Apfloat(0), a); } public static void testAsinh() { Apcomplex a = ApcomplexMath.asinh(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(2.299914040879269649955789630663175555365313484764636466611830082402437121311729696004733902877606405,0.9176168533514786557598627486701745415899523820362300027773647609161124445462833451286169894870273957)"), a, new Apfloat("5e-98")); a = ApcomplexMath.asinh(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(2.299914040879269649955789630663175555365313484764636466611830082402437121311729696004733902877606405,-0.9176168533514786557598627486701745415899523820362300027773647609161124445462833451286169894870273957)"), a, new Apfloat("5e-98")); a = ApcomplexMath.asinh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(-2.299914040879269649955789630663175555365313484764636466611830082402437121311729696004733902877606405,0.9176168533514786557598627486701745415899523820362300027773647609161124445462833451286169894870273957)"), a, new Apfloat("5e-98")); a = ApcomplexMath.asinh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(-2.299914040879269649955789630663175555365313484764636466611830082402437121311729696004733902877606405,-0.9176168533514786557598627486701745415899523820362300027773647609161124445462833451286169894870273957)"), a, new Apfloat("5e-98")); a = ApcomplexMath.asinh(new Apfloat(2, 10)); assertEquals("(2,0), 10 precision", 10, a.precision(), 1); assertEquals("(2,0), 10 value", new Apcomplex("1.443635475"), a, new Apfloat("5e-9")); a = ApcomplexMath.asinh(new Apfloat(-2, 10)); assertEquals("(-2,0), 10 precision", 10, a.precision(), 1); assertEquals("(-2,0), 10 value", new Apcomplex("(-1.443635475)"), a, new Apfloat("5e-9")); a = ApcomplexMath.asinh(new Apcomplex(Apfloat.ZERO, new Apfloat(2, 10))); assertEquals("(0,2), 10 precision", 10, a.precision(), 1); assertEquals("(0,2), 10 value", new Apcomplex("(1.316957897,1.570796327)"), a, new Apfloat("5e-9")); a = ApcomplexMath.asinh(new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 10))); assertEquals("(0,-2), 10 precision", 10, a.precision(), 1); assertEquals("(0,-2), 10 value", new Apcomplex("(-1.316957897,-1.570796327)"), a, new Apfloat("5e-9")); a = ApcomplexMath.asinh(new Apcomplex("0")); assertEquals("0, 100 value", new Apfloat(0), a); } public static void testAtanh() { Apcomplex a = ApcomplexMath.atanh(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(0.1175009073114338884127342577870855161752247622030620101123480342515004695503565955468640257240191129,1.409921049596575522530619384460420782588207051908724814771070766475530084440199227135813201495737847)"), a, new Apfloat("5e-98")); a = ApcomplexMath.atanh(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(0.1175009073114338884127342577870855161752247622030620101123480342515004695503565955468640257240191129,-1.409921049596575522530619384460420782588207051908724814771070766475530084440199227135813201495737847)"), a, new Apfloat("5e-98")); a = ApcomplexMath.atanh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(-0.1175009073114338884127342577870855161752247622030620101123480342515004695503565955468640257240191129,1.409921049596575522530619384460420782588207051908724814771070766475530084440199227135813201495737847)"), a, new Apfloat("5e-98")); a = ApcomplexMath.atanh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(-0.1175009073114338884127342577870855161752247622030620101123480342515004695503565955468640257240191129,-1.409921049596575522530619384460420782588207051908724814771070766475530084440199227135813201495737847)"), a, new Apfloat("5e-98")); a = ApcomplexMath.atanh(new Apfloat(2, 10)); assertEquals("(2,0), 10 precision", 10, a.precision(), 1); assertEquals("(2,0), 10 value", new Apcomplex("(0.549306144,-1.570796327)"), a, new Apfloat("5e-9")); a = ApcomplexMath.atanh(new Apfloat(-2, 10)); assertEquals("(-2,0), 10 precision", 10, a.precision(), 1); assertEquals("(-2,0), 10 value", new Apcomplex("(-0.549306144,1.570796327)"), a, new Apfloat("5e-9")); a = ApcomplexMath.atanh(new Apcomplex(Apfloat.ZERO, new Apfloat(2, 10))); assertEquals("(0,2), 10 precision", 10, a.precision(), 1); assertEquals("(0,2), 10 value", new Apcomplex("(0,1.107148718)"), a, new Apfloat("5e-9")); a = ApcomplexMath.atanh(new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 10))); assertEquals("(0,-2), 10 precision", 10, a.precision(), 1); assertEquals("(0,-2), 10 value", new Apcomplex("(0,-1.107148718)"), a, new Apfloat("5e-9")); a = ApcomplexMath.atanh(new Apcomplex("0")); assertEquals("0, 100 value", new Apfloat(0), a); try { ApcomplexMath.atanh(new Apcomplex("1")); fail("atanh(1) accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } try { ApcomplexMath.atanh(new Apcomplex("-1")); fail("atanh(-1) accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } public static void testCosh() { Apcomplex a = ApcomplexMath.cosh(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(-6.580663040551156432560744126538803616711267345515897773220218329756121215365251384163430874396326777,-7.581552742746544353716345286538426009387527590948852812949363456244614022672964969341075109130625439)"), a, new Apfloat("5e-98")); a = ApcomplexMath.cosh(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(-6.580663040551156432560744126538803616711267345515897773220218329756121215365251384163430874396326777,7.581552742746544353716345286538426009387527590948852812949363456244614022672964969341075109130625439)"), a, new Apfloat("5e-98")); a = ApcomplexMath.cosh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(-6.580663040551156432560744126538803616711267345515897773220218329756121215365251384163430874396326777,7.581552742746544353716345286538426009387527590948852812949363456244614022672964969341075109130625439)"), a, new Apfloat("5e-98")); a = ApcomplexMath.cosh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(-6.580663040551156432560744126538803616711267345515897773220218329756121215365251384163430874396326777,-7.581552742746544353716345286538426009387527590948852812949363456244614022672964969341075109130625439)"), a, new Apfloat("5e-98")); a = ApcomplexMath.cosh(new Apcomplex("1.00000")); assertEquals("1 value", new Apfloat("1.54308"), a, new Apfloat("5e-5")); assertEquals("1 imag value", new Apfloat(0), a.imag()); a = ApcomplexMath.cosh(new Apcomplex("0")); assertEquals("0 value", new Apfloat(1), a); } public static void testSinh() { Apcomplex a = ApcomplexMath.sinh(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(-6.548120040911001647766811018835324740820888396888583499736134313039666841835229556393917343956455199,-7.619231720321410208487135736804311796557265472675575619426852074665542955161180340917983240028178743)"), a, new Apfloat("5e-98")); a = ApcomplexMath.sinh(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(-6.548120040911001647766811018835324740820888396888583499736134313039666841835229556393917343956455199,7.619231720321410208487135736804311796557265472675575619426852074665542955161180340917983240028178743)"), a, new Apfloat("5e-98")); a = ApcomplexMath.sinh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(6.548120040911001647766811018835324740820888396888583499736134313039666841835229556393917343956455199,-7.619231720321410208487135736804311796557265472675575619426852074665542955161180340917983240028178743)"), a, new Apfloat("5e-98")); a = ApcomplexMath.sinh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(6.548120040911001647766811018835324740820888396888583499736134313039666841835229556393917343956455199,7.619231720321410208487135736804311796557265472675575619426852074665542955161180340917983240028178743)"), a, new Apfloat("5e-98")); a = ApcomplexMath.sinh(new Apcomplex("1.0000")); assertEquals("1 value", new Apfloat("1.1752"), a, new Apfloat("5e-4")); assertEquals("1 imag value", new Apfloat(0), a.imag()); a = ApcomplexMath.sinh(new Apcomplex("0")); assertEquals("0, 100 value", new Apfloat(0), a); } public static void testTanh() { Apcomplex a = ApcomplexMath.tanh(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 101, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(1.0007095360672329393295854724041727462153209051467602180192607299042866403616169551650374279065226404,0.0049082580674960602590787869299327668433742155793555069748955113426747384320810439493273599689927112)"), a, new Apfloat("5e-98")); a = ApcomplexMath.tanh(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 101, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(1.0007095360672329393295854724041727462153209051467602180192607299042866403616169551650374279065226404,-0.0049082580674960602590787869299327668433742155793555069748955113426747384320810439493273599689927112)"), a, new Apfloat("5e-98")); a = ApcomplexMath.tanh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 101, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(-1.0007095360672329393295854724041727462153209051467602180192607299042866403616169551650374279065226404,0.0049082580674960602590787869299327668433742155793555069748955113426747384320810439493273599689927112)"), a, new Apfloat("5e-98")); a = ApcomplexMath.tanh(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 101, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(-1.0007095360672329393295854724041727462153209051467602180192607299042866403616169551650374279065226404,-0.0049082580674960602590787869299327668433742155793555069748955113426747384320810439493273599689927112)"), a, new Apfloat("5e-98")); a = ApcomplexMath.tanh(new Apcomplex("1.0000")); assertEquals("1 value", new Apfloat("0.76159"), a, new Apfloat("5e-5")); assertEquals("1 imag value", new Apfloat(0), a.imag()); a = ApcomplexMath.tanh(new Apcomplex(new Apfloat(5000000, 100), new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"))); assertEquals("(5000000,pi), 100 precision", 4343037, a.precision(), 1); assertEquals("(5000000,pi), 100 value", new Apfloat(1).subtract(new Apfloat("3.03387356179746871517892756452203249280217116298171287391802587502345779082540217305405121824e-4342945")), a, new Apfloat("5e-4343037")); a = ApcomplexMath.tanh(new Apcomplex(new Apfloat(-5000000, 100), new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"))); assertEquals("(-5000000,pi), 100 precision", 4343037, a.precision(), 1); assertEquals("(-5000000,pi), 100 value", new Apfloat(-1).add(new Apfloat("3.03387356179746871517892756452203249280217116298171287391802587502345779082540217305405121824e-4342945")), a, new Apfloat("5e-4343037")); a = ApcomplexMath.tanh(new Apcomplex("0")); assertEquals("0, 100 value", new Apfloat(0), a); } public static void testAcos() { Apcomplex a = ApcomplexMath.acos(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(0.9368124611557199029125245765756089164871812290143448233044479241680079302681295000053794681278219233,-2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), a, new Apfloat("5e-98")); a = ApcomplexMath.acos(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(0.9368124611557199029125245765756089164871812290143448233044479241680079302681295000053794681278219233,2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), a, new Apfloat("5e-98")); // NOTE: result precision is reduced a = ApcomplexMath.acos(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 2); assertEquals("(-3,4), 100 value", new Apcomplex("(2.204780192434073335550118806703893967709988170360760997670496668139808476018079498622655357214295145,-2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), a, new Apfloat("5e-98")); // NOTE: result precision is reduced a = ApcomplexMath.acos(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 2); assertEquals("(-3,-4), 100 value", new Apcomplex("(2.204780192434073335550118806703893967709988170360760997670496668139808476018079498622655357214295145,2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), a, new Apfloat("5e-98")); a = ApcomplexMath.acos(new Apfloat(2, 10)); assertEquals("(2,0), 10 precision", 10, a.precision(), 1); assertEquals("(2,0), 10 value", new Apcomplex("(0,1.316957897)"), a, new Apfloat("5e-9")); a = ApcomplexMath.acos(new Apfloat(-2, 10)); assertEquals("(-2,0), 10 precision", 10, a.precision(), 1); assertEquals("(-2,0), 10 value", new Apcomplex("(3.141592654,-1.316957897)"), a, new Apfloat("5e-9")); a = ApcomplexMath.acos(new Apcomplex(Apfloat.ZERO, new Apfloat(2, 10))); assertEquals("(0,2), 10 precision", 10, a.precision(), 1); assertEquals("(0,2), 10 value", new Apcomplex("(1.570796327,-1.443635475)"), a, new Apfloat("5e-9")); a = ApcomplexMath.acos(new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 10))); assertEquals("(0,-2), 10 precision", 10, a.precision(), 1); assertEquals("(0,-2), 10 value", new Apcomplex("(1.570796327,1.443635475)"), a, new Apfloat("5e-9")); a = ApcomplexMath.acos(new Apcomplex(new Apfloat(1, 100))); assertEquals("1, 100 value", new Apfloat(0), a); a = ApcomplexMath.acos(new Apcomplex(new Apfloat("0.5", 30))); assertEquals("0.5, 30 value", new Apfloat("1.04719755119659774615421446109"), a, new Apfloat("5e-28")); try { ApcomplexMath.acos(new Apcomplex("0")); fail("acos(0) accepted"); } catch (InfiniteExpansionException iee) { // OK; result would have infinite precision } } public static void testAsin() { Apcomplex a = ApcomplexMath.asin(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(0.6339838656391767163187971150641425256114034706732080871830243719859002728749749993086379445432366107,2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), a, new Apfloat("5e-98")); a = ApcomplexMath.asin(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(0.6339838656391767163187971150641425256114034706732080871830243719859002728749749993086379445432366107,-2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), a, new Apfloat("5e-98")); a = ApcomplexMath.asin(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(-0.6339838656391767163187971150641425256114034706732080871830243719859002728749749993086379445432366107,2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), a, new Apfloat("5e-98")); a = ApcomplexMath.asin(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(-0.6339838656391767163187971150641425256114034706732080871830243719859002728749749993086379445432366107,-2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), a, new Apfloat("5e-98")); a = ApcomplexMath.asin(new Apfloat(2, 10)); assertEquals("(2,0), 10 precision", 10, a.precision(), 1); assertEquals("(2,0), 10 value", new Apcomplex("(1.570796327,-1.316957897)"), a, new Apfloat("5e-9")); a = ApcomplexMath.asin(new Apfloat(-2, 10)); assertEquals("(-2,0), 10 precision", 10, a.precision(), 1); assertEquals("(-2,0), 10 value", new Apcomplex("(-1.570796327,1.316957897)"), a, new Apfloat("5e-9")); a = ApcomplexMath.asin(new Apcomplex(Apfloat.ZERO, new Apfloat(2, 10))); assertEquals("(0,2), 10 precision", 10, a.precision(), 1); assertEquals("(0,2), 10 value", new Apcomplex("(0,1.443635475)"), a, new Apfloat("5e-9")); a = ApcomplexMath.asin(new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 10))); assertEquals("(0,-2), 10 precision", 10, a.precision(), 1); assertEquals("(0,-2), 10 value", new Apcomplex("(0,-1.443635475)"), a, new Apfloat("5e-9")); a = ApcomplexMath.asin(new Apcomplex("0")); assertEquals("0, 100 value", new Apfloat(0), a); a = ApcomplexMath.asin(new Apcomplex(new Apfloat("0.5", 30))); assertEquals("0.5, 30 value", new Apfloat("0.523598775598298873077107230547"), a, new Apfloat("5e-29")); } public static void testAtan() { Apcomplex a = ApcomplexMath.atan(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(1.448306995231464542145280451034113536641512650496960876923784338820230643349283451026750333836707538,0.1589971916799991743647610360070187815733054742350614709569622676518259973409283367912158396025096925)"), a, new Apfloat("5e-98")); a = ApcomplexMath.atan(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(1.448306995231464542145280451034113536641512650496960876923784338820230643349283451026750333836707538,-0.1589971916799991743647610360070187815733054742350614709569622676518259973409283367912158396025096925)"), a, new Apfloat("5e-98")); a = ApcomplexMath.atan(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(-1.448306995231464542145280451034113536641512650496960876923784338820230643349283451026750333836707538,0.1589971916799991743647610360070187815733054742350614709569622676518259973409283367912158396025096925)"), a, new Apfloat("5e-98")); a = ApcomplexMath.atan(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(-1.448306995231464542145280451034113536641512650496960876923784338820230643349283451026750333836707538,-0.1589971916799991743647610360070187815733054742350614709569622676518259973409283367912158396025096925)"), a, new Apfloat("5e-98")); a = ApcomplexMath.atan(new Apfloat(2, 10)); assertEquals("(2,0), 10 precision", 10, a.precision(), 1); assertEquals("(2,0), 10 value", new Apcomplex("1.107148718"), a, new Apfloat("5e-9")); a = ApcomplexMath.atan(new Apfloat(-2, 10)); assertEquals("(-2,0), 10 precision", 10, a.precision(), 1); assertEquals("(-2,0), 10 value", new Apcomplex("-1.107148718"), a, new Apfloat("5e-9")); a = ApcomplexMath.atan(new Apcomplex(Apfloat.ZERO, new Apfloat(2, 10))); assertEquals("(0,2), 10 precision", 10, a.precision(), 1); assertEquals("(0,2), 10 value", new Apcomplex("(1.570796327,0.549306144)"), a, new Apfloat("5e-9")); a = ApcomplexMath.atan(new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 10))); assertEquals("(0,-2), 10 precision", 10, a.precision(), 1); assertEquals("(0,-2), 10 value", new Apcomplex("(-1.570796327,-0.549306144)"), a, new Apfloat("5e-9")); a = ApcomplexMath.atan(new Apcomplex("0")); assertEquals("0, 100 value", new Apfloat(0), a); a = ApcomplexMath.atan(new Apcomplex(new Apfloat("0.5", 30))); assertEquals("0.5, 30 value", new Apfloat("0.463647609000806116214256231461"), a, new Apfloat("5e-29")); } public static void testCos() { Apcomplex a = ApcomplexMath.cos(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(-27.03494560307422464769480266827091348467753695567661661019265514673434246483988229429946831870519301,-3.851153334811777536563337123053124569704160846091637003157728595256494186490481089994453362578315815)"), a, new Apfloat("5e-97")); a = ApcomplexMath.cos(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(-27.03494560307422464769480266827091348467753695567661661019265514673434246483988229429946831870519301,3.851153334811777536563337123053124569704160846091637003157728595256494186490481089994453362578315815)"), a, new Apfloat("5e-97")); a = ApcomplexMath.cos(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(-27.03494560307422464769480266827091348467753695567661661019265514673434246483988229429946831870519301,3.851153334811777536563337123053124569704160846091637003157728595256494186490481089994453362578315815)"), a, new Apfloat("5e-97")); a = ApcomplexMath.cos(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(-27.03494560307422464769480266827091348467753695567661661019265514673434246483988229429946831870519301,-3.851153334811777536563337123053124569704160846091637003157728595256494186490481089994453362578315815)"), a, new Apfloat("5e-97")); a = ApcomplexMath.cos(new Apcomplex("1.0000")); assertEquals("1 value", new Apfloat("0.5403"), a, new Apfloat("5e-5")); assertEquals("1 imag value", new Apfloat(0), a.imag()); a = ApcomplexMath.cos(new Apcomplex(new Apfloat(0))); assertEquals("0, 100 value", new Apfloat(1), a); try { ApcomplexMath.cos(new Apcomplex(new Apfloat(1000, 3), new Apfloat("1.5"))); fail("cos(1000 prec 3) accepted"); } catch (LossOfPrecisionException lope) { // OK; loss of precision } } public static void testSin() { Apcomplex a = ApcomplexMath.sin(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 100, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(3.853738037919377321617528940463730667068274946989034956763346803317838585207899050385464301460315524,-27.01681325800393448809754375499215226336386568976518470594798897425063415478434990691671779691472675)"), a, new Apfloat("5e-97")); a = ApcomplexMath.sin(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(3.853738037919377321617528940463730667068274946989034956763346803317838585207899050385464301460315524,27.01681325800393448809754375499215226336386568976518470594798897425063415478434990691671779691472675)"), a, new Apfloat("5e-97")); a = ApcomplexMath.sin(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(-3.853738037919377321617528940463730667068274946989034956763346803317838585207899050385464301460315524,-27.01681325800393448809754375499215226336386568976518470594798897425063415478434990691671779691472675)"), a, new Apfloat("5e-97")); a = ApcomplexMath.sin(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 100, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(-3.853738037919377321617528940463730667068274946989034956763346803317838585207899050385464301460315524,27.01681325800393448809754375499215226336386568976518470594798897425063415478434990691671779691472675)"), a, new Apfloat("5e-97")); a = ApcomplexMath.sin(new Apcomplex("(3.00000e-1000,4.00000e-1000)")); assertEquals("3e-1000,4e-1000 precision", 6, a.precision()); assertEquals("3e-1000,4e-1000 value", new Apcomplex("(3.00000e-1000,4.00000e-1000)"), a, new Apfloat("5e-1004")); a = ApcomplexMath.sin(new Apcomplex("1.0000")); assertEquals("1 value", new Apfloat("0.84147"), a, new Apfloat("5e-5")); assertEquals("1 imag value", new Apfloat(0), a.imag()); a = ApcomplexMath.sin(new Apcomplex(new Apfloat(0))); assertEquals("0, 100 value", new Apfloat(0), a); try { ApcomplexMath.sin(new Apcomplex(new Apfloat(1000, 3), new Apfloat("1.5"))); fail("sin(1000 prec 3) accepted"); } catch (LossOfPrecisionException lope) { // OK; loss of precision } } public static void testTan() { Apcomplex a = ApcomplexMath.tan(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 101, a.precision(), 1); assertEquals("(3,4), 100 value", new Apcomplex("(-0.0001873462046294784262242556377282181042124242427296606263580802232052224832174311687842725259181727521,0.9993559873814731413916496303201330615648885028135384928319757364498179348866065958722698773248799920)"), a, new Apfloat("5e-98")); a = ApcomplexMath.tan(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 101, a.precision(), 1); assertEquals("(3,-4), 100 value", new Apcomplex("(-0.0001873462046294784262242556377282181042124242427296606263580802232052224832174311687842725259181727521,-0.9993559873814731413916496303201330615648885028135384928319757364498179348866065958722698773248799920)"), a, new Apfloat("5e-98")); a = ApcomplexMath.tan(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 101, a.precision(), 1); assertEquals("(-3,4), 100 value", new Apcomplex("(0.0001873462046294784262242556377282181042124242427296606263580802232052224832174311687842725259181727521,0.9993559873814731413916496303201330615648885028135384928319757364498179348866065958722698773248799920)"), a, new Apfloat("5e-98")); a = ApcomplexMath.tan(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 101, a.precision(), 1); assertEquals("(-3,-4), 100 value", new Apcomplex("(0.0001873462046294784262242556377282181042124242427296606263580802232052224832174311687842725259181727521,-0.9993559873814731413916496303201330615648885028135384928319757364498179348866065958722698773248799920)"), a, new Apfloat("5e-98")); a = ApcomplexMath.tan(new Apfloat("3.1415926535897932384626433832795", 24).divide(new Apint(180))); assertEquals("1 degree value", new Apfloat("0.0174550649282175857651289"), a, new Apfloat("5e-25")); assertEquals("1 degree imag value", new Apfloat(0), a.imag()); a = ApcomplexMath.tan(new Apcomplex(new Apfloat(0), new Apfloat(5000000, 100))); assertEquals("(0,5000000), 100 precision", 4343037, a.precision(), 1); assertEquals("(0,5000000), 100 value", new Apcomplex(Apfloat.ZERO, new Apfloat(1).subtract(new Apfloat("3.03387356179746871517892756452203249280217116298171287391802587502345779082540217305405121824e-4342945"))), a, new Apfloat("5e-4343037")); a = ApcomplexMath.tan(new Apcomplex(new Apfloat(0), new Apfloat(-5000000, 100))); assertEquals("(0,-5000000), 100 precision", 4343037, a.precision(), 1); assertEquals("(0,-5000000), 100 value", new Apcomplex(Apfloat.ZERO, new Apfloat(-1).add(new Apfloat("3.03387356179746871517892756452203249280217116298171287391802587502345779082540217305405121824e-4342945"))), a, new Apfloat("5e-4343037")); a = ApcomplexMath.tan(new Apcomplex(new Apfloat(0))); assertEquals("0, 100 value", new Apfloat(0), a); try { ApcomplexMath.tan(new Apcomplex(new Apfloat(1000, 3), new Apfloat("1.5"))); fail("tan(1000 prec 3) accepted"); } catch (LossOfPrecisionException lope) { // OK; loss of precision } } public static void testCot() { Apcomplex a = ApcomplexMath.cot(new Apcomplex(new Apfloat(3, 100), new Apfloat(4, 100))); assertEquals("(3,4), 100 precision", 103, a.precision()); assertEquals("(3,4), 100 value", new Apcomplex("(-0.00018758773798365921562850466246423355472564846529309782893964921914630968050082632783622198386659471,-1.00064439247155908009818470784307948938834227700912898634814356679250631676718292100755226328263131)"), a, new Apfloat("5e-99")); a = ApcomplexMath.cot(new Apcomplex(new Apfloat(3, 100), new Apfloat(-4, 100))); assertEquals("(3,-4), 100 precision", 103, a.precision()); assertEquals("(3,-4), 100 value", new Apcomplex("(-0.00018758773798365921562850466246423355472564846529309782893964921914630968050082632783622198386659471,1.00064439247155908009818470784307948938834227700912898634814356679250631676718292100755226328263131)"), a, new Apfloat("5e-99")); a = ApcomplexMath.cot(new Apcomplex(new Apfloat(-3, 100), new Apfloat(4, 100))); assertEquals("(-3,4), 100 precision", 103, a.precision()); assertEquals("(-3,4), 100 value", new Apcomplex("(0.00018758773798365921562850466246423355472564846529309782893964921914630968050082632783622198386659471,-1.00064439247155908009818470784307948938834227700912898634814356679250631676718292100755226328263131)"), a, new Apfloat("5e-99")); a = ApcomplexMath.cot(new Apcomplex(new Apfloat(-3, 100), new Apfloat(-4, 100))); assertEquals("(-3,-4), 100 precision", 103, a.precision()); assertEquals("(-3,-4), 100 value", new Apcomplex("(0.00018758773798365921562850466246423355472564846529309782893964921914630968050082632783622198386659471,1.00064439247155908009818470784307948938834227700912898634814356679250631676718292100755226328263131)"), a, new Apfloat("5e-99")); a = ApcomplexMath.cot(new Apcomplex(Apfloat.ZERO, new Apfloat(4, 100))); assertEquals("(0,4), 100 precision", 104, a.precision()); assertEquals("(0,4), 100 value", new Apcomplex("(0,-1.000671150401682489912111744434371930958710622745064689809122475628813351918433317813144115811237098917)"), a, new Apfloat("5e-100")); a = ApcomplexMath.cot(new Apcomplex(Apfloat.ZERO, new Apfloat(-4, 100))); assertEquals("(0,-4), 100 precision", 104, a.precision()); assertEquals("(0,-4), 100 value", new Apcomplex("(0,1.000671150401682489912111744434371930958710622745064689809122475628813351918433317813144115811237098917)"), a, new Apfloat("5e-100")); a = ApcomplexMath.cot(new Apfloat(3, 100)); assertEquals("(3,0), 100 precision", 100, a.precision()); assertEquals("(3,0), 100 value", new Apcomplex("-7.0152525514345334694285513795264765782931033520963538381563324249075850694824874909055796047896063"), a, new Apfloat("5e-99")); a = ApcomplexMath.cot(new Apfloat(-3, 100)); assertEquals("(-3,0), 100 precision", 100, a.precision()); assertEquals("(-3,0), 100 value", new Apcomplex("7.0152525514345334694285513795264765782931033520963538381563324249075850694824874909055796047896063"), a, new Apfloat("5e-99")); try { ApcomplexMath.cot(new Apcomplex(new Apfloat(0))); fail("cot(0) accepted"); } catch (ArithmeticException ae) { // OK; division by zero } try { ApcomplexMath.cot(new Apcomplex(new Apfloat(1000, 3), new Apfloat("1.5"))); fail("cot(1000 prec 3) accepted"); } catch (LossOfPrecisionException lope) { // OK; loss of precision } } public static void testSinc() { Apcomplex a = ApcomplexMath.sinc(new Apcomplex(new Apfloat(3, 20), new Apfloat(4, 20))); assertEquals("(3,4), 20 precision", 20, a.precision()); assertEquals("(3,4), 20 value", new Apcomplex("(-3.860241556730304240,-3.858615677027572510)"), a, new Apfloat("5e-19")); a = ApcomplexMath.sinc(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apint(1), a); a = ApcomplexMath.sinc(new Apint(0, 2)); assertEquals("0 radix 2 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 radix 2 radix", 2, a.radix()); assertEquals("0 radix 2 value", new Apint(1, 2), a); } public static void testW() { Apcomplex a = new Apcomplex(new Apfloat(1, 45, 16), new Apfloat(2, 45, 16)); Apcomplex w = ApcomplexMath.w(a, -1); assertEquals("value", new Apcomplex(new Apfloat("-0.731b614b3b95524effd3f81d9be7b8c8e1d21e69264d", 45, 16), new Apfloat("-3.7a03f382c1f5dd2df77921934d2d67941431ed093840", 45, 16)), w, new Apfloat("5", 1, 16).scale(-44)); assertEquals("radix", 16, w.radix()); assertEquals("precision", 45, w.precision()); a = new Apcomplex(new Apfloat(1, 45), new Apfloat(2, 45)); w = ApcomplexMath.w(a); assertEquals("value", new Apcomplex("(0.823771216709230498962714234680902867860235005,0.532928986795441605088201422572330085339330393)"), w, new Apfloat("5e-45")); assertEquals("radix", 10, w.radix()); assertEquals("precision", 45, w.precision()); } public static void testProduct() { Apcomplex a = ApcomplexMath.product(new Apcomplex("(1,1)"), new Apcomplex("(1,1)")); assertEquals("1-1 precision", 1, a.precision()); assertEquals("1-1 value", new Apcomplex("(0,2)"), a); a = ApcomplexMath.product(new Apcomplex(Apfloat.ZERO, new Apfloat(2)), new Apcomplex(new Apfloat(3, 5), new Apfloat(3, 5)), new Apcomplex(new Apfloat(4, 8), new Apfloat(4, 8))); assertEquals("MAX-5-8 precision", 5, a.precision()); assertEquals("MAX-5-8 value", new Apcomplex("-48"), a); a = ApcomplexMath.product(Apcomplex.ZERO, new Apcomplex("12345")); assertEquals("0 precision", Apcomplex.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); a = ApcomplexMath.product(new Apint(0, 12)); assertEquals("0 radix", 12, a.radix()); a = ApcomplexMath.product(new Apcomplex("-1"), new Apcomplex("(0,2.50000000000000000000000000000000000000000000000000000000000000000000001)"), new Apcomplex("(0,2.0000000000000000000000000000000000001)"), new Apcomplex(new Apfloat(2))); assertEquals("Many precision", 1, a.precision()); assertEquals("Many value", new Apcomplex("10"), a); Apcomplex[] x = new Apcomplex[] { new Apcomplex("1000000000000"), new Apcomplex("1") }; ApcomplexMath.product(x); assertEquals("Array product 1 [0]", new Apcomplex("1000000000000"), x[0]); assertEquals("Array product 1 [1]", new Apcomplex("1"), x[1]); x = new Apcomplex[] { new Apcomplex("1"), new Apcomplex("1000000000000") }; ApcomplexMath.product(x); assertEquals("Array product 2 [0]", new Apcomplex("1"), x[0]); assertEquals("Array product 2 [1]", new Apcomplex("1000000000000"), x[1]); assertEquals("Empty product", new Apcomplex("1"), ApcomplexMath.product()); Apcomplex[] numbers = new Apcomplex[100000]; // Length should be divisible by 4 here for (int i = 0; i < numbers.length; i++) { numbers[i] = new Apcomplex(Apfloat.ZERO, new Apfloat(i + 1)); } Apcomplex factorial = ApintMath.factorial(numbers.length); assertEquals("Factorial", factorial, ApcomplexMath.product(numbers)); numbers[0] = new Apcomplex(Apfloat.ZERO, factorial.real()); assertEquals("Factorial squared", factorial.multiply(factorial), ApcomplexMath.product(numbers)); } public static void testSum() { Apcomplex a = ApcomplexMath.sum(new Apcomplex(Apfloat.ZERO, new Apfloat(12345000, 5)), new Apcomplex(Apfloat.ZERO, new Apfloat(12345, 5))); assertEquals("5-2 precision", 5, a.precision()); assertEquals("5-2 value", new Apcomplex("(0,12357000)"), a); a = ApcomplexMath.sum(new Apcomplex(new Apfloat(12345678, 10)), new Apcomplex(new Apfloat(12345, 5))); assertEquals("8-5 precision", 8, a.precision()); assertEquals("8-5 value", new Apcomplex("12358023"), a); a = ApcomplexMath.sum(new Apcomplex("0"), new Apcomplex("12345")); assertEquals("0-0 precision", 5, a.precision()); assertEquals("0-0 value", new Apcomplex("12345"), a); a = ApcomplexMath.sum(new Apcomplex("2")); assertEquals("2 precision", 1, a.precision()); assertEquals("2 value", new Apcomplex("2"), a); a = ApcomplexMath.sum(new Apcomplex("(0,1)"), new Apcomplex("(0,3333333.33)"), new Apcomplex("(0,2.2)"), new Apcomplex("(0,444444444400000000000000000000000000)"), new Apcomplex("(0,6666.6)"), new Apcomplex("(0,555)"), new Apcomplex(Apfloat.ZERO, new Apfloat(7))); assertEquals("Many precision", 36, a.precision()); assertEquals("Many value", new Apcomplex("(0,444444444400000000000000000003340564)"), a); Apcomplex[] x = new Apcomplex[] { new Apcomplex("1000000000000"), new Apcomplex("1") }; ApcomplexMath.sum(x); assertEquals("Array sum 1 [0]", new Apcomplex("1000000000000"), x[0]); assertEquals("Array sum 1 [1]", new Apcomplex("1"), x[1]); x = new Apcomplex[] { new Apcomplex("1"), new Apcomplex("1000000000000") }; ApcomplexMath.sum(x); assertEquals("Array sum 2 [0]", new Apcomplex("1"), x[0]); assertEquals("Array sum 2 [1]", new Apcomplex("1000000000000"), x[1]); assertEquals("Empty sum", new Apcomplex("0"), ApcomplexMath.sum()); } public static void testGamma() { Apcomplex a = ApcomplexMath.gamma(new Apcomplex("0.50000000")); assertEquals("0.5 precision", 8, a.precision()); assertEquals("0.5 value", new Apfloat("1.7724539"), a, new Apfloat("5e-7")); a = ApcomplexMath.gamma(new Apcomplex("-0.50000000")); assertEquals("-0.5 precision", 8, a.precision()); assertEquals("-0.5 value", new Apfloat("-3.5449077"), a, new Apfloat("5e-7")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat(1, 8, 5))); assertEquals("1 precision", 8, a.precision()); assertEquals("1 radix", 5, a.radix()); assertEquals("1 value", new Apfloat("1"), a); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat(2, 100, 15))); assertEquals("2 precision", 100, a.precision()); assertEquals("2 radix", 15, a.radix()); assertEquals("2 value", new Apfloat("1"), a); a = ApcomplexMath.gamma(new Apcomplex("3.0000")); assertEquals("3 precision", 5, a.precision()); assertEquals("3 value", new Apfloat("2"), a); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("1.6", 50, 12))); assertEquals("1.5 precision", 50, a.precision()); assertEquals("1.5 radix", 12, a.radix()); assertEquals("1.5 value", new Apfloat("0.a77497505445a57663a7a6a27293557aa7636b52055b106267", 50, 12), a, new Apfloat("5e-50", 1, 12)); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("1.6", 50, 12), new Apfloat("1.6", 50, 12))); assertEquals("(1.5,1.5) precision", 50, a.precision()); assertEquals("(1.5,1.5) radix", 12, a.radix()); assertEquals("(1.5,1.5) value", new Apcomplex(new Apfloat("0.421432a040a1238266b59319481b82250a972699b1218016a4", 50, 12), new Apfloat("0.184386517914307662b897756b0100538485b04495282b25ba", 50, 12)), a, new Apfloat("5e-50", 1, 12)); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("1.6", 50, 12), new Apfloat("-1.6", 50, 12))); assertEquals("(1.5,-1.5) precision", 50, a.precision()); assertEquals("(1.5,-1.5) radix", 12, a.radix()); assertEquals("(1.5,-1.5) value", new Apcomplex(new Apfloat("0.421432a040a1238266b59319481b82250a972699b1218016a4", 50, 12), new Apfloat("-0.184386517914307662b897756b0100538485b04495282b25ba", 50, 12)), a, new Apfloat("5e-50", 1, 12)); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("10.1", 50), new Apfloat(1, 50))); assertEquals("10.1+I precision", 49, a.precision()); assertEquals("10.1+I radix", 10, a.radix()); assertEquals("10.1+I value", new Apcomplex("(-275889.24637304345640288294183505994521208628420155,332093.85747733234553448206237389863106703170190430)"), a, new Apfloat("5e-44")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("100.1", 50), new Apfloat(1, 50))); assertEquals("100.1+I precision", 48, a.precision()); assertEquals("100.1+I radix", 10, a.radix()); assertEquals("100.1+I value", new Apcomplex("(-1.6325249252175791061043773321806465941281038201e155,-1.46196463909803799277895455102943868342521844260e156)"), a, new Apfloat("5e109")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat(1, 200), new Apfloat("1000000000000.1", 200))); assertEquals("1000000000000.1+I precision", 186, a.precision()); assertEquals("1000000000000.1+I radix", 10, a.radix()); assertEquals("1000000000000.1+I value", new Apcomplex("(2.2799397381057012808806414716554222166361918093242073118331397578121585980690443002813637584289628198999964037945275096726070876981676095000509004082444136731667291762706895607184590520e-682188176916,2.56143734228029034694359025317416641643312626363528304218252981145494697876711767159132470544194941716039395729054771162631751713400996765379046059018461097663341902573535496875851156846e-682188176915)"), a, new Apfloat("5e-682188177101")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat(1, 40), new Apfloat("1000000000000.1", 40))); assertEquals("1000000000000.1+I precision", 26, a.precision()); assertEquals("1000000000000.1+I radix", 10, a.radix()); assertEquals("1000000000000.1+I value", new Apcomplex("(2.2799397381057012808806415e-682188176916,2.56143734228029034694359025e-682188176915)"), a, new Apfloat("5e-682188176941")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat(1, 133, 2), new Apfloat("1.110100011010100101001010001000000000000000110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011e39", 133, 2))); assertEquals("1000000000000.1+I radix 2 precision", 87, a.precision()); assertEquals("1000000000000.1+I radix 2 radix", 2, a.radix()); assertEquals("1000000000000.1+I radix 2 value", new Apcomplex(new Apfloat("1.111010101000100100110111110011011000101001000110001000101011000111010000100110001001e-2266180070897", Apfloat.DEFAULT, 2), new Apfloat("1.0101100001110000001011000010100111110010000010101111100000100011110010100011010001110010e-2266180070893", Apfloat.DEFAULT, 2)), a, new Apfloat("1e-2266180070981", 1, 2)); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat(1, 25, 36), new Apfloat("cre66i9s.3lllllllllllllllm", 25, 36))); assertEquals("100000000000.1+I radix 36 precision", 17, a.precision()); assertEquals("100000000000.1+I radix 36 radix", 36, a.radix()); assertEquals("100000000000.1+I radix 36 value", ApcomplexMath.scale(new Apcomplex(new Apfloat("0.4w3ncj1ol4pgrcbkl", Apfloat.DEFAULT, 36),new Apfloat("1.iyfv83hi4ul6s26oy", Apfloat.DEFAULT, 36)), -438339061062L), a, ApfloatMath.scale(new Apfloat("h", 1, 36), -438339061078L)); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat(100, 30), new Apfloat(374, 30))); assertEquals("(100,374) precision", 30, a.precision()); assertEquals("(100,374) radix", 10, a.radix()); assertEquals("(100,374) value", new Apcomplex("(47.4294943677064514689542753377,-32.7488916473624576880974867017)"), a, new Apfloat("5e-28")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat(1000000000, 30), new Apfloat(14913639641L, 30))); assertEquals("(1000000000,14913639641) precision", 30, a.precision()); assertEquals("(1000000000,14913639641) radix", 10, a.radix()); assertEquals("(1000000000,14913639641) value", new Apcomplex("(-2.99966240181596582389952917253,-0.39936803730444026987241513690)"), a, new Apfloat("5e-29")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("4825490186121.8", 30), new Apfloat(99000000000000L, 30))); assertEquals("(4825490186121.8,99000000000000) precision", 30, a.precision()); assertEquals("(4825490186121.8,99000000000000) radix", 10, a.radix()); assertEquals("(4825490186121.8,99000000000000) value", new Apcomplex("(-6.62771164327451839566254131658,5.32978019529137704595692626876)"), a, new Apfloat("5e-29")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("1e-100", 50), new Apfloat("1e-100", 50))); assertEquals("1e-100+1e-100i precision", 50, a.precision()); assertEquals("1e-100+1e-100i radix", 10, a.radix()); assertEquals("1e-100+1e-100i value", new Apcomplex("(5.000000000000000000000000000000000000000000000000e99,-5.000000000000000000000000000000000000000000000000e99)"), a, new Apfloat("5e51")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("1e-100", 50), new Apfloat("-1e-100", 50))); assertEquals("1e-100-1e-100i precision", 50, a.precision()); assertEquals("1e-100-1e-100i radix", 10, a.radix()); assertEquals("1e-100-1e-100i value", new Apcomplex("(5.000000000000000000000000000000000000000000000000e99,5.000000000000000000000000000000000000000000000000e99)"), a, new Apfloat("5e51")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("-1e-100", 50), new Apfloat("1e-100", 50))); assertEquals("-1e-100+1e-100i precision", 50, a.precision()); assertEquals("-1e-100+1e-100i radix", 10, a.radix()); assertEquals("-1e-100+1e-100i value", new Apcomplex("(-5.000000000000000000000000000000000000000000000000e99,-5.000000000000000000000000000000000000000000000000e99)"), a, new Apfloat("5e51")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("-1e-100", 50), new Apfloat("-1e-100", 50))); assertEquals("-1e-100-1e-100i precision", 50, a.precision()); assertEquals("-1e-100-1e-100i radix", 10, a.radix()); assertEquals("-1e-100-1e-100i value", new Apcomplex("(-5.000000000000000000000000000000000000000000000000e99,5.000000000000000000000000000000000000000000000000e99)"), a, new Apfloat("5e51")); a = ApcomplexMath.gamma(new Apfloat("1000000000000", 100)); assertEquals("1000000000000 precision", 87, a.precision()); assertEquals("1000000000000 radix", 10, a.radix()); assertEquals("1000000000000 value", new Apcomplex("1.40366116037375609072013386771345056395992457297880153995116109278764014118526674828156e11565705518091"), a, new Apfloat("5e11565705518005")); a = ApcomplexMath.gamma(new Apfloat("12345.12345")); assertEquals("12345.12345 precision", 5, a.precision()); assertEquals("12345.12345 radix", 10, a.radix()); assertEquals("12345.12345 value", new Apcomplex("8.9252e45146"), a, new Apfloat("5e45142")); a = ApcomplexMath.gamma(new Apfloat("-0.9999991")); assertEquals("-0.9999991 precision", 1, a.precision()); assertEquals("-0.9999991 radix", 10, a.radix()); assertEquals("-0.9999991 value", new Apcomplex("-1e6"), a, new Apfloat("0")); a = ApcomplexMath.gamma(new Apfloat("-0.900000")); assertEquals("-0.9 precision", 6, a.precision()); assertEquals("-0.9 radix", 10, a.radix()); assertEquals("-0.9 value", new Apcomplex("-10.5706"), a, new Apfloat("5e-4")); a = ApcomplexMath.gamma(new Apcomplex("(-1.00000000000000000,1.00000000000000000e-5)")); assertEquals("-1+1e-5i precision", 14, a.precision()); assertEquals("-1+1e-5i radix", 10, a.radix()); assertEquals("-1+1e-5i value", new Apcomplex("(-0.4227843350,99999.999985882)"), a, new Apfloat("5e-9")); try { ApcomplexMath.gamma(new Apcomplex("0")); fail("Gamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.gamma(new Apcomplex("-1")); fail("Gamma of -1"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.gamma(new Apcomplex("(-1.00000,1.00000e-1000)")); fail("Gamma of -1 within precision"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.gamma(new Apcomplex("(1e2,1)")); fail("Gamma loss of precision"); } catch (LossOfPrecisionException lope) { // OK } try { ApcomplexMath.gamma(new Apcomplex("(0,1e2)")); fail("Gamma loss of precision"); } catch (LossOfPrecisionException lope) { // OK } try { ApcomplexMath.gamma(new Apcomplex("1e100")); fail("Gamma overflow"); } catch (ApfloatRuntimeException are) { // OK } try { ApcomplexMath.gamma(new Apcomplex(new Apint(1), new Apfloat("4.5", Apfloat.INFINITE))); fail("Gamma infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testGammaIncomplete() { Apcomplex a = ApcomplexMath.gamma(new Apfloat(-4, 10), new Apfloat(-2, 10)); assertEquals("-4,-2 precision", 10, a.precision()); assertEquals("-4,-2 value", new Apcomplex("(0.2169049075,-0.1308996939)"), a, new Apfloat("5e-10")); a = ApcomplexMath.gamma(new Apfloat(-1, 10), new Apfloat(-2, 10)); assertEquals("-1,-2 precision", 10, a.precision()); assertEquals("-1,-2 value", new Apcomplex("(1.259706307,3.141592654)"), a, new Apfloat("5e-9")); a = ApcomplexMath.gamma(new Apfloat(0), new Apfloat(-1, 11)); assertEquals("0,-1 precision", 10, a.precision()); assertEquals("0,-1 value", new Apcomplex("(-1.895117816,-3.141592654)"), a, new Apfloat("5e-9")); a = ApcomplexMath.gamma(new Apfloat(-4, 10), new Apcomplex(Apfloat.ZERO, new Apfloat(-2, 10))); assertEquals("-4,-2i precision", 10, a.precision()); assertEquals("-4,-2i value", new Apcomplex("(-0.01031978444,0.00762842656)"), a, new Apfloat("5e-11")); a = ApcomplexMath.gamma(new Apfloat(-4, 10), new Apcomplex(Apfloat.ZERO, new Apfloat(2, 10))); assertEquals("-4,2i precision", 10, a.precision()); assertEquals("-4,2i value", new Apcomplex("(-0.01031978444,-0.00762842656)"), a, new Apfloat("5e-11")); a = ApcomplexMath.gamma(new Apfloat(-4, 10), new Apcomplex(Apfloat.ZERO, new Apfloat(-200, 10))); assertEquals("-4,-200i precision", 8, a.precision()); assertEquals("-4,-200i value", new Apcomplex("(2.765031767e-12,1.453166391e-12)"), a, new Apfloat("5e-21")); a = ApcomplexMath.gamma(new Apcomplex(Apfloat.ZERO, new Apfloat(-4, 10)), new Apcomplex(Apfloat.ZERO, new Apfloat(2, 10))); assertEquals("-4i,2i precision", 10, a.precision()); assertEquals("-4i,2i value", new Apcomplex("(89.37681331,-0.32076166)"), a, new Apfloat("5e-8")); a = ApcomplexMath.gamma(new Apcomplex("3.50000"), new Apcomplex("0")); assertEquals("3.5 precision", 6, a.precision()); assertEquals("3.5 value", new Apcomplex("3.32335"), a, new Apfloat("5e-5")); a = ApcomplexMath.gamma(new Apcomplex("(1.5000000,1.0000000)"), new Apcomplex("(-1.0000000,1.0000000e-2)")); assertEquals("1.5+i,-1+0.01i precision", 8, a.precision()); assertEquals("1.5+i,-1+0.01i value", new Apcomplex("(0.59778962,0.13066077)"), a, new Apfloat("5e-8")); a = ApcomplexMath.gamma(new Apcomplex("(1.5000000,1.0000000)"), new Apcomplex("(-1.0000000,-1.0000000e-2)")); assertEquals("1.5+i,-1-0.01i precision", 8, a.precision()); assertEquals("1.5+i,-1-0.01i value", new Apcomplex("(-10.201515,-22.643499)"), a, new Apfloat("5e-6")); a = ApcomplexMath.gamma(new Apcomplex("(-1.0000000e-2,4.0000000e2)"), new Apcomplex("(1.0000000e-2,1.0000000e2)")); assertEquals("-1e-2+4e2i,1e-2+1e2i precision", 7, a.precision()); assertEquals("-1e-2+4e2i,1e-2+1e2i value", new Apcomplex("(-1.0542844e-274,-1.2073566e-274)"), a, new Apfloat("5e-280")); a = ApcomplexMath.gamma(new Apcomplex("(-1.1538262523991663e-1,5.373868295802127e-5)"), new Apcomplex("(-1.773822473482807e1,1.1375203210348511e-1)")); assertEquals("-1.1538262523991663e-1+5.373868295802127e-5i,-1.773822473482807e1+1.1375203210348511e-1i precision", 15, a.precision()); assertEquals("-1.1538262523991663e-1+5.373868295802127e-5i,-1.773822473482807e1+1.1375203210348511e-1i value", new Apcomplex("(-1955553.446208209,989495.924550850)"), a, new Apfloat("5e-9")); a = ApcomplexMath.gamma(new Apcomplex("(-8.221677442966661e-11,-8.40160119100972e-11)"), new Apcomplex("(1.2025846683194057e-3,9.851413511989293e-9)")); assertEquals("-8.221677442966661e-11-8.40160119100972e-11i,1.2025846683194057e-3+9.851413511989293e-9i precision", 17, a.precision()); assertEquals("-8.221677442966661e-11-8.40160119100972e-11i,1.2025846683194057e-3+9.851413511989293e-9i value", new Apcomplex("(6.14726870827323060,-8.180204838272392707e-6)"), a, new Apfloat("5e-16")); a = ApcomplexMath.gamma(new Apcomplex("(5.9140452392587956e-5,8.5750776148049e8)"), new Apcomplex("(4.673198134242025,-1.3140870009190432e-7)")); assertEquals("5.9140452392587956e-5+8.5750776148049e8i,4.673198134242025-1.3140870009190432e-7i precision", 14, a.precision()); assertEquals("5.9140452392587956e-5+8.5750776148049e8i,4.673198134242025-1.3140870009190432e-7i value", new Apcomplex("(-0.32088105037554,0.03770361316879)"), a, new Apfloat("5e-14")); a = ApcomplexMath.gamma(new Apcomplex("(-1.078432904072464e-1,2.2318918029265195e-9)"), new Apcomplex("(-1.318051987307835,2.2206695185439e9)")); assertEquals("-1.078432904072464e-1+2.2318918029265195e-9i,-1.318051987307835+2.2206695185439e9i precision", 5, a.precision()); assertEquals("-1.078432904072464e-1+2.2318918029265195e-9i,-1.318051987307835+2.2206695185439e9i value", new Apcomplex("(1.155363210e-10,-1.180636439e-10)"), a, new Apfloat("5e-15")); a = ApcomplexMath.gamma(new Apcomplex("(-9.608072523703581e1,-3.7643456893059174e-1)"), new Apcomplex("(-1.3814972507571912e2,-3.4538159572099236e-1)")); assertEquals("-9.608072523703581e1-3.7643456893059174e-1,-1.3814972507571912e2-3.4538159572099236e-1i precision", 14, a.precision()); assertEquals("-9.608072523703581e1-3.7643456893059174e-1,-1.3814972507571912e2-3.4538159572099236e-1i value", new Apcomplex("(-1.3024207045775e-149,1.8066865252068e-148)"), a, new Apfloat("5e-161")); a = ApcomplexMath.gamma(new Apcomplex("(4.929287290773249e-3,-4.681295287406053e1)"), new Apcomplex("(2.7955773531635903e-6,6.918020068517608e9)")); assertEquals("4.929287290773249e-3-4.681295287406053e1i,2.7955773531635903e-6+6.918020068517608e9i precision", 7, a.precision()); assertEquals("4.929287290773249e-3-4.681295287406053e1i,2.7955773531635903e-6+6.918020068517608e9i value", new Apcomplex("(-9.62645560037940e21,-1.006027591105011e22)"), a, new Apfloat("5e14")); a = ApcomplexMath.gamma(new Apcomplex("(-154,-8.66)").precision(10), new Apcomplex("(-48700,-0.0274)").precision(10)); assertEquals("-154-8.66i,-48700-0.0274i precision 10", 6, a.precision()); assertEquals("-154-8.66i,-48700-0.0274i value 10", new Apcomplex("(-3.993583e20411,-4.146069e20411)"), a, new Apfloat("5e20406")); a = ApcomplexMath.gamma(new Apcomplex("(-154,-8.66)").precision(50), new Apcomplex("(-48700,-0.0274)").precision(50)); assertEquals("-154-8.66i,-48700-0.0274i precision 50", 46, a.precision()); assertEquals("-154-8.66i,-48700-0.0274i value 50", new Apcomplex("(-3.993583401859555074273878866836005256257679217e20411,-4.146069249480328790411648959625162586421100204e20411)"), a, new Apfloat("5e20366")); a = ApcomplexMath.gamma(new Apcomplex("(-154,-8.66)").precision(100), new Apcomplex("(-48700,-0.0274)").precision(100)); assertEquals("-154-8.66i,-48700-0.0274i precision 100", 96, a.precision()); assertEquals("-154-8.66i,-48700-0.0274i value 100", new Apcomplex("(-3.99358340185955507427387886683600525625767921706238693274185708531557493280695373333096470482086e20411,-4.14606924948032879041164895962516258642110020393956205308840983212659862153878019935909589513889e20411)"), a, new Apfloat("5e20316")); a = ApcomplexMath.gamma(new Apcomplex("(-1.539926526059491e2,-8.659643233600654)").precision(10), new Apcomplex("(3.651741272548377e1,3.651741272548377e1)").precision(10)); assertEquals("-1.539926526059491e2-8.659643233600654i,3.651741272548377e1+3.651741272548377e1i precision 10", 7, a.precision()); assertEquals("-1.539926526059491e2-8.659643233600654i,3.651741272548377e1+3.651741272548377e1i value 10", new Apcomplex("(-1.000387473e-279,2.19340186e-280)"), a, new Apfloat("5e-288")); a = ApcomplexMath.gamma(new Apcomplex("(-1.539926526059491e2,-8.659643233600654)").precision(100), new Apcomplex("(3.651741272548377e1,3.651741272548377e1)").precision(100)); assertEquals("-1.539926526059491e2-8.659643233600654i,3.651741272548377e1+3.651741272548377e1i precision 100", 99, a.precision()); assertEquals("-1.539926526059491e2-8.659643233600654i,3.651741272548377e1+3.651741272548377e1i value 100", new Apcomplex("(-1.000387472881261786364648259266083073101695881441237876788775418264481632743088708557828811438171176e-279,2.19340185670881734177337416745907040764484275856218117734431994846665774924244282427508784873315962e-280)"), a, new Apfloat("5e-378")); a = ApcomplexMath.gamma(new Apcomplex("(-1.539926526059491e2,-8.659643233600654)").precision(150), new Apcomplex("(3.651741272548377e1,3.651741272548377e1)").precision(150)); assertEquals("-1.539926526059491e2-8.659643233600654i,3.651741272548377e1+3.651741272548377e1i precision 150", 149, a.precision()); assertEquals("-1.539926526059491e2-8.659643233600654i,3.651741272548377e1+3.651741272548377e1i value 150", new Apcomplex("(-1.00038747288126178636464825926608307310169588144123787678877541826448163274308870855782881143817117680690207698118346329877280924878328777673631757823e-279,2.1934018567088173417733741674590704076448427585621811773443199484666577492424428242750878487331596225808712634666511287059353332666354112564113593836e-280)"), a, new Apfloat("5e-428")); a = ApcomplexMath.gamma(new Apcomplex("(-1.539926526059491e2,3.651741272548377e1)"), new Apcomplex("(-1.539926526059491e2,2.053525026457146)")); assertEquals("-1.539926526059491e2+3.651741272548377e1i,-1.539926526059491e2+2.053525026457146i precision", 14, a.precision()); assertEquals("-1.539926526059491e2+3.651741272548377e1i,-1.539926526059491e2+2.053525026457146i value", new Apcomplex("(1.839734790895e-319,1.338102215869e-319)"), a, new Apfloat("5e-330")); a = ApcomplexMath.gamma(new Apcomplex("(3.651741272548377e1,6.493816315762113e2)"), new Apcomplex("(-1.539926526059491e2, 6.493816315762113e2)")); assertEquals("3.651741272548377e1+6.493816315762113e2i,-1.539926526059491e2+6.493816315762113e2i precision 16", 13, a.precision()); assertEquals("3.651741272548377e1+6.493816315762113e2i,-1.539926526059491e2+6.493816315762113e2i value 16", new Apcomplex("(2.915334707954e-342,-1.655111718059e-341)"), a, new Apfloat("5e-353")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("3.651741272548377e1", 100), new Apfloat("6.493816315762113e2", 100)), new Apcomplex(new Apfloat("-1.539926526059491e2", 100), new Apfloat("6.493816315762113e2", 100))); assertEquals("3.651741272548377e1+6.493816315762113e2i,-1.539926526059491e2+6.493816315762113e2i precision 100", 97, a.precision()); assertEquals("3.651741272548377e1+6.493816315762113e2i,-1.539926526059491e2+6.493816315762113e2i value 100", new Apcomplex("(2.91533470795462694774511982618601485525980988048575683897915057656824264524933126474133998657486524e-342,-1.655111718059222466900917172705448065052184678587394506208944906007626306997703966539065820047728131e-341)"), a, new Apfloat("5e-438")); a = ApcomplexMath.gamma(new Apcomplex("(6.493816315e2,-4.869675251e4)"), new Apcomplex("(2.053525026, -4.869675251e4)")); assertEquals("6.493816315762113e2-4.869675251658631e4i,2.053525026457146-4.869675251658631e4i precision 10", 5, a.precision()); assertEquals("6.493816315762113e2-4.869675251658631e4i,2.053525026457146-4.869675251658631e4i value 10", new Apcomplex("(-3.336774750653543e-30179,-3.429254232216520e-30179)"), a, new Apfloat("5e-30183")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("6.493816315762113e2", 100), new Apfloat("-4.869675251658631e4", 100)), new Apcomplex(new Apfloat("2.053525026457146", 100), new Apfloat("-4.869675251658631e4", 100))); assertEquals("6.493816315762113e2-4.869675251658631e4i,2.053525026457146-4.869675251658631e4i precision 100", 95, a.precision()); assertEquals("6.493816315762113e2-4.869675251658631e4i,2.053525026457146-4.869675251658631e4i value 100", new Apcomplex("(-3.336774750653542780292101143074244789906130563661596634385946198826707896979733558295247049539498194e-30179,-3.429254232216520432738635661723033982576737397069537462221535204624693947897645031930120034934224312e-30179)"), a, new Apfloat("5e-30278")); a = ApcomplexMath.gamma(new Apcomplex("(6.493816315762113e2,1.154781984689458e4)"), new Apcomplex("(-8.659643233600654,1.154781984689458e4)")); assertEquals("6.493816315762113e2+1.154781984689458e4i,-8.659643233600654+1.154781984689458e4i precision 16", 11, a.precision()); assertEquals("6.493816315762113e2+1.154781984689458e4i,-8.659643233600654+1.154781984689458e4i value 16", new Apcomplex("(-6.550743789275929e-5242,-1.416983672208689e-5242)"), a, new Apfloat("5e-5257")); a = ApcomplexMath.gamma(new Apcomplex(new Apfloat("6.493816315762113e2", 50), new Apfloat("1.154781984689458e4", 50)), new Apcomplex(new Apfloat("-8.659643233600654", 50), new Apfloat("1.154781984689458e4", 50))); assertEquals("6.493816315762113e2+1.154781984689458e4i,-8.659643233600654+1.154781984689458e4i precision 50", 45, a.precision()); assertEquals("6.493816315762113e2+1.154781984689458e4i,-8.659643233600654+1.154781984689458e4i value 50", new Apcomplex("(-6.5507437892759319457546310871131583985239939226551e-5242,-1.4169836722086846119544003377316736599354795064143e-5242)"), a, new Apfloat("5e-5286")); // NOTE some 20 last digits are incorrect a = ApcomplexMath.gamma(new Apcomplex("(-1.53992652e2,6.49381631e-3)"), new Apcomplex("(-1.53992652e2,6.49381631e-3)")); assertEquals("-1.53992652e2+6.49381631e-3i,-1.53992652e2+6.49381631e-3i precision 9", 6, a.precision()); assertEquals("-1.53992652e2+6.49381631e-3i,-1.53992652e2+6.49381631e-3i value 9", new Apcomplex("(7.9794e-273,-1.03098e-271)"), a, new Apfloat("5e-276")); a = ApcomplexMath.gamma(new Apcomplex("(-1.539926526059491e2,6.493816315762112e-3)"), new Apcomplex("(-1.539926526059491e2,6.493816315762112e-3)")); assertEquals("-1.539926526059491e2+6.493816315762112e-3i,-1.539926526059491e2+6.493816315762112e-3i precision 16", 13, a.precision()); assertEquals("-1.539926526059491e2+6.493816315762112e-3i,-1.539926526059491e2+6.493816315762112e-3i value 16", new Apcomplex("(7.9792063198967e-273,-1.0309779572519e-271)"), a, new Apfloat("5e-283")); a = ApcomplexMath.gamma(new Apcomplex("(6.493816315762113e2,-4.869675251658631e4)"), new Apcomplex("(-8.659643233600654,-4.869675251658631e4)")); assertEquals("6.493816315762113e2-4.869675251658631e4i,-8.659643233600654-4.869675251658631e4i precision 16", 11, a.precision()); assertEquals("6.493816315762113e2-4.869675251658631e4i,-8.659643233600654-4.869675251658631e4i value 16", new Apcomplex("(-3.25441737499e-30179,-3.3855297992e-30179)"), a, new Apfloat("5e-30189")); a = ApcomplexMath.gamma(new Apcomplex("(6.493816315762113e2,1.154781984689458e4)"), new Apcomplex("(-8.659643233600654,1.154781984689458e4)")); assertEquals("6.493816315762113e2+1.154781984689458e4i,-8.659643233600654+1.154781984689458e4i precision 16", 11, a.precision()); assertEquals("6.493816315762113e2+1.154781984689458e4i,-8.659643233600654+1.154781984689458e4i value 16", new Apcomplex("(-6.550743789275931e-5242,-1.416983672208684e-5242)"), a, new Apfloat("5e-5252")); a = ApcomplexMath.gamma(new Apcomplex("(1.154781984689458e4,-1.539926526059491e2)"), new Apcomplex("(1.154781984689458e4,3.651741272548377e1)")); assertEquals("1.154781984689458e4-1.539926526059491e2i,1.154781984689458e4+3.651741272548377e1i precision 16", 11, a.precision()); assertEquals("1.154781984689458e4-1.539926526059491e2i,1.154781984689458e4+3.651741272548377e1i value 16", new Apcomplex("(-8.382175690814767e41895,-2.511119213693562e41895)"), a, new Apfloat("5e41880")); a = ApcomplexMath.gamma(new Apcomplex("(100000,0)"), new Apcomplex("(2.00000,3.00000)")); assertEquals("100000,2+3i precision", 6, a.precision()); assertEquals("100000,2+3i", new Apcomplex("(2.824229e456568)"), a, new Apfloat("5e456563")); a = ApcomplexMath.gamma(new Apcomplex("(100000.000000,100000.000000)"), new Apcomplex("(2.00000,3.00000)")); assertEquals("100000+100000i,2+3i precision", 6, a.precision()); assertEquals("100000+100000i,2+3i", new Apcomplex("(3.13729e437509,2.911201e437510)"), a, new Apfloat("5e437505")); a = ApcomplexMath.gamma(new Apcomplex("(0,100000.00000)"), new Apcomplex("(2.0000000000,3.0000000000)")); assertEquals("100000i,2+3i precision", 11, a.precision()); assertEquals("100000i,2+3i", new Apcomplex("(8.7426106520e-42689,-4.958470896e-42690)"), a, new Apfloat("5e-42699")); a = ApcomplexMath.gamma(new Apcomplex("(-100000.000,100000.000)"), new Apcomplex("(2.00000000,3.00000000)")); assertEquals("-100000+100000i,2+3i precision", 9, a.precision()); assertEquals("-100000+100000i,2+3i", new Apcomplex("(8.3872927789e-98387,4.1247684828e-98386)"), a, new Apfloat("5e-98398")); a = ApcomplexMath.gamma(new Apcomplex("(-100000.100,0)"), new Apcomplex("(2.00000000,3.00000000)")); assertEquals("-100000,2+3i precision", 9, a.precision()); assertEquals("-100000,2+3i", new Apcomplex("(5.118337676266220e-55704,-6.268428497322141e-55704)"), a, new Apfloat("5e-55712")); a = ApcomplexMath.gamma(new Apcomplex("(-100000.000,-100000.000)"), new Apcomplex("(2.00000000,3.00000000)")); assertEquals("-100000-100000i,2+3i precision", 9, a.precision()); assertEquals("-100000-100000i,2+3i", new Apcomplex("(-9.8621266689e-13022,-1.956797639e-13022)"), a, new Apfloat("5e-13030")); a = ApcomplexMath.gamma(new Apcomplex("(0,-100000.00000)"), new Apcomplex("(2.0000000000,3.0000000000)")); assertEquals("-100000i,2+3i precision", 11, a.precision()); assertEquals("-100000i,2+3i", new Apcomplex("(1.97199906e42676,6.97215465e42675)"), a, new Apfloat("5e42666")); a = ApcomplexMath.gamma(new Apcomplex("(100000.000,-100000.000)"), new Apcomplex("(2.00000000,3.00000000)")); assertEquals("100000-100000i,2+3i precision", 3, a.precision()); assertEquals("100000-100000i,2+3i", new Apcomplex("(3.137289665e437509,-2.91120055e437510)"), a, new Apfloat("5e437507")); a = ApcomplexMath.gamma(new Apcomplex("(2.000000,3.000000)"), new Apcomplex("(100000.00000,0)")); assertEquals("100000,2+3i precision", 6, a.precision()); assertEquals("100000,2+3i", new Apcomplex("(-3.562361388475777e-43425,6.6669518912609e-43427)"), a, new Apfloat("5e-43430")); a = ApcomplexMath.gamma(new Apcomplex("(2.000000,3.000000)"), new Apcomplex("(100000.00000,100000.00000)")); assertEquals("100000+100000i,2+3i precision", 6, a.precision()); assertEquals("100000+100000i,2+3i", new Apcomplex("(-1.280065859976790e-43426,4.601110542440815e-43426)"), a, new Apfloat("5e-43426")); a = ApcomplexMath.gamma(new Apcomplex("(2.000000,3.000000)"), new Apcomplex("(0,100000.00000)")); assertEquals("100000i,2+3i precision", 6, a.precision()); assertEquals("100000i,2+3i", new Apcomplex("(-15.2746,898.226)"), a, new Apfloat("5e-3")); a = ApcomplexMath.gamma(new Apcomplex("(2.000000,3.000000)"), new Apcomplex("(-100000.00000,100000.00000)")); assertEquals("-100000+100000i,2+3i precision", 6, a.precision()); assertEquals("-100000+100000i,2+3i", new Apcomplex("(-3.255952560962579e43431,-9.05726879806356e43430)"), a, new Apfloat("5e43426")); a = ApcomplexMath.gamma(new Apcomplex("(2.000000,3.000000)"), new Apcomplex("(-100000.00000,0)")); assertEquals("-100000,2+3i precision", 6, a.precision()); assertEquals("-100000,2+3i", new Apcomplex("(2.264542049935799e43430,-4.2516777388445e43428)"), a, new Apfloat("5e43425")); a = ApcomplexMath.gamma(new Apcomplex("(2.000000,3.000000)"), new Apcomplex("(-100000.00000,-100000.00000)")); assertEquals("-100000-100000i,2+3i precision", 6, a.precision()); assertEquals("-100000-100000i,2+3i", new Apcomplex("(9.25282360923927e43436,-4.568939763307709e43437)"), a, new Apfloat("5e43432")); a = ApcomplexMath.gamma(new Apcomplex("(2.000000,3.000000)"), new Apcomplex("(0,-100000.00000)")); assertEquals("-100000i,2+3i precision", 6, a.precision()); assertEquals("-100000i,2+3i", new Apcomplex("(-606243,-1.11149e7)"), a, new Apfloat("5e2")); a = ApcomplexMath.gamma(new Apcomplex("(2.000000,3.000000)"), new Apcomplex("(100000.00000,-100000.00000)")); assertEquals("100000-100000i,2+3i precision", 6, a.precision()); assertEquals("100000-100000i,2+3i", new Apcomplex("(5.210410681496100e-43424,1.055353060233141e-43424)"), a, new Apfloat("5e-43429")); a = ApcomplexMath.gamma(new Apfloat("-4.0000000", Apfloat.DEFAULT, 11), new Apfloat("-6.0000000", Apfloat.DEFAULT, 11)); assertEquals("-4,-6 precision radix 11", 8, a.precision()); assertEquals("-4,-6 value radix 11", new Apcomplex(new Apfloat("-0.0987840", Apfloat.DEFAULT, 11), new Apfloat("-0.1492559", Apfloat.DEFAULT, 11)), a, new Apfloat("5e-7", Apfloat.DEFAULT, 11)); a = ApcomplexMath.gamma(new Apfloat("-4.00000000", Apfloat.DEFAULT, 11), new Apfloat("-0.600000000", Apfloat.DEFAULT, 11)); assertEquals("-4,-0.6 precision radix 11", 8, a.precision()); assertEquals("-4,-0.6 value radix 11", new Apcomplex(new Apfloat("6.11a99456", Apfloat.DEFAULT, 11), new Apfloat("-0.14925588", Apfloat.DEFAULT, 11)), a, new Apfloat("5e-8", Apfloat.DEFAULT, 11)); try { ApcomplexMath.gamma(Apcomplex.ZERO, Apcomplex.ZERO); fail("Gamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.gamma(new Apcomplex("(1.000e100,1.000)"), new Apcomplex("(1.000e102,1.000)")); fail("Overflow"); } catch (OverflowException are) { // OK } try { ApcomplexMath.gamma(new Apcomplex(new Apfloat(4)), new Apcomplex(new Apfloat(5)), Apfloat.ZERO); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testGammaIncompleteGeneralized() { Apcomplex a = ApcomplexMath.gamma(new Apcomplex("(-1.0000000e-2,4.0000000e2)"), Apcomplex.ZERO, new Apcomplex("(1.0000000e-2,1.0000000e2)")); assertEquals("-1e-2+4e2i,0,1e-2+1e2i precision", 5, a.precision()); assertEquals("-1e-2+4e2i,0,1e-2+1e2i value", new Apcomplex("(4.3680e-276,1.761e-277)"), a, new Apfloat("5e-280")); a = ApcomplexMath.gamma(new Apcomplex("(-1.0000000e-2,4.0000000e2)"), new Apcomplex("(1.0000000e-2,1.0000000e2)"), Apcomplex.ZERO); assertEquals("-1e-2+4e2i,1e-2+1e2i,0 precision", 5, a.precision()); assertEquals("-1e-2+4e2i,1e-2+1e2i,0 value", new Apcomplex("(-4.3680e-276,-1.761e-277)"), a, new Apfloat("5e-280")); a = ApcomplexMath.gamma(new Apcomplex("(-1.0000000e-2,4.0000000e2)"), new Apcomplex("(1.0000000e-2,1.0000000e2)"), new Apcomplex("(1.0000000e-2,1.0000000e2)")); assertEquals("-1e-2+4e2i,1e-2+1e2i,1e-2+1e2i precision", Apfloat.INFINITE, a.precision()); assertEquals("-1e-2+4e2i,1e-2+1e2i,1e-2+1e2i value", Apcomplex.ZERO, a); a = ApcomplexMath.gamma(new Apcomplex("(0,1.0000)"), new Apcomplex("(0,1.0000)"), new Apcomplex("(0,2.0000)")); assertEquals("i,i,2i precision", 5, a.precision()); assertEquals("i,i,2i value", new Apcomplex("(0.06560,-0.12764)"), a, new Apfloat("5e-5")); a = ApcomplexMath.gamma(Apcomplex.ZERO, new Apcomplex("(0,1.0000)"), new Apcomplex("(0,2.0000)")); assertEquals("0,i,2i precision", 5, a.precision()); assertEquals("0,i,2i value", new Apcomplex("(0.08558,-0.65933)"), a, new Apfloat("5e-5")); a = ApcomplexMath.gamma(Apcomplex.ZERO, new Apcomplex("(1.0000,1.0000)"), new Apcomplex("(2.0000,0)")); assertEquals("0,1+i,2 precision", 5, a.precision()); assertEquals("0,1+i,2 value", new Apcomplex("(-0.04862,-0.17932)"), a, new Apfloat("5e-5")); a = ApcomplexMath.gamma(Apcomplex.ZERO, new Apcomplex("(1.0000,1.0000)"), new Apcomplex("(0,2.0000)")); assertEquals("0,1+i,2i precision", 5, a.precision()); assertEquals("0,1+i,2i value", new Apcomplex("(0.42326,-0.21394)"), a, new Apfloat("5e-5")); a = ApcomplexMath.gamma(new Apcomplex("(0,1.0000)"), new Apcomplex("(0,1.0000)"), Apcomplex.ZERO); assertEquals("i,i,0 precision", 5, a.precision()); assertEquals("i,i,0 value", new Apcomplex("(0.14013,0.28147)"), a, new Apfloat("5e-5")); try { ApcomplexMath.gamma(Apcomplex.ZERO, Apcomplex.ZERO, Apcomplex.ZERO); fail("Gamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.gamma(new Apcomplex("-1"), Apcomplex.ZERO, new Apcomplex("(1,2)")); fail("Lower gamma of non-positive integer"); } catch (ArithmeticException ae) { // OK a is non-positive integer } try { ApcomplexMath.gamma(Apcomplex.ZERO, new Apcomplex("(0,-1)"), Apcomplex.ZERO); fail("Lower gamma of non-positive integer"); } catch (ArithmeticException ae) { // OK a is non-positive integer } try { ApcomplexMath.gamma(Apcomplex.ZERO, Apcomplex.ZERO, new Apcomplex("(0,-1)")); fail("Lower gamma of non-positive integer"); } catch (ArithmeticException ae) { // OK a is non-positive integer } try { ApcomplexMath.gamma(Apcomplex.ZERO, Apcomplex.ZERO, new Apcomplex("(1,-1)")); fail("Lower gamma of non-positive integer"); } catch (ArithmeticException ae) { // OK a is non-positive integer } try { ApcomplexMath.gamma(new Apcomplex("(1.00e19,1.00e19)"), new Apcomplex("(1.00e18,1.00e18)"), new Apcomplex("(2.00e19,2.00e19)")); fail("Overflow"); } catch (OverflowException are) { // OK } try { ApcomplexMath.gamma(new Apcomplex(Apfloat.ZERO, new Apfloat(4)), new Apcomplex(Apfloat.ZERO, new Apfloat(5)), new Apcomplex(Apfloat.ZERO, new Apfloat(6))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testLogGamma() { Apcomplex a = ApcomplexMath.logGamma(new Apcomplex("(3,4)").precision(30)); assertEquals("3+4i precision", 29, a.precision()); assertEquals("3+4i value", new Apcomplex("(-1.75662678460378411053060418162,4.74266443803465792819488940755)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(3,-4)").precision(30)); assertEquals("3-4i precision", 29, a.precision()); assertEquals("3-4i value", new Apcomplex("(-1.75662678460378411053060418162,-4.74266443803465792819488940755)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(-3,4)").precision(30)); assertEquals("-3+4i precision", 30, a.precision()); assertEquals("-3+4i value", new Apcomplex("(-10.5813046757679821776505859518,-5.3256146315280061739958499710)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(-3,-4)").precision(30)); assertEquals("-3-4i precision", 30, a.precision()); assertEquals("-3-4i value", new Apcomplex("(-10.5813046757679821776505859518,5.3256146315280061739958499710)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(300,4)").precision(30)); assertEquals("300+4i precision", 30, a.precision()); assertEquals("300+4i value", new Apcomplex("(1409.17535710394427231445345360,22.80857843613452556017830512)"), a, new Apfloat("5e-26")); a = ApcomplexMath.logGamma(new Apcomplex("(-300,-4)").precision(30)); assertEquals("-300-4i precision", 30, a.precision()); assertEquals("-300-4i value", new Apcomplex("(-1425.60772200752672992622696153,921.22668142430419691996693265)"), a, new Apfloat("5e-26")); a = ApcomplexMath.logGamma(new Apcomplex("(3,400)").precision(30)); assertEquals("3+400i precision", 30, a.precision()); assertEquals("3+400i value", new Apcomplex("(-612.42091519215003296376447609,2000.50510137367765558763842034)"), a, new Apfloat("5e-26")); a = ApcomplexMath.logGamma(new Apcomplex("(7,-4)").precision(30)); assertEquals("7-4i precision", 29, a.precision()); assertEquals("7-4i value", new Apcomplex("(5.4180869718730471169905929840,-7.7181013652048386845411947705)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(3e100000,4e100000)").precision(30)); assertEquals("3e100000+4e100000i precision", 30, a.precision()); assertEquals("3e100000+4e100000i value", new Apcomplex("(6.90773647031079001057591524633e100005,9.21039256834922014845392270448e100005)"), a, new Apfloat("5e99975")); a = ApcomplexMath.logGamma(new Apcomplex("(-3e100000,4e100000)").precision(30)); assertEquals("-3e100000+4e100000i precision", 30, a.precision()); assertEquals("-3e100000+4e100000i value", new Apcomplex("(-6.90786213401693360230545375207e100005,9.21029832056961245465676882518e100005)"), a, new Apfloat("5e99975")); a = ApcomplexMath.logGamma(new Apcomplex("(3e-100000,4e-100000)").precision(30)); assertEquals("3e-100000+4e-100000i precision", 30, a.precision()); assertEquals("-3e100000+4e100000i value", new Apcomplex("(230256.89986149213430142454470910319,-0.927295218001612232428512462922)"), a, new Apfloat("5e-30")); a = ApcomplexMath.logGamma(new Apcomplex("(-3e-100000,4e-100000)").precision(30)); assertEquals("-3e-100000+4e-100000i precision", 30, a.precision()); assertEquals("-3e-100000+4e-100000i value", new Apcomplex("(230256.89986149213430142454470910319,-2.214297435588181006034130920357)"), a, new Apfloat("5e-29")); a = ApcomplexMath.logGamma(new Apcomplex("(-3e-8,-4e-8)").precision(6)); assertEquals("-3e-8-4e-8i precision", 6, a.precision()); assertEquals("-3e-8-4e-8i value", new Apcomplex("(16.81124,2.214297)"), a, new Apfloat("5e-5")); a = ApcomplexMath.logGamma(new Apcomplex("(0.001,0.001)").precision(30)); assertEquals("0.001+0.001i precision", 29, a.precision()); assertEquals("0.001+0.001i value", new Apcomplex("(6.56060447383755263956515723187,-0.785973734929653434835994646315)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(0,0.001)").precision(30)); assertEquals("0.001i precision", 30, a.precision()); assertEquals("0.001i value", new Apcomplex("(6.90775445651537420857962686091,-1.571373542059112725090803754152)"), a, new Apfloat("5e-29")); a = ApcomplexMath.logGamma(new Apcomplex("(-0.001,0.001)").precision(30)); assertEquals("-0.001+0.001i precision", 29, a.precision()); assertEquals("-0.001+0.001i value", new Apcomplex("(6.56175890356461150865814111470,-2.356773351592683747807274450833)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(0.001,2)").precision(30)); assertEquals("0.001+2i precision", 29, a.precision()); assertEquals("0.001+2i value", new Apcomplex("(-2.56851143797407428601007061119,-1.43932944213613926991901894905)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(0,2)").precision(30)); assertEquals("2i precision", 29, a.precision()); assertEquals("2i value", new Apcomplex("(-2.56922596699087465064722769986,-1.44115001048510830784761423525)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(-0.001,2)").precision(30)); assertEquals("-0.001+2i precision", 29, a.precision()); assertEquals("-0.001+2i value", new Apcomplex("(-2.56994062107649702287048674102,-1.44297105665961289556329006395)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(0.999,2)").precision(30)); assertEquals("0.999+2i precision", 29, a.precision()); assertEquals("0.999+2i value", new Apcomplex("(-1.87679331551656733845065045339,0.12832527009361706325136384495)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(-0.999,2)").precision(30)); assertEquals("-0.999+2i precision", 29, a.precision()); assertEquals("-0.999+2i value", new Apcomplex("(-3.37303045422046060401853555827,-3.47337329793718494112946036370)"), a, new Apfloat("5e-28")); a = ApcomplexMath.logGamma(new Apcomplex("(-0.5,0.01)").precision(17)); assertEquals("-0.5,0.1 precision", 17, a.precision()); assertEquals("-0.5,0.1 value", new Apcomplex("(1.2650654639403971,-3.141227615720128556)"), a, new Apfloat("5e-16")); a = ApcomplexMath.logGamma(new Apcomplex("(-0.5)").precision(17)); assertEquals("-0.5 precision", 17, a.precision()); assertEquals("-0.5 value", new Apcomplex("(1.2655121234846454,-3.1415926535897932)"), a, new Apfloat("5e-16")); a = ApcomplexMath.logGamma(new Apcomplex("(-0.5,-0.01)").precision(17)); assertEquals("-0.5,-0.01 precision", 17, a.precision()); assertEquals("-0.5,-0.01 value", new Apcomplex("(1.2650654639403971,3.141227615720128556)"), a, new Apfloat("5e-16")); a = ApcomplexMath.logGamma(new Apcomplex("(-1.5,0.01)").precision(17)); assertEquals("-1.5,0.1 precision", 16, a.precision()); assertEquals("-1.5,0.1 value", new Apcomplex("(0.8595781341038230,-6.27615370140605357)"), a, new Apfloat("5e-15")); a = ApcomplexMath.logGamma(new Apcomplex("(-1.5)").precision(17)); assertEquals("-1.5 precision", 16, a.precision()); assertEquals("-1.5 value", new Apcomplex("(0.8600470153764810,-6.2831853071795865)"), a, new Apfloat("5e-15")); a = ApcomplexMath.logGamma(new Apcomplex("(-1.5,-0.01)").precision(17)); assertEquals("-1.5,-0.01 precision", 16, a.precision()); assertEquals("-1.5,-0.01 value", new Apcomplex("(0.8595781341038230,6.27615370140605357)"), a, new Apfloat("5e-15")); a = ApcomplexMath.logGamma(new Apcomplex("(-2.5,0.01)").precision(17)); assertEquals("-2.5,0.1 precision", 16, a.precision()); assertEquals("-2.5,0.1 value", new Apcomplex("(-0.0567205977063328,-9.4137463763289753)"), a, new Apfloat("5e-15")); a = ApcomplexMath.logGamma(new Apcomplex("(-2.5)").precision(17)); assertEquals("-2.5 precision", 16, a.precision()); assertEquals("-2.5 value", new Apcomplex("(-0.0562437164976741,-9.4247779607693797)"), a, new Apfloat("5e-15")); a = ApcomplexMath.logGamma(new Apcomplex("(-2.5,-0.01)").precision(17)); assertEquals("-2.5,-0.01 precision", 16, a.precision()); assertEquals("-2.5,-0.01 value", new Apcomplex("(-0.0567205977063328,9.4137463763289753)"), a, new Apfloat("5e-15")); a = ApcomplexMath.logGamma(new Apcomplex("(1.0,600000.0)")); assertEquals("1+600000i precision", 7, a.precision()); assertEquals("1+600000i value", new Apcomplex("(-942470,7382812)"), a, new Apfloat("5e0")); a = ApcomplexMath.logGamma(new Apcomplex("(0,600000)")); assertEquals("600000i precision", 6, a.precision()); assertEquals("600000i value", new Apcomplex("(-942483,7382810)"), a, new Apfloat("5e1")); a = ApcomplexMath.logGamma(new Apcomplex("(0,600000.0)")); assertEquals("600000.0i precision", 7, a.precision()); assertEquals("600000.0i value", new Apcomplex("(-942483,7382810)"), a, new Apfloat("5e0")); a = ApcomplexMath.logGamma(new Apcomplex("(-1.0,600000.0)")); assertEquals("-1+600000i precision", 7, a.precision()); assertEquals("-1+600000i value", new Apcomplex("(-942497,7382809)"), a, new Apfloat("5e0")); a = ApcomplexMath.logGamma(new Apcomplex("(1.00000e600000,0)")); assertEquals("1e600000 precision", 6, a.precision()); assertEquals("1e600000 value", new Apcomplex("(1.38155e600006)"), a, new Apfloat("5e600001")); a = ApcomplexMath.logGamma(new Apcomplex("(-1.00000e600000,1)")); assertEquals("-1e600000+i precision", 6, a.precision()); assertEquals("-1e600000+i value", new Apcomplex("(-1.38155e600006,-3.14159e600000)"), a, new Apfloat("5e600001")); a = ApcomplexMath.logGamma(new Apcomplex("(-1.00000e600000,-1)")); assertEquals("-1e600000-i precision", 6, a.precision()); assertEquals("-1e600000-i value", new Apcomplex("(-1.38155e600006,-3.14159e600000)"), a, new Apfloat("5e600001")); a = ApcomplexMath.logGamma(new Apcomplex("(0,1.00000e600000)")); assertEquals("1e600000i precision", 6, a.precision()); assertEquals("1e600000i value", new Apcomplex("(-1.5708e600000,1.38155e600006)"), a, new Apfloat("5e600001")); a = ApcomplexMath.logGamma(new Apcomplex("6.00000")); assertEquals("6 precision", 6, a.precision()); assertEquals("6 value", new Apcomplex("4.78749"), a, new Apfloat("5e-5")); a = ApcomplexMath.logGamma(new Apcomplex("-4.50000")); assertEquals("-4.5 precision", 7, a.precision()); assertEquals("-4.5 value", new Apcomplex("(-2.81308,-15.70796)"), a, new Apfloat("5e-5")); a = ApcomplexMath.logGamma(new Apcomplex("(-9.71e-2,1.5386)")); assertEquals("-9.71e-2+1.5386i precision", 4, a.precision()); assertEquals("-9.71e-2+1.5386i value", new Apcomplex("(-1.75979,-1.90299)"), a, new Apfloat("5e-3")); a = ApcomplexMath.logGamma(new Apcomplex("3")); assertEquals("3 precision", 1, a.precision(), 1); assertEquals("3 value", new Apcomplex("0.7"), a, new Apfloat("5e-1")); a = ApcomplexMath.logGamma(new Apcomplex("1").precision(100)); assertEquals("1 value", new Apcomplex("0"), a); a = ApcomplexMath.logGamma(new Apcomplex("2").precision(100)); assertEquals("2 value", new Apcomplex("0"), a); a = ApcomplexMath.logGamma(new Apcomplex(new Apfloat(-5, 20, 9), new Apfloat(-6, 20,9))); assertEquals("-5-6i radix precision", 20, a.precision()); assertEquals("-5-6i radix value", new Apcomplex(new Apfloat("-20.8777170116531164514", 20, 9), new Apfloat("6.1201335747842606317", 20, 9)), a, new Apfloat("5e-18", 1, 9)); try { ApcomplexMath.logGamma(Apcomplex.ZERO); fail("Log gamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.logGamma(new Apcomplex("-1")); fail("Log gamma of -1"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.logGamma(new Apcomplex(new Apint(3), new Apint(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testDigamma() { Apcomplex a = ApcomplexMath.digamma(new Apcomplex("(3,4)").precision(30)); assertEquals("3+4i precision", 32, a.precision(), 1); assertEquals("3+4i value", new Apcomplex("(1.55035981733341091269899018667062,1.01050220918604445291687052250976)"), a, new Apfloat("5e-31")); a = ApcomplexMath.digamma(new Apcomplex("(3,-4)").precision(30)); assertEquals("3-4i precision", 32, a.precision(), 1); assertEquals("3-4i value", new Apcomplex("(1.55035981733341091269899018667062,-1.01050220918604445291687052250976)"), a, new Apfloat("5e-31")); a = ApcomplexMath.digamma(new Apcomplex("(-3,4)").precision(30)); assertEquals("-3+4i precision", 30, a.precision()); assertEquals("-3+4i value", new Apcomplex("(1.67035981733341091269899018667,2.29109044448016209997569405192)"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(new Apcomplex("(-3,-4)").precision(30)); assertEquals("-3-4i precision", 30, a.precision()); assertEquals("-3-4i value", new Apcomplex("(1.67035981733341091269899018667,-2.29109044448016209997569405192)"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(new Apcomplex("(3000000,4000000)").precision(30)); assertEquals("3000000+4000000i precision", 30, a.precision()); assertEquals("3000000+4000000i value", new Apcomplex("(15.4249484103983754120420413946545,0.9272952980016154324285124629296)"), a, new Apfloat("5e-28")); a = ApcomplexMath.digamma(new Apcomplex("(3000000,-4000000)").precision(30)); assertEquals("3000000-4000000i precision", 30, a.precision()); assertEquals("3000000-4000000i value", new Apcomplex("(15.4249484103983754120420413946545,-0.9272952980016154324285124629296)"), a, new Apfloat("5e-28")); a = ApcomplexMath.digamma(new Apcomplex("(-3000000,4000000)").precision(30)); assertEquals("-3000000+4000000i precision", 30, a.precision()); assertEquals("-3000000+4000000i value", new Apcomplex("(15.4249485303983754120420413947,2.2142975155881778060341309203)"), a, new Apfloat("5e-28")); a = ApcomplexMath.digamma(new Apcomplex("(-3000000,-4000000)").precision(30)); assertEquals("-3000000-4000000i precision", 30, a.precision()); assertEquals("-3000000-4000000i value", new Apcomplex("(15.4249485303983754120420413947,-2.2142975155881778060341309203)"), a, new Apfloat("5e-28")); a = ApcomplexMath.digamma(new Apcomplex("(0,1e4000000)").precision(30)); assertEquals("1e4000000i precision", 36, a.precision()); assertEquals("1e4000000i value", new Apcomplex("(9.21034037197618273607196581873745683e6,1.57079632679489661923132169164)"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(new Apcomplex("(0,-1e4000000)").precision(30)); assertEquals("-1e4000000i precision", 36, a.precision()); assertEquals("-1e4000000i value", new Apcomplex("(9.21034037197618273607196581873745683e6,-1.57079632679489661923132169164)"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(new Apcomplex("(1e4000000,1e4000000)").precision(30)); assertEquals("1e4000000+1e4000000i precision", 36, a.precision()); assertEquals("1e4000000+1e4000000i value", new Apcomplex("(9.21034071854977301604462052735351756e6,0.78539816339744830961566084582)"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(new Apcomplex("(1e4000000,-1e4000000)").precision(30)); assertEquals("1e4000000-1e4000000i precision", 36, a.precision()); assertEquals("1e4000000-1e4000000i value", new Apcomplex("(9.21034071854977301604462052735351756e6,-0.78539816339744830961566084582)"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(ApfloatHelper.setPrecision(new Apcomplex("(1e3000000,1e4000000)"), 30)); assertEquals("1e3000000+1e4000000i precision", 36, a.precision()); assertEquals("1e3000000+1e4000000i value", new Apcomplex("(9.21034037197618273607196581873745683e6,1.57079632679489661923132169164)"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(ApfloatHelper.setPrecision(new Apcomplex("(1e3000000,-1e4000000)"), 30)); assertEquals("1e3000000-1e4000000i precision", 36, a.precision()); assertEquals("1e3000000-1e4000000i value", new Apcomplex("(9.21034037197618273607196581873745683e6,-1.57079632679489661923132169164)"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(ApfloatHelper.setPrecision(new Apcomplex("(1e4000000,1e3000000)"), 30)); assertEquals("1e4000000+1e3000000i precision", 36, a.precision()); assertEquals("1e4000000+1e3000000i value", new Apcomplex("9.21034037197618273607196581873745683e6"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(ApfloatHelper.setPrecision(new Apcomplex("(1e4000000,-1e3000000)"), 30)); assertEquals("1e4000000-1e3000000i precision", 36, a.precision()); assertEquals("1e4000000-1e3000000i value", new Apcomplex("9.21034037197618273607196581873745683e6"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(ApfloatHelper.setPrecision(new Apcomplex("(1e-3000,1e-4000)"), 30)); assertEquals("1e-3000+1e-4000i precision", 30, a.precision()); assertEquals("1e-3000+1e-4000i value", new Apcomplex("(-1.00000000000000000000000000000e3000,1.00000000000000000000000000000e2000)"), a, new Apfloat("5e2971")); a = ApcomplexMath.digamma(ApfloatHelper.setPrecision(new Apcomplex("(1e-3000,-1e-4000)"), 30)); assertEquals("1e-3000-1e-4000i precision", 30, a.precision()); assertEquals("1e-3000-1e-4000i value", new Apcomplex("(-1.00000000000000000000000000000e3000,-1.00000000000000000000000000000e2000)"), a, new Apfloat("5e2971")); a = ApcomplexMath.digamma(ApfloatHelper.setPrecision(new Apcomplex("(-1e-3000,1e-4000)"), 30)); assertEquals("-1e-3000+1e-4000i precision", 30, a.precision()); assertEquals("-1e-3000+1e-4000i value", new Apcomplex("(1.00000000000000000000000000000e3000,1.00000000000000000000000000000e2000)"), a, new Apfloat("5e2971")); a = ApcomplexMath.digamma(ApfloatHelper.setPrecision(new Apcomplex("(-1e-3000,-1e-4000)"), 30)); assertEquals("-1e-3000-1e-4000i precision", 30, a.precision()); assertEquals("-1e-3000-1e-4000i value", new Apcomplex("(1.00000000000000000000000000000e3000,-1.00000000000000000000000000000e2000)"), a, new Apfloat("5e2971")); a = ApcomplexMath.digamma(new Apcomplex(new Apfloat(-3, 30, 11), new Apfloat(-4, 30, 11))); assertEquals("-3-4i precision radix 11", 30, a.precision()); assertEquals("-3-4i value radix 11", new Apcomplex(new Apfloat("1.741281343469756a206022a991993", 30, 11), new Apfloat("-2.32249452a48596236132467355150", 30, 11)), a, new Apfloat("5e-29", 1, 11)); a = ApcomplexMath.digamma(new Apfloat(6, 30, 10)); assertEquals("6 precision", 30, a.precision(), 1); assertEquals("6 value", new Apcomplex("1.70611766843180047272682124325"), a, new Apfloat("5e-29")); a = ApcomplexMath.digamma(new Apfloat("-6.5", 30, 10)); assertEquals("-6.5 precision", 30, a.precision(), 1); assertEquals("-6.5 value", new Apcomplex("1.94675748424608678806929117727"), a, new Apfloat("5e-29")); try { ApcomplexMath.digamma(Apcomplex.ZERO); fail("Digamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.digamma(new Apint(-1)); fail("Digamma of -1"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.digamma(ApfloatHelper.setPrecision(new Apcomplex("(-1e4000000,-1)"), 30)); fail("Loss of precision in cot()"); } catch (LossOfPrecisionException lope) { // OK } try { ApcomplexMath.digamma(new Apcomplex(Apfloat.ZERO, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } try { ApcomplexMath.digamma(new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testPolygamma() { Apcomplex a = ApcomplexMath.polygamma(0, new Apcomplex("(3,4)").precision(30)); assertEquals("0, 3+4i precision", 31, a.precision()); assertEquals("0, 3+4i value", new Apcomplex("(1.55035981733341091269899018667062,1.01050220918604445291687052250976)"), a, new Apfloat("5e-31")); a = ApcomplexMath.polygamma(0, new Apcomplex("(-2,-3)").precision(10)); assertEquals("0, -2-3i precision", 10, a.precision()); assertEquals("0, -2-3i value", new Apcomplex("(1.361826864,-2.268232244)"), a, new Apfloat("5e-9")); a = ApcomplexMath.polygamma(1, new Apcomplex("(3,4)").precision(30)); assertEquals("1, 3+4i precision", 30, a.precision()); assertEquals("1, 3+4i value", new Apcomplex("(0.113153113946791703820257508880,-0.179680016184178366603774041063)"), a, new Apfloat("5e-30")); a = ApcomplexMath.polygamma(1, new Apcomplex("(-2,-3)").precision(10)); assertEquals("1, -2-3i precision", 10, a.precision()); assertEquals("1, -2-3i value", new Apcomplex("(-0.1651414829,0.1960040752)"), a, new Apfloat("5e-10")); a = ApcomplexMath.polygamma(3, new Apcomplex("(3,4)").precision(30)); assertEquals("3, 3+4i precision", 30, a.precision()); assertEquals("3, 3+4i value", new Apcomplex("(-0.0190846939956098231157835648328,-0.0024113608683529464829469139204)"), a, new Apfloat("5e-31")); a = ApcomplexMath.polygamma(3, new Apcomplex("(-2,-3)").precision(10)); assertEquals("3, -2-3i precision", 10, a.precision()); assertEquals("3, -2-3i value", new Apcomplex("(0.02884298730,0.01752010783)"), a, new Apfloat("5e-11")); a = ApcomplexMath.polygamma(2, new Apcomplex("1").precision(6)); assertEquals("2, 1 precision", 6, a.precision()); assertEquals("2, 1 value", new Apcomplex("-2.40411"), a, new Apfloat("5e-5")); try { ApcomplexMath.polygamma(-1, new Apcomplex("(3.00000,4.00000)")); fail("Polygamma of negative order"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.polygamma(1, Apcomplex.ZERO); fail("Polygamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.polygamma(1, new Apint(-1)); fail("Polygamma of -1"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.polygamma(1, new Apcomplex(Apfloat.ZERO, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } try { ApcomplexMath.polygamma(1, new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testBeta() { Apcomplex a = ApcomplexMath.beta(new Apcomplex("(1,2)").precision(30), new Apcomplex("(3,4)").precision(30)); assertEquals("1+2i, 3+4i precision", 30, a.precision()); assertEquals("1+2i, 3+4i value", new Apcomplex("(-0.061274167452252944196162548943,0.197519756150022453064336846144)"), a, new Apfloat("5e-30")); a = ApcomplexMath.beta(new Apcomplex("3.00000"), new Apcomplex("3.50000")); assertEquals("3, 3.5 precision", 6, a.precision()); assertEquals("3, 3.5 value", new Apcomplex("0.0230880"), a, new Apfloat("5e-7")); a = ApcomplexMath.beta(new Apcomplex("3.50000"), new Apcomplex("3.00000")); assertEquals("3.5, 3 precision", 6, a.precision()); assertEquals("3.5, 3 value", new Apcomplex("0.0230880"), a, new Apfloat("5e-7")); a = ApcomplexMath.beta(new Apcomplex("3").precision(30), new Apcomplex("-3").precision(30)); assertEquals("3, -3 precision", 30, a.precision()); assertEquals("3, -3 value", new Apcomplex("-0.333333333333333333333333333333"), a, new Apfloat("5e-30")); a = ApcomplexMath.beta(new Apcomplex("3.5"), new Apcomplex("-3.5")); assertEquals("3.5, -3.5 precision", Apfloat.INFINITE, a.precision()); assertEquals("3.5, -3.5 value", new Apcomplex("0"), a); a = ApcomplexMath.beta(new Apcomplex("-0.999999"), new Apcomplex("4.00000")); assertEquals("-0.999999, 4 precision", 6, a.precision()); assertEquals("-0.999999, 4 value", new Apcomplex("-2.99999e6"), a, new Apfloat("5e1")); a = ApcomplexMath.beta(new Apcomplex("4.00000"), new Apcomplex("-0.999999")); assertEquals("4, -0.999999 precision", 6, a.precision()); assertEquals("4, -0.999999 value", new Apcomplex("-2.99999e6"), a, new Apfloat("5e1")); try { ApcomplexMath.beta(new Apcomplex("-4"), new Apcomplex("3.5")); fail("Beta of -4, 3.5"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.beta(new Apcomplex("-4"), new Apcomplex("-3")); fail("Beta of -4, -3"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.beta(new Apint(4), new Apint(-3)); fail("Beta of 4, -3"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.beta(new Apint(0), new Apint(1)); fail("Beta of 0, 1"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.beta(new Apint(0), new Apint(0)); fail("Beta of 0, 0"); } catch (ArithmeticException ae) { // OK } } public static void testBetaIncomplete() { Apcomplex a = ApcomplexMath.beta(new Apcomplex("(1,2)").precision(30), new Apcomplex("(3,4)").precision(30), new Apcomplex("(5,6)").precision(30)); assertEquals("1+2i, 3+4i, 5+6i precision", 29, a.precision()); assertEquals("1+2i, 3+4i, 5+6i value", new Apcomplex("(-1720.81983111510859046209114724,-1217.54471001550464664125821887)"), a, new Apfloat("5e-25")); a = ApcomplexMath.beta(new Apcomplex("(1,2)").precision(30), new Apcomplex("1").precision(30), new Apcomplex("(5,6)").precision(30)); assertEquals("1+2i, 1, 5+6i precision", 29, a.precision()); assertEquals("1+2i, 1, 5+6i value", new Apcomplex("(7146.750742209233540609443877,-50265.400817471882772163196595)"), a, new Apfloat("5e-24")); try { ApcomplexMath.beta(new Apcomplex("1"), new Apcomplex("-4"), new Apcomplex("3.5")); fail("Beta of 1, -4, 3.5"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.beta(new Apcomplex("0"), new Apcomplex("(0,4)"), new Apcomplex("3.5")); fail("Beta of 0, 4i, 3.5"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.beta(new Apcomplex("1"), new Apcomplex("0"), new Apcomplex("3.5")); fail("Beta of 1, 0, 3.5"); } catch (ArithmeticException ae) { // OK } } public static void testBetaIncompleteGeneralized() { Apcomplex a = ApcomplexMath.beta(new Apcomplex("(1,2)").precision(30), new Apcomplex("(3,4)").precision(30), new Apcomplex("(5,6)").precision(30), new Apcomplex("(7,8)").precision(30)); assertEquals("1+2i, 3+4i, 5+6i, 7+8i precision", 29, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 7+8i value", new Apcomplex("(4.50638342846197639932002079147e10,3.86722680716135531751599616064e10)"), a, new Apfloat("5e-18")); a = ApcomplexMath.beta(new Apcomplex("(2.000000,3.000000)"), new Apcomplex("(3.000000,4.000000)"), new Apcomplex("1.000000"), new Apcomplex("(5.000000,6.000000)")); assertEquals("2+3i, 3+4i, 1, 5+6i precision", 6, a.precision()); assertEquals("2+3i, 3+4i, 1, 5+6i value", new Apcomplex("(1.82681e7,4.14226e7)"), a, new Apfloat("5e2")); a = ApcomplexMath.beta(new Apcomplex("2"), new Apcomplex("2"), new Apcomplex("0"), new Apcomplex("3.5")); assertEquals("2, 2, 0, 3.5 precision", Apfloat.INFINITE, a.precision()); assertEquals("2, 2, 0, 3.5 value", new Apcomplex("0"), a); try { ApcomplexMath.beta(new Apcomplex("1"), new Apcomplex("2"), new Apcomplex("-4"), new Apcomplex("3.5")); fail("Beta of 1, 2, -4, 3.5"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.beta(new Apcomplex("0"), new Apcomplex("1"), new Apcomplex("(0,4)"), new Apcomplex("3.5")); fail("Beta of 0, 1, 4i, 3.5"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.beta(new Apcomplex("1"), new Apcomplex("0"), new Apcomplex("(0,4)"), new Apcomplex("3.5")); fail("Beta of 1, 0, 4i, 3.5"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.beta(new Apcomplex("1"), new Apcomplex("2"), new Apcomplex("0"), new Apcomplex("3.5")); fail("Beta of 1, 2, 0, 3.5"); } catch (ArithmeticException ae) { // OK } } public static void testPochhammer() { Apcomplex a = ApcomplexMath.pochhammer(new Apcomplex("(1,2)").precision(30), new Apcomplex("(3,4)").precision(30)); assertEquals("1+2i, 3+4i precision", 30, a.precision()); assertEquals("1+2i, 3+4i value", new Apcomplex("(-0.804367351520622246280725889393,0.223073388594934185914414383944)"), a, new Apfloat("5e-30")); a = ApcomplexMath.pochhammer(new Apcomplex("0"), new Apcomplex("-1.00")); assertEquals("0, -1 precision", 3, a.precision()); assertEquals("0, -1 value", new Apcomplex("-1.00"), a, new Apfloat("5e-2")); a = ApcomplexMath.pochhammer(new Apcomplex("-1.00"), new Apcomplex("0")); assertEquals("-1, 0 precision", 3, a.precision()); assertEquals("-1, 0 value", new Apcomplex("1.00"), a); a = ApcomplexMath.pochhammer(new Apcomplex("-1.00"), new Apcomplex("1.00")); assertEquals("0, -1 precision", 3, a.precision()); assertEquals("0, -1 value", new Apcomplex("-1.00"), a, new Apfloat("5e-2")); a = ApcomplexMath.pochhammer(new Apcomplex("-1.00"), new Apcomplex("2.00")); assertEquals("-1, 2 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, 2 value", new Apcomplex("0"), a); a = ApcomplexMath.pochhammer(new Apcomplex("0"), new Apcomplex("1.00")); assertEquals("0, 1 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 1 value", new Apcomplex("0"), a); a = ApcomplexMath.pochhammer(new Apcomplex("-1.00"), new Apcomplex("0.500")); assertEquals("-1, 0.5 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, 0.5 value", new Apcomplex("0"), a); a = ApcomplexMath.pochhammer(new Apcomplex("3.00"), new Apcomplex("-1.00")); assertEquals("3, -1 precision", 3, a.precision()); assertEquals("3, -1 value", new Apcomplex("0.500"), a, new Apfloat("5e-3")); a = ApcomplexMath.pochhammer(new Apcomplex("0"), new Apcomplex("-2.00")); assertEquals("0, -2 precision", 3, a.precision()); assertEquals("0, -2 value", new Apcomplex("0.500"), a, new Apfloat("5e-3")); a = ApcomplexMath.pochhammer(new Apcomplex("3.00"), new Apcomplex("(0,2.00)")); assertEquals("3, -2i precision", 3, a.precision()); assertEquals("3, -2i value", new Apcomplex("(-0.211,0.436)"), a, new Apfloat("5e-3")); a = ApcomplexMath.pochhammer(new Apcomplex("0.12345"), new Apcomplex("12345")); assertEquals("0.12345, 12345 precision", 5, a.precision()); assertEquals("0.12345, 12345 value", new Apcomplex("1.16927e45146"), a, new Apfloat("5e45142")); a = ApcomplexMath.pochhammer(new Apcomplex("-0.999999"), new Apcomplex("2.00000")); assertEquals("-0.999999, 2 precision", 6, a.precision()); assertEquals("-0.999999, 2 value", new Apcomplex("-9.99999e-7"), a, new Apfloat("5e-12")); a = ApcomplexMath.pochhammer(new Apcomplex("-0.999999"), new Apcomplex("3.50000")); assertEquals("-0.999999, 3.5 precision", 6, a.precision()); assertEquals("-0.999999, 3.5 value", new Apcomplex("-1.32934e-6"), a, new Apfloat("5e-11")); a = ApcomplexMath.pochhammer(new Apcomplex("1.00000e-1000000000000000"), new Apcomplex("2.00000")); assertEquals("1e-1000000000000000, 2 precision", 6, a.precision()); assertEquals("1e-1000000000000000, 2 value", new Apcomplex("1.00000e-1000000000000000"), a, new Apfloat("5e-1000000000000005")); try { ApcomplexMath.pochhammer(new Apcomplex("-0.50000"), new Apcomplex("-0.50000")); fail("Gamma of -1"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.pochhammer(new Apcomplex("0.50000"), new Apcomplex("-0.50000")); fail("Gamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.pochhammer(new Apcomplex("1"), new Apcomplex("-1")); fail("Gamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.pochhammer(new Apcomplex(new Apint(1), new Apint(2)), new Apcomplex(new Apint(3), new Apint(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testBinomial() { Apcomplex a = ApcomplexMath.binomial(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("(3,4),(5,6) precision", 6, a.precision()); assertEquals("(3,4),(5,6) value", new Apcomplex("(-3.10924,-1.60449)"), a, new Apfloat("5e-5")); a = ApcomplexMath.binomial(new Apfloat(0), new Apfloat(0)); assertEquals("0,0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0,0 value", new Apfloat(1), a); a = ApcomplexMath.binomial(new Apfloat(1), new Apfloat(0)); assertEquals("1,0 precision", Apfloat.INFINITE, a.precision()); assertEquals("1,0 value", new Apfloat(1), a); a = ApcomplexMath.binomial(new Apcomplex("(0,3.20000)"), new Apcomplex("4.00000")); assertEquals("3.2i,4 precision", 6, a.precision()); assertEquals("3.2i,4 value", new Apcomplex("(-0.324267,7.39200)"), a, new Apfloat("5e-5")); a = ApcomplexMath.binomial(new Apcomplex("(7.20000,1.00000)"), new Apcomplex("(4.20000,1.00000)")); assertEquals("7.2+i,4.2+i precision", 6, a.precision()); assertEquals("7.2+i,4.2+i value", new Apcomplex("(35.5880,18.8867)"), a, new Apfloat("5e-4")); a = ApcomplexMath.binomial(new Apcomplex("(3.20000,1.00000)"), new Apcomplex("(4.20000,1.00000)")); assertEquals("3.2+i,4.2+i precision", Apcomplex.INFINITE, a.precision()); assertEquals("3.2+i,4.2+i value", new Apcomplex("0"), a); a = ApcomplexMath.binomial(new Apcomplex("(0,3.20000)"), new Apcomplex("-4.00000")); assertEquals("3.2i,-4 precision", Apcomplex.INFINITE, a.precision()); assertEquals("3.2i,-4 value", new Apcomplex("0"), a); try { ApcomplexMath.binomial(new Apcomplex("-3.00000"), new Apcomplex("(0,4.00000)")); fail("Binomial of -3,4i"); } catch (ArithmeticException ae) { // OK } } public static void testZeta() { Apcomplex a = ApcomplexMath.zeta(new Apcomplex("(2.00000,3.00000)")); assertEquals("2+3i precision", 6, a.precision()); assertEquals("2+3i value", new Apcomplex("(0.798022,-0.113744)"), a, new Apfloat("5e-6")); a = ApcomplexMath.zeta(new Apcomplex("(0,3.00000)")); assertEquals("0+3i precision", 6, a.precision()); assertEquals("0+3i value", new Apcomplex("(0.439283,-0.0364719)"), a, new Apfloat("5e-6")); a = ApcomplexMath.zeta(new Apcomplex("(-1.50000,-3.00000)")); assertEquals("-1.5-3i precision", 6, a.precision()); assertEquals("-1.5-3i value", new Apcomplex("(0.201329,-0.0971497)"), a, new Apfloat("5e-7")); a = ApcomplexMath.zeta(new Apcomplex("(1.00000,3.00000)")); assertEquals("1+3i precision", 6, a.precision()); assertEquals("1+3i value", new Apcomplex("(0.628852,-0.107476)"), a, new Apfloat("5e-6")); a = ApcomplexMath.zeta(new Apcomplex("(0.50000,3.00000)")); assertEquals("0.5+3i precision", 6, a.precision()); assertEquals("0.5+3i value", new Apcomplex("(0.532737,-0.0788965)"), a, new Apfloat("5e-7")); a = ApcomplexMath.zeta(new Apcomplex("(0.50000,1000.00000)")); assertEquals("0.5+1000i precision", 6, a.precision()); assertEquals("0.5+1000i value", new Apcomplex("(0.356334,0.931998)"), a, new Apfloat("5e-6")); a = ApcomplexMath.zeta(new Apcomplex("(1.00000,0.00100000)")); assertEquals("1+0.001i precision", 5, a.precision()); assertEquals("1+0.001i value", new Apcomplex("(0.577216,-1000.00)"), a, new Apfloat("5e-2")); a = ApcomplexMath.zeta(new Apcomplex("(2,3)").precision(100)); assertEquals("2+3i precision", 100, a.precision()); assertEquals("2+3i value", new Apcomplex("(0.7980219851462757206222945007248126860252200816083761283248050997826895848039950677534983494423933738,-0.1137443080529385002159133658573150755701378063996650889647244069923585325514128567603037164372547988)"), a, new Apfloat("5e-100")); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("0.5", 100), new Apfloat(1000, 104))); assertEquals("0.5+1000i precision 100", 100, a.precision()); assertEquals("0.5+1000i value 100", new Apcomplex("(0.3563343671943960550744024767110296418750462109065525137341055161422510305547050764059845122070513740,0.9319978312329936651150604327370560741603548016645680162344141200846918466728345537721968349602390048)"), a, new Apfloat("5e-100")); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("0.5", 5), new Apfloat(55000, 10))); assertEquals("0.5+10000i precision", 5, a.precision()); assertEquals("0.5+10000i value", new Apcomplex("(0.33492,0.08418)"), a, new Apfloat("5e-5")); /* These tests are quite slow a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("0.5", 100), new Apfloat(55000, 105))); assertEquals("0.5+10000i precision", 100, a.precision()); assertEquals("0.5+10000i value", new Apcomplex("(0.3349197720514120096603674282428742796903831318984995606867247129474952184104423947312465231789576299,0.0841783899417542541667178765548311987703519184678648667055626089534129546322036235064366776146346549)"), a, new Apfloat("5e-100")); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("0.5", 100), new Apfloat(10000, 105))); assertEquals("0.5+10000i precision", 100, a.precision()); assertEquals("0.5+10000i value", new Apcomplex("(-0.3393738026388344575674710779459893805666468101906410889337680247470798756615454924994040171851332603,-0.0370915059732060314743442068130120234022523694433894137028295017082175782077688242563900270774953535)"), a, new Apfloat("5e-100")); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("0.5", 100), new Apfloat(100000, 106))); assertEquals("0.5+100000i precision", 101, a.precision()); assertEquals("0.5+100000i value", new Apcomplex("(1.0730320148577531321140762694920985306591621977677459354641392297498113660694398465432029270776708412,5.7808485443635039842610405578322343742615982357792297214917608074005985960567100284957369179276183025)"), a, new Apfloat("5e-100")); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("0.5", 100), new Apfloat(1000000, 108))); assertEquals("0.5+1000000i precision", 100, a.precision()); assertEquals("0.5+1000000i value", new Apcomplex("(0.076089069738227100005564558379927322310798604744722282657978217385062498238818630801746583609816947,2.805102101019298955393836716564940236462506152772803595920107742605247149870834705975457224921619717)"), a, new Apfloat("5e-100")); */ for (int precision = 2; precision < 20; precision++) { a = ApcomplexMath.zeta(new Apcomplex("(2,3)").precision(precision)); assertEquals("2+3i precision " + precision, precision, a.precision()); assertEquals("2+3i value " + precision, new Apcomplex("(0.79802198514627572062,-0.11374430805293850021)").precision(precision), a, new Apfloat("5e-" + precision)); } a = ApcomplexMath.zeta(new Apcomplex(new Apfloat(2, 6, 11), new Apfloat(3, 6, 11))); assertEquals("2+3i radix 11 precision", 6, a.precision()); assertEquals("2+3i radix 11 value", new Apcomplex(new Apfloat("0.886193", 6, 11), new Apfloat("-0.128437", 6, 11)), a, new Apfloat("5e-6", 1, 11)); a = ApcomplexMath.zeta(new Apfloat(-200001, 20)); assertEquals("-200001 precision", 15, a.precision()); assertEquals("-200001 value", new Apfloat("-1.5289316181229617526e813718"), a, new Apfloat("5e813704")); a = ApcomplexMath.zeta(new Apfloat(-11, 20)); assertEquals("-11 precision", 19, a.precision()); assertEquals("-11 value", new Apfloat("0.021092796092796092796"), a, new Apfloat("5e-20")); a = ApcomplexMath.zeta(new Apint(-1)); assertEquals("-1 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1 value", new Aprational("-1/12"), a); a = ApcomplexMath.zeta(new Apint(-2)); assertEquals("-2 precision", Apfloat.INFINITE, a.precision()); assertEquals("-2 value", Apfloat.ZERO, a); a = ApcomplexMath.zeta(new Apint(-3)); assertEquals("-3 precision", Apfloat.INFINITE, a.precision()); assertEquals("-3 value", new Aprational("1/120"), a); a = ApcomplexMath.zeta(new Apint(-4, 11)); assertEquals("-4 precision", Apfloat.INFINITE, a.precision()); assertEquals("-4 value", Apfloat.ZERO, a); assertEquals("-4 radix", 11, a.radix()); a = ApcomplexMath.zeta(new Apint(-5, 13)); assertEquals("-5 precision", Apfloat.INFINITE, a.precision()); assertEquals("-5 value", new Aprational("-1/165", 13), a); assertEquals("-5 radix", 13, a.radix()); try { ApcomplexMath.zeta(Apcomplex.ONE); fail("Zeta of one"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.zeta(new Apcomplex("(0.5,1e1000)")); fail("Overflow"); } catch (OverflowException are) { // OK } try { ApcomplexMath.zeta(new Apcomplex("(0.5,1e100)")); fail("Loss of precision"); } catch (LossOfPrecisionException lope) { // OK } try { ApcomplexMath.zeta(new Apcomplex(Apfloat.ZERO, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testZetaHurwitz() { Apcomplex a = ApcomplexMath.zeta(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)")); assertEquals("1+2i,3+4i precision", 6, a.precision()); assertEquals("1+2i,3+4i value", new Apcomplex("(-0.128334,3.75887)"), a, new Apfloat("5e-5")); a = ApcomplexMath.zeta(new Apcomplex("(-1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)")); assertEquals("-1+2i,3+4i precision", 6, a.precision()); assertEquals("-1+2i,3+4i value", new Apcomplex("(-57.3674,17.7938)"), a, new Apfloat("5e-4")); a = ApcomplexMath.zeta(new Apcomplex("(1.00000,-2.00000)"), new Apcomplex("(3.00000,4.00000)")); assertEquals("1-2i,3+4i precision", 6, a.precision()); assertEquals("1-2i,3+4i value", new Apcomplex("(-0.00315145,-0.0659678)"), a, new Apfloat("5e-7")); a = ApcomplexMath.zeta(new Apcomplex("(-1.00000,-2.00000)"), new Apcomplex("(3.00000,4.00000)")); assertEquals("-1-2i,3+4i precision", 6, a.precision()); assertEquals("-1-2i,3+4i value", new Apcomplex("(0.370730,0.957515)"), a, new Apfloat("5e-6")); a = ApcomplexMath.zeta(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(-3.00000,4.00000)")); assertEquals("1+2i,-3+4i precision", 6, a.precision()); assertEquals("1+2i,-3+4i value", new Apcomplex("(9.3754,47.9189)"), a, new Apfloat("5e-4")); a = ApcomplexMath.zeta(new Apcomplex("(-1.00000,2.00000)"), new Apcomplex("(-3.00000,4.00000)")); assertEquals("-1+2i,-3+4i precision", 6, a.precision()); assertEquals("-1+2i,-3+4i value", new Apcomplex("(423.329,-866.408)"), a, new Apfloat("5e-3")); a = ApcomplexMath.zeta(new Apcomplex("(1.00000,-2.00000)"), new Apcomplex("(-3.00000,4.00000)")); assertEquals("1-2i,-3+4i precision", 6, a.precision()); assertEquals("1-2i,-3+4i value", new Apcomplex("(0.00104043,-0.00500563)"), a, new Apfloat("5e-8")); a = ApcomplexMath.zeta(new Apcomplex("(-1.00000,-2.00000)"), new Apcomplex("(-3.00000,4.00000)")); assertEquals("-1-2i,-3+4i precision", 6, a.precision()); assertEquals("-1-2i,-3+4i value", new Apcomplex("(-0.0677588,-0.0780479)"), a, new Apfloat("5e-7")); a = ApcomplexMath.zeta(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,-4.00000)")); assertEquals("1+2i,3-4i precision", 6, a.precision()); assertEquals("1+2i,3-4i value", new Apcomplex("(-0.00315145,0.0659678)"), a, new Apfloat("5e-7")); a = ApcomplexMath.zeta(new Apcomplex("(-1.00000,2.00000)"), new Apcomplex("(3.00000,-4.00000)")); assertEquals("-1+2i,3-4i precision", 6, a.precision()); assertEquals("-1+2i,3-4i value", new Apcomplex("(0.370730,-0.957515)"), a, new Apfloat("5e-6")); a = ApcomplexMath.zeta(new Apcomplex("(1.00000,-2.00000)"), new Apcomplex("(3.00000,-4.00000)")); assertEquals("1-2i,3-4i precision", 6, a.precision()); assertEquals("1-2i,3-4i value", new Apcomplex("(-0.128334,-3.75887)"), a, new Apfloat("5e-5")); a = ApcomplexMath.zeta(new Apcomplex("(-1.00000,-2.00000)"), new Apcomplex("(3.00000,-4.00000)")); assertEquals("-1-2i,3-4i precision", 6, a.precision()); assertEquals("-1-2i,3-4i value", new Apcomplex("(-57.3674,-17.7938)"), a, new Apfloat("5e-4")); a = ApcomplexMath.zeta(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(-3.00000,-4.00000)")); assertEquals("1+2i,-3-4i precision", 6, a.precision()); assertEquals("1+2i,-3-4i value", new Apcomplex("(0.00104043,0.00500563)"), a, new Apfloat("5e-8")); a = ApcomplexMath.zeta(new Apcomplex("(-1.00000,2.00000)"), new Apcomplex("(-3.00000,-4.00000)")); assertEquals("-1+2i,-3-4i precision", 6, a.precision()); assertEquals("-1+2i,-3-4i value", new Apcomplex("(-0.0677588,0.0780479)"), a, new Apfloat("5e-7")); a = ApcomplexMath.zeta(new Apcomplex("(1.00000,-2.00000)"), new Apcomplex("(-3.00000,-4.00000)")); assertEquals("1-2i,-3-4i precision", 6, a.precision()); assertEquals("1-2i,-3-4i value", new Apcomplex("(9.3754,-47.9189)"), a, new Apfloat("5e-4")); a = ApcomplexMath.zeta(new Apcomplex("(-1.00000,-2.00000)"), new Apcomplex("(-3.00000,-4.00000)")); assertEquals("-1-2i,-3-4i precision", 6, a.precision()); assertEquals("-1-2i,-3-4i value", new Apcomplex("(423.329,866.408)"), a, new Apfloat("5e-3")); a = ApcomplexMath.zeta(new Apcomplex("(200,3)").precision(100), new Apcomplex("(4,5)").precision(100)); assertEquals("200+3i,4+5i precision", 100, a.precision()); assertEquals("200+3i,4+5i value", new Apcomplex("(-6.510650712253089835100933540605593885423625555766396841030109372143821363398670155866232696777769754e-161,-4.196413709796671831220877888896810470945873889262943538389029106853602203682435123378815438519792110e-161)"), a, new Apfloat("5e-260")); a = ApcomplexMath.zeta(new Apcomplex("(-200,3)").precision(100), new Apcomplex("(4,5)").precision(100)); assertEquals("-200+3i,4+5i precision", 100, a.precision()); assertEquals("-200+3i,4+5i value", new Apcomplex("(-1.142766776555529743371297901097238001495355117120858842538861484336796660434095964178580019465230251e230,-7.93012330139120590521613115546189973364629076639541502155881731765751317903438879443411307094369442e229)"), a, new Apfloat("5e131")); a = ApcomplexMath.zeta(new Apcomplex("(2,300)").precision(100), new Apcomplex("(4,5)").precision(100)); assertEquals("2+300i,4+5i precision", 100, a.precision()); assertEquals("2+300i,4+5i value", new Apcomplex("(1.263022208466642119929613734524512143419322652805397208096904557073524855247036414033104354476916940e115,4.97993045496596456851060626340311079427549002991295705149743068485693575066125052846850379420489017e114)"), a, new Apfloat("5e16")); a = ApcomplexMath.zeta(new Apcomplex("(2,-300)").precision(100), new Apcomplex("(4,5)").precision(100)); assertEquals("2-300i,4+5i precision", 100, a.precision()); assertEquals("2-300i,4+5i value", new Apcomplex("(-1.656175472255496559727564671944616326873344713856337103136980595651959727043476386628834684809146318e-17,-6.681498034417950900886174675379127869732588558333009625497538461825412951655606371987994909561495188e-17)"), a, new Apfloat("5e-116")); a = ApcomplexMath.zeta(new Apcomplex("(2,3)").precision(100), new Apcomplex("(400,5)").precision(100)); assertEquals("2+3i,400+5i precision", 100, a.precision()); assertEquals("2+3i,400+5i value", new Apcomplex("(0.0007622758908028892841285412120539558133199778951059196976920207815264516538552449013583036172195813640,-0.0003070142863332686417875078833396554514650819941131970534284169324884139279052591800902624774270017371)"), a, new Apfloat("5e-103")); a = ApcomplexMath.zeta(new Apcomplex("(2,3)").precision(100), new Apcomplex("(-400,5)").precision(100)); assertEquals("2+3i,-400+5i precision", 100, a.precision()); assertEquals("2+3i,-400+5i value", new Apcomplex("(-8.801757372564087615610300337744809871640017567311551657978936640446111619828384618462840131011191894,3.367214239247479438315669736493982562557325268189216328935202322652541577231596038333636652254492929)"), a, new Apfloat("5e-99")); a = ApcomplexMath.zeta(new Apcomplex("(2,3)").precision(100), new Apcomplex("(4,500)").precision(100)); assertEquals("2+3i,4+500i precision", 100, a.precision()); assertEquals("2+3i,4+500i value", new Apcomplex("(-0.05932655962239436562739499724622952234262807293751692953398064487895538069336256502462076212692751826,-0.03511280488247812166160792282342282860315665135863852252502961596875493374359715802589497563087468930)"), a, new Apfloat("5e-101")); a = ApcomplexMath.zeta(new Apcomplex("(2,3)").precision(100), new Apcomplex("(4,-500)").precision(100)); assertEquals("2+3i,4-500i precision", 100, a.precision()); assertEquals("2+3i,4-500i value", new Apcomplex("(5.033864599238220394312706546835276797429459490608123122092294078279577716315638351945811941403453475e-6,2.884941945966693002338695967539314988955661994247957452817443910538025152229897547137605972983369419e-6)"), a, new Apfloat("5e-105")); a = ApcomplexMath.zeta(new Apcomplex("(-1.00000,2.00000)"), new Apcomplex("-3.00000")); assertEquals("-1+2i,-3 precision", 6, a.precision()); assertEquals("-1+2i,-3 value", new Apcomplex("(210.002,2354.18)"), a, new Apfloat("5e-2")); a = ApcomplexMath.zeta(new Apcomplex("0"), new Apcomplex("-1.00000")); assertEquals("0,-1 precision", 6, a.precision()); assertEquals("0,-1 value", new Apcomplex("(1.50000)"), a, new Apfloat("5e-5")); a = ApcomplexMath.zeta(new Apcomplex("0"), new Apcomplex("-2.00000")); assertEquals("0,-2 precision", 6, a.precision()); assertEquals("0,-2 value", new Apcomplex("(2.50000)"), a, new Apfloat("5e-5")); a = ApcomplexMath.zeta(new Apcomplex("(2,3)"), new Apcomplex("(4,5)")); assertEquals("2+3i,4+5i precision", 1, a.precision()); assertEquals("2+3i,4+5i value", new Apcomplex("(0.2,-0.9)"), a, new Apfloat("5e-1")); a = ApcomplexMath.zeta(new Apcomplex("-1.00000000000000000001000000000000000000"), new Apcomplex("(5.8177641733144326503024335907577183960e-3,2.9041784805448350436957228471747086506e-18)")); assertEquals("-1.00000000000000000001000000000000000000, 5.8177641733144326503024335907577183960e-3+2.9041784805448350436957228471747086506e-18i precision", 38, a.precision()); assertEquals("-1.00000000000000000001000000000000000000, 5.8177641733144326503024335907577183960e-3+2.9041784805448350436957228471747086506e-18i value", new Apcomplex("(-0.08044137443666426748877533567221511214,1.43519341475539303437e-18)"), a, new Apfloat("5e-39")); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("-7.5", 18, 9), new Apfloat("-3.2", 18, 9)), new Apcomplex(new Apfloat("-2.3", 18, 9), new Apfloat("-4.6", 18, 9))); assertEquals("-7.5-3.2i,-2.3-4.6i radix 9 precision", 18, a.precision()); assertEquals("-7.5-3.2i,-2.3-4.6i radix 9 value", new Apcomplex(new Apfloat("-4.30042688353112500e8", 18, 9), new Apfloat("1.43812330126776638e8", 18, 9)), a, new Apfloat("5e-8", 1, 9)); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("-1", 18, 2)), new Apcomplex(new Apfloat("0", 18, 2))); assertEquals("-1,0 radix 2 precision", 18, a.precision()); assertEquals("-1,0 radix 2 value", new Apcomplex(new Apfloat("-0.00010101010101010101011", 18, 2)), a, new Apfloat("1e-21", 1, 2)); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("0", 18, 2)), new Apcomplex(new Apfloat("-1", 18, 2))); assertEquals("0,-1 radix 2 precision", 18, a.precision()); assertEquals("0,-1 radix 2 value", new Apcomplex(new Apfloat("1.1", 18, 2)), a, new Apfloat("1e-17", 1, 2)); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("-0.1", 18, 2)), new Apcomplex(new Apfloat("-1", 18, 2))); assertEquals("-0.1,-1 radix 2 precision", 18, a.precision()); assertEquals("-0.1,-1 radix 2 value", new Apcomplex(new Apfloat("-0.001101010011100000001", 18, 2), new Apfloat("1", 18, 2)), a, new Apfloat("1e-17", 1, 2)); a = ApcomplexMath.zeta(new Apcomplex(new Apfloat("0", 18, 2)), new Apcomplex(new Apfloat("0", 18, 2))); assertEquals("0,0 radix 2 precision", Apfloat.INFINITE, a.precision()); assertEquals("0,0 radix 2 value", new Apcomplex(new Apfloat("0.1", Apfloat.INFINITE, 2)), a); for (int r = -5; r <= 5; r += 2) { for (int i = -5; i <= 5; i += 2) { Apfloat real = new Apfloat(r + 0.5, 10), imag = new Apfloat(i + 0.5, 10); a = new Apcomplex(real, imag); Apcomplex hurwitz = ApcomplexMath.zeta(a, new Apfloat(1, 10)); Apcomplex riemann = ApcomplexMath.zeta(a); //assertEquals(a + " algorithm precision", riemann.precision(), hurwitz.precision(), 1); assertEquals(a + " algorithm value", riemann, hurwitz, new Apfloat("5e" + (hurwitz.scale() - hurwitz.precision()))); } } try { ApcomplexMath.zeta(Apcomplex.ONE, new Apfloat(2.0)); fail("Zeta of one"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.zeta(new Apcomplex("2"), new Apfloat(0)); fail("Zeta of a 0"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.zeta(new Apcomplex("2"), new Apfloat("-1")); fail("Zeta of a -1"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.zeta(new Apcomplex("(0,1.00000)"), new Apfloat("0")); fail("Zeta of i,0"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.zeta(new Apcomplex("(0,1)"), new Apfloat("-1")); fail("Zeta of i,-1"); } catch (ArithmeticException ae) { // OK } try { ApcomplexMath.zeta(new Apcomplex("(0.5000,1.000e1000)"), new Apcomplex("(2.000,2.000)")); fail("Overflow"); } catch (OverflowException are) { // OK } try { ApcomplexMath.zeta(new Apcomplex("(0.5,1e100)"), new Apfloat(2.0)); fail("Loss of precision"); } catch (LossOfPrecisionException lope) { // OK } try { ApcomplexMath.zeta(new Apcomplex(Apfloat.ZERO, new Apfloat(4)), new Apfloat(2)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHypergeometric0F1() { Apcomplex a = ApcomplexMath.hypergeometric0F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)")); assertEquals("1+2i, 3+4i precision", 6, a.precision()); assertEquals("1+2i, 3+4i value", new Apcomplex("(6.24111,0.025037)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric0F1(new Apcomplex(new Apfloat(2, 12, 36), new Apfloat(3, 12, 36)), new Apcomplex(new Apfloat(4, 12, 36), new Apfloat(5, 12, 36))); assertEquals("2+3i, 4+5i radix 36 precision", 12, a.precision()); assertEquals("2+3i, 4+5i radix 36 radix", 36, a.radix()); assertEquals("2+3i, 4+5i radix 36 value", new Apcomplex(new Apfloat("4.st9rbd539a0", 12, 36), new Apfloat("0.5oqplurvcpbq", 12, 36)), a, new Apfloat("0.00000000000g", 1, 36)); // z = 0 a = ApcomplexMath.hypergeometric0F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("0")); assertEquals("1+2i, 0 precision", 6, a.precision()); assertEquals("1+2i, 0 value", new Apcomplex("1.00000"), a); // z very large a = ApcomplexMath.hypergeometric0F1(new Apcomplex("(1.00000000,2.00000000)"), new Apcomplex("(300000.000,400000.000)")); assertEquals("1+2i, 300000+400000i precision", 6, a.precision()); assertEquals("1+2i, 300000+400000i value", new Apcomplex("(-8.57044753692138e546,-2.99860981175263e546)"), a, new Apfloat("5e541")); a = ApcomplexMath.hypergeometric0F1(new Apcomplex("0.500000"), new Apcomplex("(300000,400000)")); // z very large and b-1/2 is nonpositive integer assertEquals("1+2i, 300000+400000i precision", 6, a.precision()); assertEquals("1+2i, 300000+400000i value", new Apcomplex("(-6.006090911265257e548,-9.26014030743587e548)"), a, new Apfloat("5e543")); a = ApcomplexMath.hypergeometric0F1(new Apcomplex(new Apfloat(2, 28, 2), new Apfloat(3, 28, 2)), new Apcomplex(new Apfloat(400000, 28, 2), new Apfloat(500000, 28, 2))); assertEquals("2+3i, 400000+500000i radix 2 precision", 17, a.precision()); assertEquals("2+3i, 400000+500000i radix 2 radix", 2, a.radix()); assertEquals("2+3i, 400000+500000i radix 2 value", new Apcomplex(new Apfloat("-1.010001101001111001111001110001111100000011001011000e2063", 17, 2), new Apfloat("1.101111010100101100101110011000110100010110010000100e2062", 17, 2)), a, new Apfloat("1e2047", 1, 2)); a = ApcomplexMath.hypergeometric0F1(new Apcomplex(new Apfloat(2, 27, 2), new Apfloat(3, 27, 2)), new Apcomplex(new Apfloat(-400000, 27, 2), new Apfloat(-500000, 27, 2))); assertEquals("2+3i, -400000-500000i radix 2 precision", 17, a.precision()); assertEquals("2+3i, -400000-500000i radix 2 radix", 2, a.radix()); assertEquals("2+3i, -400000-500000i radix 2 value", new Apcomplex(new Apfloat("1.011001011111100111e975", 17, 2), new Apfloat("-1.0111010000000101001e975", 17, 2)), a, new Apfloat("1e959", 1, 2)); // Non converging cases try { ApcomplexMath.hypergeometric0F1(new Apcomplex("-42.00000"), new Apcomplex("(2.00000,3.00000)")); fail("-42, 2+3i accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.hypergeometric0F1(new Apcomplex("0.00000"), new Apcomplex("0.00000")); fail("0, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.hypergeometric0F1(new Apcomplex(new Apfloat(3), new Apfloat(4)), new Apcomplex(new Apfloat(5), new Apfloat(6))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHypergeometric1F1() { Apcomplex a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 3+4i, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i value", new Apcomplex("(-8.28601,-9.84438)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric1F1(new Apcomplex(new Apfloat(2, 13, 35), new Apfloat(3, 13, 35)), new Apcomplex(new Apfloat(4, 13, 35), new Apfloat(5, 13, 35)), new Apcomplex(new Apfloat(6, 13, 35), new Apfloat(7, 13, 35))); assertEquals("2+3i, 4+5i, 6+7i radix 35 precision", 13, a.precision()); assertEquals("2+3i, 4+5i, 6+7i radix 35 radix", 35, a.radix()); assertEquals("2+3i, 4+5i, 6+7i radix 35 value", new Apcomplex(new Apfloat("i.hqetnbmwn38j", 13, 35), new Apfloat("-18.bk1aevn10od1", 13, 35)), a, new Apfloat("0.00000000000f", 1, 35)); // z = 0 a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("0")); assertEquals("1+2i, 3+4i, 0 precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 0 value", new Apcomplex("1.00000"), a); // z negative real part a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(-5.00000,-6.00000)")); assertEquals("1+2i, 3+4i, -5-6i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, -5-6i value", new Apcomplex("(-0.1555016,-0.2669975)"), a, new Apfloat("5e-6")); // z very large a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(1.0000000000,2.0000000000)"), new Apcomplex("(3.0000000000,4.0000000000)"), new Apcomplex("(500000.00000,600000.00000)")); assertEquals("1+2i, 3+4i, 500000+600000i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 500000+600000i value", new Apcomplex("(1.4855603302940e217136,1.1115533092224e217136)"), a, new Apfloat("5e217131")); a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(1.0000000000,2.0000000000)"), new Apcomplex("(3.0000000000,2.0000000000)"), new Apcomplex("(500000.00000,600000.00000)")); assertEquals("1+2i, 3+2i, 500000+600000i precision", 6, a.precision()); assertEquals("1+2i, 3+2i, 500000+600000i value", new Apcomplex("(1.8007619947265998435e217136,-1.337011417934778174e217135)"), a, new Apfloat("5e217131")); a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(3.0000000,2.0000000)"), new Apcomplex("(1.0000000,2.0000000)"), new Apcomplex("(500.00000,600.00000)")); // z very large and b - a nonpositive integer assertEquals("3+2i, 1+2i, 500+600i precision", 6, a.precision()); assertEquals("3+2i, 1+2i, 500+600i value", new Apcomplex("(-1.34020e222,2.51189e221)"), a, new Apfloat("5e217")); a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(3.0000000,2.0000000)"), new Apcomplex("(1.0000000,2.0000001)"), new Apcomplex("(500.00000,600.00000)")); // z very large and b - a nonpositive near-integer assertEquals("3+2i, 1+2.0000001i, 500+600i precision", 6, a.precision()); assertEquals("3+2i, 1+2.0000001i, 500+600i value", new Apcomplex("(-1.34020e222,2.51190e221)"), a, new Apfloat("5e217")); a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(1.0000000,2.0000000)"), new Apcomplex("(2.0000000,2.0000000)"), new Apcomplex("(500.00000,600.00000)")); // z very large and a - b + 1 nonpositive integer assertEquals("1+2i, 2+2i, 500+600i precision", 6, a.precision()); assertEquals("1+2i, 2+2i, 500+600i value", new Apcomplex("(-3.94194e214,-7.38748e213)"), a, new Apfloat("5e209")); a = ApcomplexMath.hypergeometric1F1(new Apcomplex("1.0000000"), new Apcomplex("(2.0000000,3.0000000)"), new Apcomplex("(500.00000,600.00000)")); // z very large and 1 - a nonpositive integer assertEquals("1, 2+3i, 500+600i precision", 6, a.precision()); assertEquals("1, 2+3i, 500+600i value", new Apcomplex("(-2.97414e214,-7.59031e213)"), a, new Apfloat("5e209")); // z pure imaginary a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(0,14.0000)")); assertEquals("1+2i, 3+4i, 14i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 14i value", new Apcomplex("(-0.0831361,-0.0482419)"), a, new Apfloat("5e-7")); // Polynomial cases a = ApcomplexMath.hypergeometric1F1(new Apcomplex("0"), new Apcomplex("1.0"), new Apcomplex("1.0")); assertEquals("0, 1, 1 precision", 2, a.precision()); assertEquals("0, 1, 1 value", new Apcomplex("1.0"), a); a = ApcomplexMath.hypergeometric1F1(new Apcomplex("-42.0000000"), new Apcomplex("(3.0000000,4.0000000)"), new Apcomplex("(5.0000000,6.0000000)")); assertEquals("-42, 3+4i, 5+6i precision", 2, a.precision()); assertEquals("-42, 3+4i, 5+6i value", new Apcomplex("(-56.0081,-31.8473)"), a, new Apfloat("5e0")); // Reduction to 0F0 a = ApcomplexMath.hypergeometric1F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 1+2i, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 1+2i, 5+6i value", new Apcomplex("(142.502,-41.4689)"), a, new Apfloat("5e-4")); // Non converging cases try { ApcomplexMath.hypergeometric1F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)")); fail("1+2i, 0, 5+6i accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.hypergeometric1F1(new Apcomplex("1.00000"), new Apcomplex("0"), new Apcomplex("0")); fail("1, 0, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is indeterminate } try { ApcomplexMath.hypergeometric1F1(new Apcomplex(new Apfloat(3), new Apfloat(4)), new Apcomplex(new Apfloat(5), new Apfloat(6)), new Apcomplex(new Apfloat(7), new Apfloat(8))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHypergeometric2F1() { // T0 Apcomplex a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("0.100000")); assertEquals("1, 2.2, 3.3, 0.1 precision", 6, a.precision()); assertEquals("1, 2.2, 3.3, 0.1 value", new Apcomplex("1.0720565"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("2.20000"), new Apcomplex("0.000000000100000"), new Apcomplex("0.100000")); assertEquals("1.1, 2.2, 0.0000000001, 0.1 precision", 6, a.precision()); assertEquals("1.1, 2.2, 0.0000000001, 0.1 value", new Apcomplex("3.44671e9"), a, new Apfloat("5e4")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("0.0000100000"), new Apcomplex("2.20000"), new Apcomplex("0.000000000100000"), new Apcomplex("0.100000")); assertEquals("0.00001, 2.2, 0.0000000001, 0.1 precision", 6, a.precision()); assertEquals("0.00001, 2.2, 0.0000000001, 0.1 value", new Apcomplex("26086.9"), a, new Apfloat("5e-1")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-1.00001"), new Apcomplex("2.20000"), new Apcomplex("0.000000000100000"), new Apcomplex("0.100000")); assertEquals("-1.00001, 2.2, 0.0000000001, 0.1 precision", 6, a.precision()); assertEquals("-1.00001, 2.2, 0.0000000001, 0.1 value", new Apcomplex("-2.20002e9"), a, new Apfloat("5e4")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-1.00001"), new Apcomplex("2.20000"), new Apcomplex("-3.00001"), new Apcomplex("0.100000")); assertEquals("-1.00001, 2.2, -3.00001, 0.1 precision", 6, a.precision()); assertEquals("-1.00001, 2.2, -3.00001, 0.1 value", new Apcomplex("1.07365"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-3.00001"), new Apcomplex("2.20000"), new Apcomplex("-1.00001"), new Apcomplex("0.100000")); assertEquals("-3.00001, 2.2, -1.00001, 0.1 precision", 5, a.precision()); assertEquals("-3.00001, 2.2, -1.00001, 0.1 value", new Apcomplex("18164.8"), a, new Apfloat("5e-1")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(0.100000,0.100000)")); assertEquals("1+2i, 3+4i, 5+6i, 0.1+0.1i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 0.1+0.1i value", new Apcomplex("(0.901921,0.175485)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1, 6, 7), new Apfloat(2, 6, 7)), new Apcomplex(new Apfloat(3, 6, 7), new Apfloat(4, 6, 7)), new Apcomplex(new Apfloat(5, 6, 7), new Apfloat(6, 6, 7)), new Apcomplex(new Apfloat("0.1", 6, 7), new Apfloat("0.1", 6, 7))); assertEquals("1+2i, 3+4i, 5+6i, 0.1+0.1i radix 7 precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 0.1+0.1i radix 7 radix", 7, a.radix()); assertEquals("1+2i, 3+4i, 5+6i, 0.1+0.1i radix 7 value", new Apcomplex(new Apfloat("0.5631550", 7, 7), new Apfloat("0.1452024", 7, 7)), a, new Apfloat("3e-6", 1, 7)); // T1 a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("-0.500000")); assertEquals("1, 2.2, 3.3, -0.5 precision", 6, a.precision()); assertEquals("1, 2.2, 3.3, -0.5 value", new Apcomplex("0.755818"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("4.30000"), new Apcomplex("5.30000"), new Apcomplex("3.30000"), new Apcomplex("-0.500000")); // c-a is integer and <= 0 and (c-b is not integer or c-b > 0 or c-a >= c-b) assertEquals("4.3, 5.3, 3.3, -0.5 precision", 6, a.precision()); assertEquals("4.3, 5.3, 3.3, -0.5 value", new Apcomplex("0.054179995"), a, new Apfloat("5e-7")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(0,1.00000)")); assertEquals("1+2i, 3+4i, 5+6i, i precision", 5, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, i value", new Apcomplex("(0.277926,0.0318455)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1, 6, 7), new Apfloat(2, 6, 7)), new Apcomplex(new Apfloat(3, 6, 7), new Apfloat(4, 6, 7)), new Apcomplex(new Apfloat(5, 6, 7), new Apfloat(6, 6, 7)), new Apcomplex(new Apfloat(0, 6, 7), new Apfloat(1, 6, 7))); assertEquals("1+2i, 3+4i, 5+6i, i radix 7 precision", 5, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, i radix 7 radix", 7, a.radix()); assertEquals("1+2i, 3+4i, 5+6i, i radix 7 value", new Apcomplex(new Apfloat("0.1642205", 7, 7), new Apfloat("0.0136314", 7, 7)), a, new Apfloat("3e-6", 1, 7)); // T2 a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); assertEquals("1, 2.2, 3.3, 5 precision", 5, a.precision()); assertEquals("1, 2.2, 3.3, 5 value", new Apcomplex("(-0.527130,-0.228019)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.000000"), new Apcomplex("1.000000"), new Apcomplex("3.300000"), new Apcomplex("5.000000")); // a = b assertEquals("1, 1, 3.3, 5 precision", 6, a.precision()); assertEquals("1, 1, 3.3, 5 value", new Apcomplex("(0.041932,-1.081246)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("1.00001"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); // a = b almost assertEquals("1, 1.00001, 3.3, 5 precision", 6, a.precision()); assertEquals("1, 1.00001, 3.3, 5 value", new Apcomplex("(0.041918,-1.081244)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("1.0000000001"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); // a = b very almost, and rounded is equal assertEquals("1, 1.0000000001, 3.3, 5 precision", 6, a.precision()); assertEquals("1, 1.0000000001, 3.3, 5 value", new Apcomplex("(0.041932,-1.081246)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.000000"), new Apcomplex("2.000000"), new Apcomplex("3.300000"), new Apcomplex("5.000000")); // a - b is some integer assertEquals("1, 2, 3.3, 5 precision", 6, a.precision()); assertEquals("1, 2, 3.3, 5 value", new Apcomplex("(-0.561372,-0.351405)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.00001"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); // a - b is almost integer assertEquals("1, 2.00001, 3.3, 5 precision", 6, a.precision()); assertEquals("1, 2.00001, 3.3, 5 value", new Apcomplex("(-0.561371,-0.351398)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("0.0000100000"), new Apcomplex("1.00000"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); // a - b is almost integer, a almost zero assertEquals("0.00001, 1, 3.3, 5 precision", 6, a.precision()); assertEquals("0.00001, 1, 3.3, 5 value", new Apcomplex("(1.00001,-0.0000188043)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("0.0000000000100000"), new Apcomplex("1.00000"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); // a - b is very almost integer, and rounded integer, a almost zero assertEquals("0.00000000001, 1, 3.3, 5 precision", 6, a.precision()); assertEquals("0.00000000001, 1, 3.3, 5 value", new Apcomplex("(1.00001,-0.0000188043)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("0.0000100000"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); // a - b is almost integer, b almost zero assertEquals("1, 0.00001, 3.3, 5 precision", 6, a.precision()); assertEquals("1, 0.00001, 3.3, 5 value", new Apcomplex("(1.00001,-0.0000188043)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("0.000000000100000"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); // a - b is very almost integer, and rounded integer, b almost zero assertEquals("1, 0.0000000001, 3.3, 5 precision", 5, a.precision()); assertEquals("1, 0.0000000001, 3.3, 5 value", new Apcomplex("(1.00001,-0.0000188043)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.000000000000000"), new Apcomplex("23456.000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("5.0000000000000000000")); // a - b is very large integer assertEquals("12345, 23456, 3.3, 5 precision", 20, a.precision()); assertEquals("12345, 23456, 3.3, 5 value", new Apcomplex("(5.2099702663731078027e-4961,7.1709088808283296782e-4961)"), a, new Apfloat("5e-4980")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.000000000000001"), new Apcomplex("23456.000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("5.0000000000000000000")); // a - b is very large almost integer assertEquals("12345.000000000000001, 23456, 3.3, 5 precision", 20, a.precision()); assertEquals("12345.000000000000001, 23456, 3.3, 5 value", new Apcomplex("(5.2099702663731332954e-4961,7.1709088808283173911e-4961)"), a, new Apfloat("5e-4980")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.000000000000000"), new Apcomplex("2.0000000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("5.0000000000000000000")); // a - b is very large integer but different scales assertEquals("12345, 2, 3.3, 5 precision", 16, a.precision()); assertEquals("12345, 2, 3.3, 5 value", new Apcomplex("7.849803042660721e-10"), a, new Apfloat("5e-25")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.000000000000000"), new Apcomplex("2.0000000000000000001"), new Apcomplex("3.3000000000000000000"), new Apcomplex("5.0000000000000000000")); // a - b is very large almost integer but different scales assertEquals("12345, 2.0000000000000000001, 3.3, 5 precision", 20, a.precision()); assertEquals("12345, 2.0000000000000000001, 3.3, 5 value", new Apcomplex("(7.8498030426607211909e-10,-2.4660883570949728023e-28)"), a, new Apfloat("5e-47")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("4.30000"), new Apcomplex("1.00000"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); // c - a is negative integer assertEquals("4.3, 1, 3.3, 5 precision", 5, a.precision()); assertEquals("4.3, 1, 3.3, 5 value", new Apcomplex("-0.155303"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("1.20000"), new Apcomplex("5.00000")); // c - b is negative integer assertEquals("1, 2.2, 1.2, 5 precision", 5, a.precision()); assertEquals("1, 2.2, 1.2, 5 value", new Apcomplex("0.0104167"), a, new Apfloat("5e-7")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(5.00000,5.00000)")); assertEquals("1+2i, 3+4i, 5+6i, 5+5i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 5+5i value", new Apcomplex("(0.00471924,-0.00269112)"), a, new Apfloat("5e-8")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1, 6, 7), new Apfloat(2, 6, 7)), new Apcomplex(new Apfloat(3, 6, 7), new Apfloat(4, 6, 7)), new Apcomplex(new Apfloat(5, 6, 7), new Apfloat(6, 6, 7)), new Apcomplex(new Apfloat(5, 6, 7), new Apfloat(5, 6, 7))); assertEquals("1+2i, 3+4i, 5+6i, 5+5i radix 7 precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 5+5i radix 7 radix", 7, a.radix()); assertEquals("1+2i, 3+4i, 5+6i, 5+5i radix 7 value", new Apcomplex(new Apfloat("0.001422133", 7, 7), new Apfloat("-0.0006314153", 7, 7)), a, new Apfloat("3e-8", 1, 7)); // T3 a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("-5.00000")); assertEquals("1, 2.2, 3.3, -5 precision", 5, a.precision()); assertEquals("1, 2.2, 3.3, -5 value", new Apcomplex("0.254205"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("1.00000"), new Apcomplex("3.30000"), new Apcomplex("-5.00000")); // a = b assertEquals("1, 1, 3.3, -5 precision", 5, a.precision()); assertEquals("1, 1, 3.3, -5 value", new Apcomplex("0.482978"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("1.00001"), new Apcomplex("3.30000"), new Apcomplex("-5.00000")); // a = b almost assertEquals("1, 1.00001, 3.3, -5 precision", 5, a.precision()); assertEquals("1, 1.00001, 3.3, -5 value", new Apcomplex("0.482975"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.00000"), new Apcomplex("3.30000"), new Apcomplex("-5.00000")); // a - b is some integer assertEquals("1, 2, 3.3, -5 precision", 6, a.precision()); assertEquals("1, 2, 3.3, -5 value", new Apcomplex("0.278688"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.00001"), new Apcomplex("3.30000"), new Apcomplex("-5.00000")); // a - b is almost integer assertEquals("1, 2.00001, 3.3, -5 precision", 6, a.precision()); assertEquals("1, 2.00001, 3.3, -5 value", new Apcomplex("0.278687"), a, new Apfloat("5e-6")); /* Extreme instability a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.000000000000000"), new Apcomplex("23456.000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("-5.0000000000000000000")); // a - b is very large integer assertEquals("12345, 23456, 3.3, -5 precision", 16, a.precision()); assertEquals("12345, 23456, 3.3, -5 value", new Apcomplex("2.113637302878074e-9709"), a, new Apfloat("5e-9724")); // Could not be verified a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.000000000000001"), new Apcomplex("23456.000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("-5.0000000000000000000")); // a - b is very large almost integer assertEquals("12345.000000000000001, 23456, 3.3, -5 precision", 16, a.precision()); assertEquals("12345.000000000000001, 23456, 3.3, -5 value", new Apcomplex("7.926014599973323e-9710"), a, new Apfloat("5e-9725")); // Could not be verified */ a = ApcomplexMath.hypergeometric2F1(new Apcomplex("123.00000000000000000"), new Apcomplex("234.00000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("-5.0000000000000000000")); // a - b is very large integer assertEquals("123, 234, 3.3, -5 precision", 20, a.precision()); assertEquals("123, 234, 3.3, -5 value", new Apcomplex("-1.6244271268683561270e-145"), a, new Apfloat("5e-164")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("123.00000000000000001"), new Apcomplex("234.00000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("-5.0000000000000000000")); // a - b is very large almost integer assertEquals("123.00000000000000001, 234, 3.3, -5 precision", 20, a.precision()); assertEquals("123.00000000000000001, 234, 3.3, -5 value", new Apcomplex("-1.6244271268683561596e-145"), a, new Apfloat("5e-164")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.000000000000000"), new Apcomplex("2.0000000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("-5.0000000000000000000")); // a - b is very large integer but different scales assertEquals("12345, 2, 3.3, -5 precision", 16, a.precision()); assertEquals("12345, 2, 3.3, -5 value", new Apcomplex("7.849650398485188e-10"), a, new Apfloat("5e-25")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.000000000000000"), new Apcomplex("2.0000000000000000001"), new Apcomplex("3.3000000000000000000"), new Apcomplex("-5.0000000000000000000")); // a - b is very large almost integer but different scales assertEquals("12345, 2.0000000000000000001, 3.3, -5 precision", 20, a.precision()); assertEquals("12345, 2.0000000000000000001, 3.3, -5 value", new Apcomplex("7.8496503984851883023e-10"), a, new Apfloat("5e-29")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(-5.00000,-5.00000)")); assertEquals("1+2i, 3+4i, 5+6i, -5-5i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, -5-5i value", new Apcomplex("(-0.633637,0.498949)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1, 6, 7), new Apfloat(2, 6, 7)), new Apcomplex(new Apfloat(3, 6, 7), new Apfloat(4, 6, 7)), new Apcomplex(new Apfloat(5, 6, 7), new Apfloat(6, 6, 7)), new Apcomplex(new Apfloat(-5, 6, 7), new Apfloat(-5, 6, 7))); assertEquals("1+2i, 3+4i, 5+6i, -5-5i radix 7 precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, -5-5i radix 7 radix", 7, a.radix()); assertEquals("1+2i, 3+4i, 5+6i, -5-5i radix 7 value", new Apcomplex(new Apfloat("-0.4302235", 7, 7), new Apfloat("0.33306556", 7, 7)), a, new Apfloat("3e-6", 1, 7)); // T4 a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); assertEquals("1, 2.2, 3.3, 0.9 precision", 4, a.precision()); assertEquals("1, 2.2, 3.3, 0.9 value", new Apcomplex("3.38469"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c = a + b assertEquals("1.1, 2.2, 3.3, 0.9 precision", 6, a.precision()); assertEquals("1.1, 2.2, 3.3, 0.9 value", new Apcomplex("3.89134"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("2.20001"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c = a + b almost assertEquals("1.1, 2.20001, 3.3, 0.9 precision", 6, a.precision()); assertEquals("1.1, 2.20001, 3.3, 0.9 value", new Apcomplex("3.89138"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("2.2000000001"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c = a + b very almost, and rounded is equal assertEquals("1.1, 2.2000000001, 3.3, 0.9 precision", 6, a.precision()); assertEquals("1.1, 2.2000000001, 3.3, 0.9 value", new Apcomplex("3.89134"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("3.20000"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c - a - b is some integer assertEquals("1.1, 3.2, 3.3, 0.9 precision", 6, a.precision()); assertEquals("1.1, 3.2, 3.3, 0.9 value", new Apcomplex("11.1353"), a, new Apfloat("5e-4")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("3.20001"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c - a - b is almost integer assertEquals("1.1, 3.20001, 3.3, 0.9 precision", 6, a.precision()); assertEquals("1.1, 3.20001, 3.3, 0.9 value", new Apcomplex("11.1354"), a, new Apfloat("5e-4")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("0.0000100000"), new Apcomplex("1.30000"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c - a - b is almost integer, a almost zero assertEquals("0.00001, 1.3, 3.3, 0.9 precision", 6, a.precision()); assertEquals("0.00001, 1.3, 3.3, 0.9 value", new Apcomplex("1.00001"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("0.0000000000100000"), new Apcomplex("1.30000"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c - a - b is very almost integer, and rounded integer, a almost zero assertEquals("0.00000000001, 1.3, 3.3, 0.9 precision", 6, a.precision()); assertEquals("0.00000000001, 1.3, 3.3, 0.9 value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.30000"), new Apcomplex("0.0000100000"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c - a - b is almost integer, b almost zero assertEquals("1.3, 0.00001, 3.3, 0.9 precision", 6, a.precision()); assertEquals("1.3, 0.00001, 3.3, 0.9 value", new Apcomplex("1.00001"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.30000"), new Apcomplex("0.000000000100000"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c - a - b is very almost integer, and rounded integer, b almost zero assertEquals("1.3, 0.0000000001, 3.3, 0.9 precision", 6, a.precision()); assertEquals("1.3, 0.0000000001, 3.3, 0.9 value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("-1.10000"), new Apcomplex("0.0000100000"), new Apcomplex("0.900000")); // c - a - b is almost integer, c almost zero assertEquals("1.1, -1.1, 0.00001, 0.9 precision", 6, a.precision()); assertEquals("1.1, -1.1, 0.00001, 0.9 value", new Apcomplex("-84213.6"), a, new Apfloat("5e-1")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("-1.10000"), new Apcomplex("0.000000000100000"), new Apcomplex("0.900000")); // c - a - b is very almost integer, and rounded integer, c almost zero assertEquals("1.1, -1.1, 0.0000000001, 0.9 precision", 5, a.precision()); assertEquals("1.1, -1.1, 0.0000000001, 0.9 value", new Apcomplex("-8.42142e9"), a, new Apfloat("5e4")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("0.0000000000100000"), new Apcomplex("-0.0000000000100000"), new Apcomplex("3.00000"), new Apcomplex("0.900000")); // c - a - b is very almost integer, and rounded integer, a and b both almost zero assertEquals("0.00000000001, -0.00000000001, 3.3, 0.9 precision", 6, a.precision()); assertEquals("0.00000000001, -0.00000000001, 3.3, 0.9 value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.100000000000000"), new Apcomplex("23456.200000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("0.90000000000000000000")); // c - a - b is very large integer assertEquals("12345.1, 23456.2, 3.3, 0.9 precision", 15, a.precision()); assertEquals("12345.1, 23456.2, 3.3, 0.9 value", new Apcomplex("2.15122213624475e45435"), a, new Apfloat("5e45421")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.100000000000000"), new Apcomplex("23456.200000000000000"), new Apcomplex("3.3000000000000000001"), new Apcomplex("0.90000000000000000000")); // c - a - b is very large almost integer assertEquals("12345.1, 23456.2, 3.3000000000000000001, 0.9 precision", 20, a.precision()); assertEquals("12345.1, 23456.2, 3.3000000000000000001, 0.9 value", new Apcomplex("2.1512221362447472151e45435"), a, new Apfloat("5e45416")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.100000000000000"), new Apcomplex("2.2000000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("0.90000000000000000000")); // c - a - b is very large integer but different scales assertEquals("12345.1, 2.2, 3.3, 0.9 precision", 16, a.precision()); assertEquals("12345.1, 2.2, 3.3, 0.9 value", new Apcomplex("8.6359944646509259e12339"), a, new Apfloat("5e12324")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.100000000000001"), new Apcomplex("2.2000000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("0.90000000000000000000")); // c - a - b is very large almost integer but different scales assertEquals("12345.1, 2.2, 3.3, 0.9 precision", 16, a.precision()); assertEquals("12345.1, 2.2, 3.3, 0.9 value", new Apcomplex("8.635994464650945e12339"), a, new Apfloat("5e12324")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("4.30000"), new Apcomplex("1.00000"), new Apcomplex("3.30000"), new Apcomplex("0.900000")); // c - a is negative integer assertEquals("4.3, 1, 3.3, 0.9 precision", 6, a.precision()); assertEquals("4.3, 1, 3.3, 0.9 value", new Apcomplex("37.2727"), a, new Apfloat("5e-4")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(0.800000,-0.200000)")); assertEquals("1+2i, 3+4i, 5+6i, 0.8-0.2i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 0.8-0.2i value", new Apcomplex("(1.33313,3.65726)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1, 11, 7), new Apfloat(2, 11, 7)), new Apcomplex(new Apfloat(3, 11, 7), new Apfloat(4, 11, 7)), new Apcomplex(new Apfloat(5, 11, 7), new Apfloat(6, 11, 7)), new Apcomplex(new Apfloat("0.6", 11, 7), new Apfloat("0.2", 11, 7))); assertEquals("1+2i, 3+4i, 5+6i, 0.6+0.2i radix 7 precision", 11, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 0.6+0.2i radix 7 radix", 7, a.radix()); assertEquals("1+2i, 3+4i, 5+6i, 0.6+0.2i radix 7 value", new Apcomplex(new Apfloat("-0.13460121301", 11, 7), new Apfloat("0.42563562524", 11, 7)), a, new Apfloat("3e-11", 1, 7)); // T5 a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("1.10000")); assertEquals("1, 2.2, 3.3, 1.1 precision", 4, a.precision()); assertEquals("1, 2.2, 3.3, 1.1 value", new Apcomplex("(2.412471,-5.13090)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("1.10000")); // c = a + b assertEquals("1.1, 2.2, 3.3, 1.1 precision", 5, a.precision()); assertEquals("1.1, 2.2, 3.3, 1.1 value", new Apcomplex("(1.76883,-6.38157)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("2.20001"), new Apcomplex("3.30000"), new Apcomplex("1.10000")); // c = a + b almost assertEquals("1.1, 2.20001, 3.3, 1.1 precision", 5, a.precision()); assertEquals("1.1, 2.20001, 3.3, 1.1 value", new Apcomplex("(1.76876,-6.38164)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.100000"), new Apcomplex("3.200000"), new Apcomplex("3.300000"), new Apcomplex("1.100000")); // c - a - b is some integer assertEquals("1.1, 3.2, 3.3, 1.1 precision", 6, a.precision()); assertEquals("1.1, 3.2, 3.3, 1.1 value", new Apcomplex("(-11.9673,0.68104)"), a, new Apfloat("5e-4")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.10000"), new Apcomplex("3.20001"), new Apcomplex("3.30000"), new Apcomplex("1.10000")); // c - a - b is almost integer assertEquals("1.1, 3.20001, 3.3, 1.1 precision", 6, a.precision()); assertEquals("1.1, 3.20001, 3.3, 1.1 value", new Apcomplex("(-11.9673,0.681342)"), a, new Apfloat("5e-4")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.100000000000000"), new Apcomplex("23456.200000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("1.1000000000000000000")); // c - a - b is very large integer assertEquals("12345.1, 23456.2, 3.3, 1.1 precision", 15, a.precision()); assertEquals("12345.1, 23456.2, 3.3, 1.1 value", new Apcomplex("1.56515678564160e46139"), a, new Apfloat("5e46124")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.100000000000000"), new Apcomplex("23456.200000000000000"), new Apcomplex("3.3000000000000000001"), new Apcomplex("1.1000000000000000000")); // c - a - b is very large almost integer assertEquals("12345.1, 23456.2, 3.3000000000000000001, 1.1 precision", 20, a.precision()); assertEquals("12345.1, 23456.2, 3.3000000000000000001, 1.1 value", new Apcomplex("(1.5651567856416026415e46139,4.9170850594878736391e46120)"), a, new Apfloat("5e46120")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.100000000000000"), new Apcomplex("2.2000000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("1.1000000000000000000")); // c - a - b is very large integer but different scales assertEquals("12345.1, 2.2, 3.3, 1.1 precision", 16, a.precision()); assertEquals("12345.1, 2.2, 3.3, 1.1 value", new Apcomplex("6.925586290556692e12339"), a, new Apfloat("5e12324")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("12345.100000000000001"), new Apcomplex("2.2000000000000000000"), new Apcomplex("3.3000000000000000000"), new Apcomplex("1.1000000000000000000")); // c - a - b is very large almost integer but different scales assertEquals("12345.1, 2.2, 3.3, 1.1 precision", 16, a.precision()); assertEquals("12345.1, 2.2, 3.3, 1.1 value", new Apcomplex("(6.92558629055670804609685408962018969630924e12339,-2.175737101221514124404378847e12325)"), a, new Apfloat("5e12310")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(2.20000,-1.10000)")); assertEquals("1+2i, 3+4i, 5+6i, 2.2-1.1i precision", 3, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 2.2-1.1i value", new Apcomplex("(5.94238,-45.6929)"), a, new Apfloat("5e-1")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1, 15, 7), new Apfloat(2, 15, 7)), new Apcomplex(new Apfloat(3, 15, 7), new Apfloat(4, 15, 7)), new Apcomplex(new Apfloat(5, 15, 7), new Apfloat(6, 15, 7)), new Apcomplex(new Apfloat("2.2", 15, 7), new Apfloat("1.1", 15, 7))); assertEquals("1+2i, 3+4i, 5+6i, 2.2+1.1i radix 7 precision", 15, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 2.2+1.1i radix 7 radix", 7, a.radix()); assertEquals("1+2i, 3+4i, 5+6i, 2.2+1.1i radix 7 value", new Apcomplex(new Apfloat("-0.00212125415466401", 15, 7), new Apfloat("0.01231461626540454", 15, 7)), a, new Apfloat("3e-16", 1, 7)); // AA a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("(0.500000,0.866025)")); assertEquals("1, 2.2, 3.3, 0.500000+0.866025i precision", 6, a.precision()); assertEquals("1, 2.2, 3.3, 0.500000+0.866025i value", new Apcomplex("(0.817034,0.688205)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("-2.00001"), new Apcomplex("(0.500000,0.900000)")); // c close to even negative integer assertEquals("1, 2.2, -2.00001, 0.500000+0.9i precision", 6, a.precision()); assertEquals("1, 2.2, -2.00001, 0.500000+0.9i value", new Apcomplex("(1058370,-895866)"), a, new Apfloat("5e1")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("(0,0.0000100000)"), new Apcomplex("(0.500000,0.900000)")); // c small and pure imaginary assertEquals("1, 2.2, 0.00001i, 0.500000+0.9i precision", 6, a.precision()); assertEquals("1, 2.2, 0.00001i, 0.500000+0.9i value", new Apcomplex("(-200190,50025)"), a, new Apfloat("5e0")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(0.600000,-0.700000)")); assertEquals("1+2i, 3+4i, 5+6i, 0.6-0.7i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 0.6-0.7i value", new Apcomplex("(4.583319,-0.542426)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1, 17, 7), new Apfloat(2, 17, 7)), new Apcomplex(new Apfloat(3, 17, 7), new Apfloat(4, 17, 7)), new Apcomplex(new Apfloat(5, 17, 7), new Apfloat(6, 17, 7)), new Apcomplex(new Apfloat("0.3", 17, 7), new Apfloat("0.6", 17, 7))); assertEquals("1+2i, 3+4i, 5+6i, 0.3+0.6i radix 7 precision", 17, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 0.3+0.6i radix 7 radix", 7, a.radix()); assertEquals("1+2i, 3+4i, 5+6i, 0.3+0.6i radix 7 value", new Apcomplex(new Apfloat("0.140136606425645266", 17, 7), new Apfloat("0.11630632042113610", 17, 7)), a, new Apfloat("3e-17", 1, 7)); // z = 0 a = ApcomplexMath.hypergeometric2F1(new Apcomplex("(2,3)"), new Apcomplex("(4,5)"), new Apcomplex("(6,7)"), new Apcomplex("0")); assertEquals("(2,3), (4,5), (6,7), 0 precision", 1, a.precision()); assertEquals("(2,3), (4,5), (6,7), 0 value", new Apcomplex("1"), a); a = ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1, 15, 7), new Apfloat(2, 15, 7)), new Apcomplex(new Apfloat(3, 15, 7), new Apfloat(4, 15, 7)), new Apcomplex(new Apfloat(5, 15, 7), new Apfloat(6, 15, 7)), new Apcomplex(new Apfloat(0, 15, 7))); assertEquals("1+2i, 3+4i, 5+6i, 0 radix 7 precision", 15, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 0 radix 7 radix", 7, a.radix()); assertEquals("1+2i, 3+4i, 5+6i, 0 radix 7 value", new Apcomplex(new Apfloat("1", 15, 7)), a); // z = 1 a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-1.10000"), new Apcomplex("4.40000"), new Apcomplex("3.40000"), new Apcomplex("1.00000")); // re(a + b - c) < 0 assertEquals("-1.1, 4.4, 3.4, 1 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1.1, 4.4, 3.4, 1 value", new Apcomplex("0"), a); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("(-1.10000)"), new Apcomplex("(4.40000)"), new Apcomplex("(3.40001)"), new Apcomplex("1.00000")); // re(a + b - c) < 0 assertEquals("-1.1, 4.4, 3.40001, 1 precision", 6, a.precision()); assertEquals("-1.1, 4.4, 3.40001, 1 value", new Apcomplex("-0.0000243804"), a, new Apfloat("5e-10")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1, 15, 7), new Apfloat(2, 15, 7)), new Apcomplex(new Apfloat(3, 15, 7), new Apfloat(4, 15, 7)), new Apcomplex(new Apfloat(5, 15, 7), new Apfloat(6, 15, 7)), new Apcomplex(new Apfloat(1, 15, 7))); assertEquals("1+2i, 3+4i, 5+6i, 1 radix 7 precision", 15, a.precision()); assertEquals("1+2i, 3+4i, 5+6i, 1 radix 7 radix", 7, a.radix()); assertEquals("1+2i, 3+4i, 5+6i, 1 radix 7 value", new Apcomplex(new Apfloat("-3.02122533664322", 15, 7), new Apfloat("-0.450501042623411", 15, 7)), a, new Apfloat("3e-15", 1, 7)); // Polynomial cases a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-1.00000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("0.100000")); assertEquals("-1, 2.2, 3.3, 0.1 precision", 6, a.precision()); assertEquals("-1, 2.2, 3.3, 0.1 value", new Apcomplex("0.933333"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-1.00000"), new Apcomplex("2.20000"), new Apcomplex("-2.00000"), new Apcomplex("0.100000")); assertEquals("-1, 2.2, -2, 0.1 precision", 6, a.precision()); assertEquals("-1, 2.2, -2, 0.1 value", new Apcomplex("1.110006"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-1.00000"), new Apcomplex("2.20000"), new Apcomplex("-2.00000"), new Apcomplex("1.10000")); assertEquals("-1, 2.2, -2, 1.1 precision", 6, a.precision()); assertEquals("-1, 2.2, -2, 1.1 value", new Apcomplex("2.21000"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-123456"), new Apcomplex("-234567"), new Apcomplex("3.30000"), new Apcomplex("1.23456")); assertEquals("-123456, -234567, 3.3, 1.23456 precision", 6, a.precision()); assertEquals("-123456, -234567, 3.3, 1.23456 value", new Apcomplex("6.43901e107725"), a, new Apfloat("5e107720")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-2.00000"), new Apcomplex("2.20000"), new Apcomplex("-2.00000"), new Apcomplex("5.00000")); assertEquals("-2, 2.2, -2, 5 precision", 6, a.precision()); assertEquals("-2, 2.2, -2, 5 value", new Apcomplex("100.000"), a, new Apfloat("5e-3")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-1.00000"), new Apcomplex("2.20000"), new Apcomplex("-2.00000"), new Apcomplex("5.00000")); assertEquals("-1, 2.2, -2, 5 precision", 6, a.precision()); assertEquals("-1, 2.2, -2, 5 value", new Apcomplex("6.50000"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("-3.00000"), new Apcomplex("-1.00000"), new Apcomplex("-2.00000"), new Apcomplex("1.00000")); assertEquals("-3, -1, -2, 1 precision", 6, a.precision()); assertEquals("-3, -1, -2, 1 value", new Apfloat("-0.500000"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apfloat(-1, 15, 7), new Apcomplex(new Apfloat(3, 15, 7), new Apfloat(4, 15, 7)), new Apcomplex(new Apfloat(5, 15, 7), new Apfloat(6, 15, 7)), new Apcomplex(new Apfloat(1, 15, 7), new Apfloat(2, 15, 7))); assertEquals("-1, 3+4i, 5+6i, 1+2i radix 7 precision", 15, a.precision()); assertEquals("-1, 3+4i, 5+6i, 1+2i radix 7 radix", 7, a.radix()); assertEquals("-1, 3+4i, 5+6i, 1+2i radix 7 value", new Apcomplex(new Apfloat("0.266124322031330", 15, 7), new Apfloat("-1.211556525164406", 15, 7)), a, new Apfloat("3e-15", 1, 7)); // Reduction to 1F0 a = ApcomplexMath.hypergeometric2F1(new Apcomplex("3.30000"), new Apcomplex("1.00000"), new Apcomplex("3.30000"), new Apcomplex("5.00000")); // a = c assertEquals("3.3, 1, 3.3, 5 precision", 6, a.precision()); assertEquals("3.3, 1, 3.3, 5 value", new Apcomplex("-0.250000"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("2.20000"), new Apcomplex("5.00000")); // b = c assertEquals("1, 2.2, 2.2, 5 precision", 6, a.precision()); assertEquals("1, 2.2, 2.2, 5 value", new Apcomplex("-0.250000"), a, new Apfloat("5e-6")); // Non converging cases try { ApcomplexMath.hypergeometric2F1(new Apcomplex("-3.00000"), new Apcomplex("2.20000"), new Apcomplex("-2.00000"), new Apcomplex("5.00000")); fail("-3, 2.2, -2, 5 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.hypergeometric2F1(new Apcomplex("(-1.10000)"), new Apcomplex("(4.40000)"), new Apcomplex("(3.30000)"), new Apcomplex("1.00000")); // re(a + b - c) = 0 fail("-1.1, 4.4, 3.3, 1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.hypergeometric2F1(new Apcomplex("(-1.10000)"), new Apcomplex("(4.40001)"), new Apcomplex("(3.30000)"), new Apcomplex("1.00000")); // re(a + b - c) > 0 fail("-1.1, 4.40001, 3.3, 1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.hypergeometric2F1(new Apcomplex("(1.00000)"), new Apcomplex("(2.00000)"), new Apcomplex("(1.00000)"), new Apcomplex("1.00000")); // re(a + b - c) > 0 and reduction to 1F0 fail("1, 2, 1, 1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.hypergeometric2F1(new Apcomplex("1.00000"), new Apcomplex("2.00000"), new Apcomplex("0"), new Apcomplex("0")); fail("1, 2, 0, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(-3)), new Apcomplex(new Apfloat(-2)), new Apcomplex(new Apfloat(-1)), new Apcomplex(new Apfloat(1))); fail("-3, -1, -2, 1 accepted"); } catch (ArithmeticException ae) { // OK, division by zero } try { ApcomplexMath.hypergeometric2F1(new Apcomplex(new Apfloat(1), new Apfloat(2)), new Apcomplex(new Apfloat(3), new Apfloat(4)), new Apcomplex(new Apfloat(5), new Apfloat(6)), new Apcomplex(new Apfloat(7), new Apfloat(8))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHypergeometric0F1Regularized() { Apcomplex a = ApcomplexMath.hypergeometric0F1Regularized(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)")); assertEquals("1+2i, 3+4i precision", 6, a.precision()); assertEquals("1+2i, 3+4i value", new Apcomplex("(40.4203,-5.10508)"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometric0F1Regularized(new Apcomplex("(-1.00000,-2.00000)"), new Apcomplex("(3.00000,4.00000)")); assertEquals("-1-2i, 3+4i precision", 6, a.precision()); assertEquals("-1-2i, 3+4i value", new Apcomplex("(-16.3946,-1.65106)"), a, new Apfloat("5e-4")); a = ApcomplexMath.hypergeometric0F1Regularized(new Apcomplex("-2.000000"), new Apcomplex("(3.000000,4.000000)")); assertEquals("-2, 3+4i precision", 6, a.precision()); assertEquals("-2, 3+4i value", new Apcomplex("(-39.0633,-21.8202)"), a, new Apfloat("5e-4")); a = ApcomplexMath.hypergeometric0F1Regularized(new Apcomplex("-0.9999999999998"), new Apcomplex("(3.000000000000,4.000000000000)")); assertEquals("-0.9999999999998, 3+4i precision", 12, a.precision()); assertEquals("-0.9999999999998, 3+4i value", new Apcomplex("(-33.49668360386,7.4495303552)"), a, new Apfloat("5e-11")); } public static void testHypergeometric1F1Regularized() { Apcomplex a = ApcomplexMath.hypergeometric1F1Regularized(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 3+4i, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i value", new Apcomplex("(55.548,-49.704)"), a, new Apfloat("5e-3")); a = ApcomplexMath.hypergeometric1F1Regularized(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("-3.000000"), new Apcomplex("(5.000000,6.000000)")); assertEquals("1+2i, -3, 5+6i precision", 6, a.precision()); assertEquals("1+2i, -3, 5+6i value", new Apcomplex("(-153449,880022)"), a, new Apfloat("5e1")); } public static void testHypergeometric2F1Regularized() { Apcomplex a = ApcomplexMath.hypergeometric2F1Regularized(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("3.30000"), new Apcomplex("0.100000")); assertEquals("1, 2.2, 3.3, 0.1 precision", 6, a.precision()); assertEquals("1, 2.2, 3.3, 0.1 value", new Apcomplex("0.399509"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1Regularized(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("-3.00000"), new Apcomplex("0.100000")); assertEquals("1, 2.2, -3, 0.1 precision", 6, a.precision()); assertEquals("1, 2.2, -3, 0.1 value", new Apcomplex("0.0295476"), a, new Apfloat("5e-7")); a = ApcomplexMath.hypergeometric2F1Regularized(new Apcomplex("1.00000"), new Apcomplex("2.20000"), new Apcomplex("0"), new Apcomplex("0.100000")); assertEquals("1, 2.2, 0, 0.1 precision", 6, a.precision()); assertEquals("1, 2.2, 0, 0.1 value", new Apcomplex("0.308210"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometric2F1Regularized(new Apcomplex("1.00000"), new Apcomplex("2.00000"), new Apcomplex("-3.00000"), new Apcomplex("0.100000")); assertEquals("1, 2, -3, 0.1 precision", 6, a.precision()); assertEquals("1, 2, -3, 0.1 value", new Apcomplex("0.0225801"), a, new Apfloat("5e-7")); a = ApcomplexMath.hypergeometric2F1Regularized(new Apcomplex("1.00000"), new Apcomplex("2.00000"), new Apcomplex("-3.00000"), new Apcomplex("7.000000")); assertEquals("1, 2, -3, 7 precision", 5, a.precision()); assertEquals("1, 2, -3, 7 value", new Apcomplex("6.17541"), a, new Apfloat("5e-4")); a = ApcomplexMath.hypergeometric2F1Regularized(new Apcomplex("(1.1000000,2.2000000)"), new Apcomplex("(3.4000000,5.6000000)"), new Apcomplex("-7.0000000"), new Apcomplex("(-1.2000000,3.4000000)")); assertEquals("1.1+2.2i, 3.4+5.6i, -7, -1.2+3.4i precision", 6, a.precision()); assertEquals("1.1+2.2i, 3.4+5.6i, -7, -1.2+3.4i value", new Apcomplex("(-8761.55,-55520.5)"), a, new Apfloat("5e-1")); } public static void testHypergeometricU() { Apcomplex a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 3+4i, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 5+6i value", new Apcomplex("(-0.260510,0.792445)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometricU(new Apcomplex(new Apfloat(2, 13, 35), new Apfloat(3, 13, 35)), new Apcomplex(new Apfloat(4, 13, 35), new Apfloat(5, 13, 35)), new Apcomplex(new Apfloat(6, 13, 35), new Apfloat(7, 13, 35))); assertEquals("2+3i, 4+5i, 6+7i radix 35 precision", 13, a.precision()); assertEquals("2+3i, 4+5i, 6+7i radix 35 radix", 35, a.radix()); assertEquals("2+3i, 4+5i, 6+7i radix 35 value", new Apcomplex(new Apfloat("0.1ectwfmqvde25", 13, 35), new Apfloat("-0.6t1hr8o6ew9jd", 13, 35)), a, new Apfloat("0.000000000000f", 1, 35)); // z = 0 a = ApcomplexMath.hypergeometricU(new Apcomplex("1.00000"), new Apcomplex("0"), new Apcomplex("0")); assertEquals("1, 0, 0 precision", 6, a.precision()); assertEquals("1, 0, 0 value", new Apcomplex("1.00000"), a); a = ApcomplexMath.hypergeometricU(new Apcomplex("2.00000"), new Apcomplex("-3.00000"), new Apcomplex("0")); assertEquals("2, -3, 0 precision", 6, a.precision()); assertEquals("2, -3, 0 value", new Apcomplex("0.0500000"), a); // z negative real part a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(-5.00000,-6.00000)")); assertEquals("1+2i, 3+4i, -5-6i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, -5-6i value", new Apcomplex("(-0.000890904,-0.000719161)"), a, new Apfloat("6e-9")); // z very large a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(500000.0,600000.0)")); assertEquals("1+2i, 3+4i, 500000+600000i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 500000+600000i value", new Apcomplex("(-7.13250e-6,-1.90930e-6)"), a, new Apfloat("5e-11")); a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(3.000000,2.000000)"), new Apcomplex("(500000.0,600000.0)")); assertEquals("1+2i, 3+2i, 500000+600000i precision", 6, a.precision()); assertEquals("1+2i, 3+2i, 500000+600000i value", new Apcomplex("(-7.13252e-6,-1.90926e-6)"), a, new Apfloat("5e-11")); a = ApcomplexMath.hypergeometricU(new Apcomplex("(3.000000,2.000000)"), new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(500.0000,600.0000)")); // z very large and b - a nonpositive integer assertEquals("3+2i, 1+2i, 500+600i precision", 6, a.precision()); assertEquals("3+2i, 1+2i, 500+600i value", new Apcomplex("(-1.16097e-8,2.81084e-9)"), a, new Apfloat("5e-13")); // z pure imaginary a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(0,14.0000)")); assertEquals("1+2i, 3+4i, 14i precision", 6, a.precision()); assertEquals("1+2i, 3+4i, 14i value", new Apcomplex("(2.04875,-0.72946)"), a, new Apfloat("5e-5")); // Polynomial cases a = ApcomplexMath.hypergeometricU(new Apcomplex("0"), new Apcomplex("1.0"), new Apcomplex("1.0")); assertEquals("0, 1, 1 precision", 2, a.precision()); assertEquals("0, 1, 1 value", new Apcomplex("1.0"), a, new Apfloat("5e-1")); a = ApcomplexMath.hypergeometricU(new Apcomplex("-1.00000"), new Apcomplex("1.50000"), new Apcomplex("0")); assertEquals("-1, 1.5, 0 precision", 6, a.precision()); assertEquals("-1, 1.5, 0 value", new Apcomplex("-1.50000"), a, new Apfloat("5e-5")); a = ApcomplexMath.hypergeometricU(new Apcomplex("-42.00000"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-42, 3+4i, 5+6i precision", 6, a.precision()); assertEquals("-42, 3+4i, 5+6i value", new Apcomplex("(2.80183e55,8.28632e56)"), a, new Apfloat("5e51")); a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(3.000000,2.000000)"), new Apcomplex("(500.0000,600.0000)")); // z very large and a - b + 1 nonpositive integer assertEquals("1+2i, 3+2i, 500+600i precision", 6, a.precision()); assertEquals("1+2i, 3+2i, 500+600i value", new Apcomplex("(-0.000439931,-0.00739112)"), a, new Apfloat("5e-8")); // Reduction to 0F0 a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 1+2i, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 1+2i, 5+6i value", new Apcomplex("(0.194432,0.553089)"), a, new Apfloat("5e-6")); // b - a + 1 integer a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(2.00000,2.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 2+2i, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 2+2i, 5+6i value", new Apcomplex("(0.200175,0.710710)"), a, new Apfloat("5e-6")); // b - a + 1 near-integer a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(1.00000,2.00001)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 1+2.00001i, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 1+2.00001i, 5+6i value", new Apcomplex("(0.194431,0.553089)"), a, new Apfloat("5e-6")); // b integer a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 0, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 0, 5+6i value", new Apcomplex("(0.388039,0.370539)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("1.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 1, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 1, 5+6i value", new Apcomplex("(0.451430,0.471959)"), a, new Apfloat("5e-6")); a = ApcomplexMath.hypergeometricU(new Apcomplex("1.00000"), new Apcomplex("-2.00000"), new Apcomplex("-0.100000")); assertEquals("1, -2, -0.1 precision", 6, a.precision()); assertEquals("1, -2, -0.1 value", new Apcomplex("(0.351911,-0.000473772)"), a, new Apfloat("5e-6")); // b near-integer a = ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("0.999999"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1+2i, 0, 5+6i precision", 6, a.precision()); assertEquals("1+2i, 0, 5+6i value", new Apcomplex("(0.451430,0.471959)"), a, new Apfloat("5e-6")); // Non converging cases try { ApcomplexMath.hypergeometricU(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("0")); fail("z=0 accepted"); } catch (ArithmeticException ae) { // OK, result is indeterminate } try { ApcomplexMath.hypergeometricU(new Apcomplex(new Apfloat(3), new Apfloat(4)), new Apcomplex(new Apfloat(5), new Apfloat(6)), new Apcomplex(new Apfloat(7), new Apfloat(8))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testErf() { Apcomplex a = ApcomplexMath.erf(new Apcomplex("(3.000000,4.000000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(-120.187,-27.7503)"), a, new Apfloat("5e-3")); a = ApcomplexMath.erf(new Apcomplex("(3.000000,-4.000000)")); assertEquals("3 - 4i precision", 6, a.precision()); assertEquals("3 - 4i value", new Apcomplex("(-120.187,27.7503)"), a, new Apfloat("5e-3")); a = ApcomplexMath.erf(new Apcomplex("(-3.000000,4.000000)")); assertEquals("-3 + 4i precision", 6, a.precision()); assertEquals("-3 + 4i value", new Apcomplex("(120.187,-27.7503)"), a, new Apfloat("5e-3")); a = ApcomplexMath.erf(new Apcomplex("(-3.000000,-4.000000)")); assertEquals("-3 - 4i precision", 6, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(120.187,27.7503)"), a, new Apfloat("5e-3")); a = ApcomplexMath.erf(new Apcomplex("15").precision(40)); assertEquals("15 precision", 137, a.precision()); assertEquals("15 value", new Apcomplex("0.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999992787005827548793333434933441307072890066"), a, new Apfloat("5e-137")); a = ApcomplexMath.erf(new Apcomplex("-15").precision(40)); assertEquals("-15 precision", 137, a.precision()); assertEquals("-15 value", new Apcomplex("-0.9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999992787005827548793333434933441307072890066"), a, new Apfloat("5e-137")); a = ApcomplexMath.erf(new Apcomplex("(0,15)").precision(40)); assertEquals("15i precision", 38, a.precision()); assertEquals("15i value", new Apcomplex("(0,1.96138456386738060348167059391082112595e96)"), a, new Apfloat("5e59")); a = ApcomplexMath.erf(new Apcomplex("(0,-15)").precision(40)); assertEquals("-15i precision", 38, a.precision()); assertEquals("-15i value", new Apcomplex("(0,-1.96138456386738060348167059391082112595e96)"), a, new Apfloat("5e59")); a = ApcomplexMath.erf(new Apcomplex("(0.100000,0.150000)")); assertEquals("0.1+0.15i precision", 6, a.precision()); assertEquals("0.1+0.15i value", new Apcomplex("(0.115005,0.168813)"), a, new Apfloat("5e-6")); a = ApcomplexMath.erf(new Apcomplex("(0,0.150000)")); assertEquals("0.15i precision", 6, a.precision()); assertEquals("0.15i value", new Apcomplex("(0,0.170535)"), a, new Apfloat("5e-6")); a = ApcomplexMath.erf(new Apcomplex("(0.500000,0.750000)")); assertEquals("0.5 + 0.75i precision", 6, a.precision()); assertEquals("0.5 + 0.75i value", new Apcomplex("(0.835592,0.721707)"), a, new Apfloat("5e-6")); a = ApcomplexMath.erf(new Apcomplex(new Apfloat(3, 17, 2), new Apfloat(4, 17, 2))); assertEquals("3 + 4i radix 2 precision", 13, a.precision()); assertEquals("3 + 4i radix 2 value", new Apcomplex(new Apfloat("-1111000.00101111111", 13, 2), new Apfloat("-11011.110000000001011", 13, 2)), a, new Apfloat("1e-6", 1, 2)); a = ApcomplexMath.erf(new Apcomplex(new Apfloat("0.1", 17, 2), new Apfloat("0.11", 17, 2))); assertEquals("0.1 + 0.11i radix 2 precision", 17, a.precision()); assertEquals("0.1 + 0.11i radix 2 value", new Apcomplex(new Apfloat("0.1101010111101001011", 17, 2), new Apfloat("0.101110001100000111", 17, 2)), a, new Apfloat("1e-17", 1, 2)); a = ApcomplexMath.erf(new Apcomplex("-10007.000000000000000")); assertEquals("-10007 precision", 43490286, a.precision()); assertEquals("-10007 value", new Apint(-1).subtract(new Apcomplex("-1.12953556651e-43490275")), a, new Apfloat("5e-43490264")); a = ApcomplexMath.erfFixedPrecision(new Apcomplex("-10007.000000000000000")); assertEquals("-10007 fixed precision", 20, a.precision()); assertEquals("-10007 fixed value", new Apcomplex("-0.99999999999999999999"), a, new Apfloat("5e-20")); a = ApcomplexMath.erf(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); a = ApcomplexMath.erfFixedPrecision(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); } public static void testErfc() { Apcomplex a = ApcomplexMath.erfc(new Apcomplex("(3.000000,4.000000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(121.187,27.7503)"), a, new Apfloat("5e-3")); a = ApcomplexMath.erfc(new Apcomplex("(3.000000,-4.000000)")); assertEquals("3 - 4i precision", 6, a.precision()); assertEquals("3 - 4i value", new Apcomplex("(121.187,-27.7503)"), a, new Apfloat("5e-3")); a = ApcomplexMath.erfc(new Apcomplex("(-3.000000,4.000000)")); assertEquals("-3 + 4i precision", 6, a.precision()); assertEquals("-3 + 4i value", new Apcomplex("(-119.187,27.7503)"), a, new Apfloat("5e-3")); a = ApcomplexMath.erfc(new Apcomplex("(-3.000000,-4.000000)")); assertEquals("-3 - 4i precision", 6, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(-119.187,-27.7503)"), a, new Apfloat("5e-3")); a = ApcomplexMath.erfc(new Apcomplex("15").precision(40)); assertEquals("15 precision", 38, a.precision()); assertEquals("15 value", new Apcomplex("7.21299417245120666656506655869292710993e-100"), a, new Apfloat("5e-137")); a = ApcomplexMath.erfc(new Apcomplex("-15").precision(40)); assertEquals("-15 precision", 138, a.precision()); assertEquals("-15 value", new Apcomplex("1.999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999278700582754879333343493344130707289007"), a, new Apfloat("5e-137")); a = ApcomplexMath.erfc(new Apcomplex("(0,15)").precision(40)); assertEquals("15i precision", 38, a.precision()); assertEquals("15i value", new Apcomplex("(0,-1.96138456386738060348167059391082112595e96)"), a, new Apfloat("5e59")); a = ApcomplexMath.erfc(new Apcomplex("(0,-15)").precision(40)); assertEquals("-15i precision", 38, a.precision()); assertEquals("-15i value", new Apcomplex("(0,1.96138456386738060348167059391082112595e96)"), a, new Apfloat("5e59")); a = ApcomplexMath.erfc(new Apcomplex("(0.300000,0.400000)")); assertEquals("0.3 + 0.4i precision", 6, a.precision()); assertEquals("0.3 + 0.4i value", new Apcomplex("(0.617957,-0.431252)"), a, new Apfloat("5e-6")); a = ApcomplexMath.erfc(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apint(1), a); a = ApcomplexMath.erfcFixedPrecision(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apint(1), a); a = ApcomplexMath.erfc(new Apcomplex(new Apfloat(3, 17, 2), new Apfloat(4, 17, 2))); assertEquals("3 + 4i radix 2 precision", 13, a.precision()); assertEquals("3 + 4i radix 2 value", new Apcomplex(new Apfloat("1111001.00101111111", 13, 2), new Apfloat("11011.110000000001011", 13, 2)), a, new Apfloat("1e-6", 1, 2)); } public static void testErfi() { Apcomplex a = ApcomplexMath.erfi(new Apcomplex("(3.000000,4.000000)")); assertEquals("3 + 4i precision", 10, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(-0.0000497203,0.9999106617)"), a, new Apfloat("5e-10")); a = ApcomplexMath.erfi(new Apcomplex("15").precision(8)); assertEquals("15 precision", 6, a.precision()); assertEquals("15 value", new Apcomplex("1.96138e96"), a, new Apfloat("5e91")); a = ApcomplexMath.erfi(new Apcomplex("-15").precision(8)); assertEquals("-15 precision", 6, a.precision()); assertEquals("-15 value", new Apcomplex("-1.96138e96"), a, new Apfloat("5e91")); a = ApcomplexMath.erfi(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); a = ApcomplexMath.erfi(new Apcomplex(new Apfloat(3, 17, 2), new Apfloat(4, 17, 2))); assertEquals("3 + 4i radix 2 precision", 26, a.precision()); assertEquals("3 + 4i radix 2 value", new Apcomplex(new Apfloat("-0.00000000000000110100001000101011", 26, 2), new Apfloat("0.111111111111101000100101001", 26, 2)), a, new Apfloat("1e-26", 1, 2)); } public static void testFresnelS() { Apcomplex a = ApcomplexMath.fresnelS(new Apcomplex("(3.000000,4.000000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(6.09755e14,4.53702e14)"), a, new Apfloat("5e9")); a = ApcomplexMath.fresnelS(new Apcomplex("(-3.000000,-4.000000)")); assertEquals("-3 - 4i precision", 6, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(-6.09755e14,-4.53702e14)"), a, new Apfloat("5e9")); a = ApcomplexMath.fresnelS(new Apcomplex("(2.000000000000000,1.000000000000000)")); assertEquals("2 + 1i precision", 16, a.precision()); assertEquals("2 + 1i value", new Apcomplex("(-15.5877511044046,-36.7254648839914)"), a, new Apfloat("5e-14")); a = ApcomplexMath.fresnelS(new Apcomplex("(10000.0000000000000000000000000,1.00000000000000000000000000000)")); assertEquals("10000 + i precision", 22, a.precision()); assertEquals("10000 + i value", new Apcomplex("(-9.23304009409117412e13634,-9.233334000234768004283e13638)"), a, new Apfloat("5e13617")); a = ApcomplexMath.fresnelS(new Apcomplex("(3.00000e-3,4.00000e-3)")); assertEquals("3e-3 + 4e-3i precision", 6, a.precision()); assertEquals("3e-3 + 4e-3i value", new Apcomplex("(-6.12611e-8,2.30383e-8)"), a, new Apfloat("5e-13")); a = ApcomplexMath.fresnelS(new Apcomplex("(0,4.00000)")); assertEquals("4i precision", 6, a.precision()); assertEquals("4i value", new Apcomplex("(0,-0.420516)"), a, new Apfloat("5e-6")); a = ApcomplexMath.fresnelS(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); a = ApcomplexMath.fresnelS(new Apcomplex(new Apfloat(1, 21, 2), new Apfloat(2, 21, 2))); assertEquals("2 + 1i radix 2 precision", 19, a.precision()); assertEquals("2 + 1i radix 2 value", new Apcomplex(new Apfloat("100100.1011100110111", 19, 2), new Apfloat("1111.100101100111011", 19, 2)), a, new Apfloat("1e-15", 1, 2)); a = ApcomplexMath.fresnelS(new Apcomplex(new Apfloat("0.1", 21, 2), new Apfloat("0.11", 21, 2))); assertEquals("0.5 + 0.75i radix 2 precision", 21, a.precision()); assertEquals("0.5 + 0.75i radix 2 value", new Apcomplex(new Apfloat("-0.0110100111100100001001", 21, 2), new Apfloat("0.0000101111010110101111011", 21, 2)), a, new Apfloat("1e-22", 1, 2)); } public static void testFresnelC() { Apcomplex a = ApcomplexMath.fresnelC(new Apcomplex("(3.000000,4.000000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(4.53702e14,-6.09754e14)"), a, new Apfloat("5e9")); a = ApcomplexMath.fresnelC(new Apcomplex("(-3.000000,-4.000000)")); assertEquals("-3 - 4i precision", 6, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(-4.53702e14,6.09754e14)"), a, new Apfloat("5e9")); a = ApcomplexMath.fresnelC(new Apcomplex("(2.000000000000000,1.000000000000000)")); assertEquals("2 + 1i precision", 16, a.precision()); assertEquals("2 + 1i value", new Apcomplex("(-36.22568799288165,16.08787137412548)"), a, new Apfloat("5e-14")); a = ApcomplexMath.fresnelC(new Apcomplex("(10000.0000000000000000000000000,1.00000000000000000000000000000)")); assertEquals("10000 + i precision", 22, a.precision()); assertEquals("10000 + i value", new Apcomplex("(-9.23333400023476800428e13638,9.2330400940911741e13634)"), a, new Apfloat("5e13617")); a = ApcomplexMath.fresnelC(new Apcomplex("(3.00000000000000000000000000000e-3,4.00000000000000000000000000000e-3)")); assertEquals("3e-3 + 4e-3i precision", 30, a.precision()); assertEquals("3e-3 + 4e-3i value", new Apcomplex("(0.00300000000005847740605046524772,0.00400000000076884218289338981714)"), a, new Apfloat("5e-32")); a = ApcomplexMath.fresnelC(new Apcomplex("(0,4.00000)")); assertEquals("4i precision", 6, a.precision()); assertEquals("4i value", new Apcomplex("(0,0.498426)"), a, new Apfloat("5e-6")); a = ApcomplexMath.fresnelC(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); a = ApcomplexMath.fresnelC(new Apcomplex(new Apfloat(1, 23, 2), new Apfloat(2, 23, 2))); assertEquals("2 + 1i radix 2 precision", 20, a.precision()); assertEquals("2 + 1i radix 2 value", new Apcomplex(new Apfloat("10000.000101100111111", 20, 2), new Apfloat("-100100.00111001110001", 20, 2)), a, new Apfloat("1e-14", 1, 2)); a = ApcomplexMath.fresnelC(new Apcomplex(new Apfloat("0.1", 21, 2), new Apfloat("0.11", 21, 2))); assertEquals("0.5 + 0.75i radix 2 precision", 21, a.precision()); assertEquals("0.5 + 0.75i radix 2 value", new Apcomplex(new Apfloat("0.0111010111111111010110", 21, 2), new Apfloat("0.111001100101101010101", 21, 2)), a, new Apfloat("1e-21", 1, 2)); } public static void testExpIntegralE() { Apcomplex a = ApcomplexMath.expIntegralE(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(0.000432607,-0.000317912)"), a, new Apfloat("5e-9")); a = ApcomplexMath.expIntegralE(new Apcomplex("(-3.000000,-4.000000)"), new Apcomplex("(-5.000000,-6.000000)")); assertEquals("-3 - 4i, -5 - 6i precision", 6, a.precision()); assertEquals("-3 - 4i, -5 - 6i value", new Apcomplex("(-4.60709,10.3946)"), a, new Apfloat("5e-4")); a = ApcomplexMath.expIntegralE(new Apcomplex("0.999999"), new Apcomplex("(-5.00000,-6.00000)")); assertEquals("0.9999999, -5 - 6i precision", 6, a.precision()); assertEquals("0.9999999, -5 - 6i value", new Apcomplex("(-5.79814,19.4725)"), a, new Apfloat("5e-4")); a = ApcomplexMath.expIntegralE(new Apcomplex("(-300.000000000000000,-400.000000000000000)"), new Apcomplex("(-500.000000000000000,-600.000000000000000)")); assertEquals("-300 - 400i, -500 - 600i precision", 15, a.precision()); assertEquals("-300 - 400i, -500 - 600i value", new Apcomplex("(6.46274794850681e213,-8.84938850450089e213)"), a, new Apfloat("5e199")); /* a = ApcomplexMath.expIntegralE(new Apcomplex("(3.00000e-1000000000000,4.00000e-1000000000000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3e-1000000000000 + 4e-1000000000000i, 5 + 6i precision", 6, a.precision()); assertEquals("3e-1000000000000 + 4e-1000000000000i, 5 + 6i value", new Apcomplex("(0.000715475,-0.000482033)"), a, new Apfloat("5e-9")); a = ApcomplexMath.expIntegralE(new Apcomplex("(3.0000000e-1000000000000,4.0000000e-1000000000000)"), new Apcomplex("(5.0000000e-100,6.0000000e-100)")); assertEquals("3e-1000000000000 + 4e-1000000000000i, 5e-1000000000000 + 6e-1000000000000i precision", 6, a.precision()); assertEquals("3e-1000000000000 + 4e-1000000000000i, 5e-1000000000000 + 6e-1000000000000i value", new Apcomplex("(8.19672e98,-9.83607e98)"), a, new Apfloat("5e93")); */ a = ApcomplexMath.expIntegralE(new Apcomplex("0"), new Apcomplex("-1.00000")); assertEquals("0, -1 precision", 6, a.precision()); assertEquals("0, -1 value", new Apcomplex("-2.71828"), a, new Apfloat("5e-5")); a = ApcomplexMath.expIntegralE(new Apcomplex(new Apfloat(3, 17, 2), new Apfloat(-4, 17, 2)), new Apcomplex(new Apfloat(5, 17, 2), new Apfloat(-6, 17, 2))); assertEquals("3 - 4i, 5 - 6i precision", 14, a.precision()); assertEquals("3 - 4i, 5 - 6i radix", 2, a.radix()); assertEquals("3 - 4i, 5 - 6i value", new Apcomplex(new Apfloat("1.1100010110011111e-12", 17, 2), new Apfloat("1.0100110101011011e-12", 17, 2)), a, new Apfloat("1e-25", 1, 2)); try { ApcomplexMath.expIntegralE(new Apcomplex("0"), new Apcomplex("0")); fail("0, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.expIntegralE(new Apcomplex("(0.9,0.1)"), new Apcomplex("0")); fail("0.9+0.1i, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.expIntegralE(new Apcomplex("1"), new Apcomplex("0")); fail("1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.expIntegralE(new Apcomplex("(1,1)"), new Apcomplex("0")); fail("1+i, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.expIntegralE(new Apcomplex(Apfloat.ONE, new Apfloat(4)), new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testExpIntegralEi() { Apcomplex a = ApcomplexMath.expIntegralEi(new Apcomplex("(3.00000,4.00000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(-4.15409,4.29442)"), a, new Apfloat("5e-5")); a = ApcomplexMath.expIntegralEi(new Apcomplex("(3.00000,-4.00000)")); assertEquals("3 - 4i precision", 6, a.precision()); assertEquals("3 - 4i value", new Apcomplex("(-4.15409,-4.29442)"), a, new Apfloat("5e-5")); a = ApcomplexMath.expIntegralEi(new Apcomplex("3.00000")); assertEquals("3 precision", 6, a.precision()); assertEquals("3 value", new Apcomplex("9.93383"), a, new Apfloat("5e-5")); a = ApcomplexMath.expIntegralEi(new Apcomplex("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apcomplex("-0.0130484"), a, new Apfloat("5e-7")); a = ApcomplexMath.expIntegralEi(new Apfloat(5, 17, 2)); assertEquals("5 precision", 15, a.precision()); assertEquals("5 radix", 2, a.radix()); assertEquals("5 value", new Apfloat("101000.00101111011011", 20, 2), a, new Apfloat("1e-9", 1, 2)); a = ApcomplexMath.expIntegralEi(new Apcomplex(new Apfloat(5, 17, 2), new Apfloat(-6, 17, 2))); assertEquals("5 - 6i precision", 15, a.precision()); assertEquals("5 - 6i radix", 2, a.radix()); assertEquals("5 - 6i value", new Apcomplex(new Apfloat("101.110011000101", 15, 2), new Apfloat("10000.0101010010", 15, 2)), a, new Apfloat("1e-10", 1, 2)); try { ApcomplexMath.expIntegralEi(new Apcomplex("0")); fail("0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.expIntegralEi(new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testLogIntegral() { Apcomplex a = ApcomplexMath.logIntegral(new Apcomplex("(3.00000,4.00000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(3.13438,2.67692)"), a, new Apfloat("5e-5")); a = ApcomplexMath.logIntegral(new Apcomplex("(3.00000,-4.00000)")); assertEquals("3 - 4i precision", 6, a.precision()); assertEquals("3 - 4i value", new Apcomplex("(3.13438,-2.67692)"), a, new Apfloat("5e-5")); a = ApcomplexMath.logIntegral(new Apcomplex("3.000000")); assertEquals("3 precision", 6, a.precision()); assertEquals("3 value", new Apcomplex("2.16359"), a, new Apfloat("5e-5")); a = ApcomplexMath.logIntegral(new Apcomplex("0.0500000")); assertEquals("0.05 precision", 6, a.precision()); assertEquals("0.05 value", new Apcomplex("-0.0131194"), a, new Apfloat("5e-7")); a = ApcomplexMath.logIntegral(new Apcomplex("(0,0.0500000)")); assertEquals("0.05i precision", 6, a.precision()); assertEquals("0.05i value", new Apcomplex("(0.00469234,3.13052)"), a, new Apfloat("5e-5")); a = ApcomplexMath.logIntegral(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); try { ApcomplexMath.logIntegral(new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testSinIntegral() { Apcomplex a = ApcomplexMath.sinIntegral(new Apcomplex("(3.00000,4.00000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(6.74799,-3.49866)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinIntegral(new Apcomplex("(-3.00000,4.00000)")); assertEquals("-3 + 4i precision", 6, a.precision()); assertEquals("-3 + 4i value", new Apcomplex("(-6.74799,-3.49866)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinIntegral(new Apcomplex("(0,4.00000)")); assertEquals("4i precision", 6, a.precision()); assertEquals("4i value", new Apcomplex("(0,9.81732)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinIntegral(new Apcomplex("(0,-4.00000)")); assertEquals("-4i precision", 6, a.precision()); assertEquals("-4i value", new Apcomplex("(0,-9.81732)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinIntegral(new Apcomplex("(1.68942749162698476714140196393428144026820465592265024961338177758470411763182898030309575361902912e-1,4.569309214501175479576223496730314340966258060071718886889228625514024394623574435856202062672506692e1)")); assertEquals("very slow precision", 99, a.precision()); assertEquals("very slow value", new Apcomplex("(1.2856937320582957355639864773250768352672586514874553088490985837403937331727094287936043615541429e17,7.7136891207689360132104393031156808820367356331758362713399089224432529992357532871154537681039206e17)"), a, new Apfloat("5e-84")); a = ApcomplexMath.sinIntegral(new Apcomplex("0.0001").precision(30)); assertEquals("0.00001 precision", 30, a.precision()); assertEquals("0.00001 value", new Apcomplex("0.000099999999944444444461111111108"), a, new Apfloat("5e-33")); a = ApcomplexMath.sinIntegral(new Apcomplex("(0,0.0001)").precision(30)); assertEquals("0.00001i precision", 30, a.precision()); assertEquals("0.00001i value", new Apcomplex("(0,0.000100000000055555555572222222225)"), a, new Apfloat("5e-33")); a = ApcomplexMath.sinIntegral(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); a = ApcomplexMath.sinIntegral(new Apcomplex(new Apfloat(5, 17, 2), new Apfloat(-6, 17, 2))); assertEquals("5 - 6i precision", 15, a.precision()); assertEquals("5 - 6i radix", 2, a.radix()); assertEquals("5 - 6i value", new Apcomplex(new Apfloat("-10111.00000110110", 15, 2), new Apfloat("1110.00001100100", 15, 2)), a, new Apfloat("1e-10", 1, 2)); a = ApcomplexMath.sinIntegral(new Apcomplex(new Apfloat("0.1", 17, 2), new Apfloat("0.11", 17, 2))); assertEquals("0.5 + 0.75i precision", 17, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("0.1000101001000101001", 17, 2), new Apfloat("0.101111011011111111", 17, 2)), a, new Apfloat("1e-17", 1, 2)); try { ApcomplexMath.sinIntegral(new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testCosIntegral() { Apcomplex a = ApcomplexMath.cosIntegral(new Apcomplex("(3.00000,4.00000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(-3.49576,-5.17591)"), a, new Apfloat("5e-5")); a = ApcomplexMath.cosIntegral(new Apcomplex("(-3.00000,4.00000)")); assertEquals("-3 + 4i precision", 6, a.precision()); assertEquals("-3 + 4i value", new Apcomplex("(-3.49576,8.3175)"), a, new Apfloat("5e-5")); a = ApcomplexMath.cosIntegral(new Apcomplex("(-3.00000,-4.00000)")); assertEquals("-3 - 4i precision", 6, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(-3.49576,-8.3175)"), a, new Apfloat("5e-5")); a = ApcomplexMath.cosIntegral(new Apcomplex("(0,4.00000)")); assertEquals("4i precision", 6, a.precision()); assertEquals("4i value", new Apcomplex("(9.81355,1.5708)"), a, new Apfloat("5e-5")); a = ApcomplexMath.cosIntegral(new Apcomplex("(0,-4.00000)")); assertEquals("-4i precision", 6, a.precision()); assertEquals("-4i value", new Apcomplex("(9.81355,-1.5708)"), a, new Apfloat("5e-5")); a = ApcomplexMath.cosIntegral(new Apcomplex("0.0001").precision(30)); assertEquals("0.00001 precision", 30, a.precision()); assertEquals("0.00001 value", new Apcomplex("-8.63312470957464987442378706222"), a, new Apfloat("5e-29")); a = ApcomplexMath.cosIntegral(new Apcomplex("(0,0.0001)").precision(30)); assertEquals("0.00001i precision", 30, a.precision()); assertEquals("0.00001i value", new Apcomplex("(-8.6331247045746498744237870618,1.57079632679489661923132169164)"), a, new Apfloat("5e-29")); a = ApcomplexMath.cosIntegral(new Apcomplex(new Apfloat(-5, 17, 2), new Apfloat(-6, 17, 2))); assertEquals("-5 - 6i precision", 15, a.precision()); assertEquals("-5 - 6i radix", 2, a.radix()); assertEquals("-5 - 6i value", new Apcomplex(new Apfloat("-1110.00001100101011", 15, 2), new Apfloat("10101.011101001011", 15, 2)), a, new Apfloat("1e-10", 1, 2)); a = ApcomplexMath.cosIntegral(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2))); assertEquals("0.5 + 0.75i precision", 17, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("0.100010111110101110011", 17, 2), new Apfloat("0.11001010010110111000011", 17, 2)), a, new Apfloat("1e-17", 1, 2)); try { ApcomplexMath.cosIntegral(new Apcomplex("0")); fail("0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.cosIntegral(new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testSinhIntegral() { Apcomplex a = ApcomplexMath.sinhIntegral(new Apcomplex("(3.00000,4.00000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(-2.07661,2.15160)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinhIntegral(new Apcomplex("(3.00000,-4.00000)")); assertEquals("3 - 4i precision", 6, a.precision()); assertEquals("3 - 4i value", new Apcomplex("(-2.07661,-2.15160)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinhIntegral(new Apcomplex("(-3.00000,4.00000)")); assertEquals("-3 + 4i precision", 6, a.precision()); assertEquals("-3 + 4i value", new Apcomplex("(2.07661,2.15160)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinhIntegral(new Apcomplex("(-3.00000,-4.00000)")); assertEquals("-3 - 4i precision", 6, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(2.07661,-2.15160)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinhIntegral(new Apcomplex("4.00000")); assertEquals("4 precision", 6, a.precision()); assertEquals("4 value", new Apcomplex("9.81733"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinhIntegral(new Apcomplex("-4.00000")); assertEquals("-4 precision", 6, a.precision()); assertEquals("-4 value", new Apcomplex("-9.81733"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinhIntegral(new Apcomplex("(0,4.00000)")); assertEquals("4i precision", 6, a.precision()); assertEquals("4i value", new Apcomplex("(0,1.75820)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinhIntegral(new Apcomplex("(0,-4.00000)")); assertEquals("-4i precision", 6, a.precision()); assertEquals("-4i value", new Apcomplex("(0,-1.75820)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sinhIntegral(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); try { ApcomplexMath.sinhIntegral(new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testCoshIntegral() { Apcomplex a = ApcomplexMath.coshIntegral(new Apcomplex("(3.00000,4.00000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(-2.07748,2.14282)"), a, new Apfloat("5e-5")); a = ApcomplexMath.coshIntegral(new Apcomplex("(3.00000,-4.00000)")); assertEquals("3 - 4i precision", 6, a.precision()); assertEquals("3 - 4i value", new Apcomplex("(-2.07748,-2.14282)"), a, new Apfloat("5e-5")); a = ApcomplexMath.coshIntegral(new Apcomplex("(-3.00000,4.00000)")); assertEquals("-3 + 4i precision", 6, a.precision()); assertEquals("-3 + 4i value", new Apcomplex("(-2.07748,0.998776)"), a, new Apfloat("5e-5")); a = ApcomplexMath.coshIntegral(new Apcomplex("(-3.00000,-4.00000)")); assertEquals("-3 - 4i precision", 6, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(-2.07748,-0.998776)"), a, new Apfloat("5e-5")); a = ApcomplexMath.coshIntegral(new Apcomplex("4.00000")); assertEquals("4 precision", 6, a.precision()); assertEquals("4 value", new Apcomplex("9.81355"), a, new Apfloat("5e-5")); a = ApcomplexMath.coshIntegral(new Apcomplex("-4.00000")); assertEquals("-4 precision", 6, a.precision()); assertEquals("-4 value", new Apcomplex("(9.81355,3.14159)"), a, new Apfloat("5e-5")); a = ApcomplexMath.coshIntegral(new Apcomplex("(0,4.00000)")); assertEquals("4i precision", 6, a.precision()); assertEquals("4i value", new Apcomplex("(-0.140982,1.57080)"), a, new Apfloat("5e-5")); a = ApcomplexMath.coshIntegral(new Apcomplex("(0,-4.00000)")); assertEquals("-4i precision", 6, a.precision()); assertEquals("-4i value", new Apcomplex("(-0.140982,-1.57080)"), a, new Apfloat("5e-5")); try { ApcomplexMath.coshIntegral(new Apcomplex("0")); fail("0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.coshIntegral(new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testAiryAi() { Apcomplex a = ApcomplexMath.airyAi(new Apcomplex("(1.00000,2.00000)")); assertEquals("1 + 2i precision", 6, a.precision()); assertEquals("1 + 2i value", new Apcomplex("(-0.219386,-0.175386)"), a, new Apfloat("5e-6")); a = ApcomplexMath.airyAi(new Apcomplex("(-3.000000,-4.000000)")); assertEquals("-3 - 4i precision", 7, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(207.7347,-204.6056)"), a, new Apfloat("5e-4")); a = ApcomplexMath.airyAi(new Apcomplex("(-300.000000000000,400.000000000000)")); assertEquals("-300 + 400i precision", 11, a.precision()); assertEquals("-300 + 400i value", new Apcomplex("(2.9404090561e3183,2.7090694495e3183)"), a, new Apfloat("5e3173")); a = ApcomplexMath.airyAi(new Apcomplex(new Apfloat(-300, 50, 2), new Apfloat(-400, 50, 2))); assertEquals("-300 - 400i precision", 37, a.precision()); assertEquals("-300 - 400i radix", 2, a.radix()); assertEquals("-300 - 400i value", new Apcomplex(new Apfloat("1.001100010001100111011000010101110010e10575", 37, 2), new Apfloat("-1.000110010001100011001010010000000101e10575", 37, 2)), a, new Apfloat("1e10539", 1, 2)); a = ApcomplexMath.airyAi(new Apcomplex(new Apfloat("0.1", 17, 2), new Apfloat("0.11", 17, 2))); assertEquals("0.5 + 0.75i precision", 17, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("0.0011000110100010010", 17, 2), new Apfloat("-0.0010110100011100011", 17, 2)), a, new Apfloat("1e-19", 1, 2)); try { ApcomplexMath.airyAi(new Apcomplex("0")); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testAiryAiPrime() { Apcomplex a = ApcomplexMath.airyAiPrime(new Apcomplex("(1.00000,2.00000)")); assertEquals("1 + 2i precision", 6, a.precision()); assertEquals("1 + 2i value", new Apcomplex("(0.170445,0.387622)"), a, new Apfloat("5e-6")); a = ApcomplexMath.airyAiPrime(new Apcomplex("(-3.000000,-4.000000)")); assertEquals("-3 - 4i precision", 7, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(199.6016,604.6785)"), a, new Apfloat("5e-4")); a = ApcomplexMath.airyAiPrime(new Apcomplex("(-300.000000000000,400.000000000000)")); assertEquals("-300 + 400i precision", 11, a.precision()); assertEquals("-300 + 400i value", new Apcomplex("(2.477709693e3184,-8.589688662e3184)"), a, new Apfloat("5e3174")); a = ApcomplexMath.airyAiPrime(new Apcomplex(new Apfloat("0.1", 19, 2), new Apfloat("0.11", 19, 2))); assertEquals("0.5 + 0.75i precision", 19, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("-0.01000000101011010010", 19, 2), new Apfloat("0.00011101011010111011101", 19, 2)), a, new Apfloat("1e-20", 1, 2)); try { ApcomplexMath.airyAiPrime(new Apcomplex("0")); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testAiryBi() { Apcomplex a = ApcomplexMath.airyBi(new Apcomplex("(1.00000,2.00000)")); assertEquals("1 + 2i precision", 6, a.precision()); assertEquals("1 + 2i value", new Apcomplex("(0.048822,0.133274)"), a, new Apfloat("5e-6")); a = ApcomplexMath.airyBi(new Apcomplex("(-3.000000,-4.000000)")); assertEquals("-3 - 4i precision", 7, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(-204.6057,-207.7345)"), a, new Apfloat("5e-4")); a = ApcomplexMath.airyBi(new Apcomplex("(300.00000000000,-400.00000000000)")); assertEquals("-300 + 400i precision", 11, a.precision()); assertEquals("-300 + 400i value", new Apcomplex("(1.1097608159e578,-7.994050161e577)"), a, new Apfloat("5e568")); a = ApcomplexMath.airyBi(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2))); assertEquals("0.5 + 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("0.110000000000010100", 18, 2), new Apfloat("0.01010101001010100101", 18, 2)), a, new Apfloat("1e-18", 1, 2)); try { ApcomplexMath.airyBi(new Apcomplex("0")); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testAiryBiPrime() { Apcomplex a = ApcomplexMath.airyBiPrime(new Apcomplex("(1.00000,2.00000)")); assertEquals("1 + 2i precision", 6, a.precision()); assertEquals("1 + 2i value", new Apcomplex("(-0.857239,0.495506)"), a, new Apfloat("5e-6")); a = ApcomplexMath.airyBiPrime(new Apcomplex("(-3.000000,-4.000000)")); assertEquals("-3 - 4i precision", 7, a.precision()); assertEquals("-3 - 4i value", new Apcomplex("(604.6789,-199.6012)"), a, new Apfloat("5e-4")); a = ApcomplexMath.airyBiPrime(new Apcomplex("(300.00000000000,-400.00000000000)")); assertEquals("-300 + 400i precision", 11, a.precision()); assertEquals("-300 + 400i value", new Apcomplex("(1.4200513472e579,-2.7085912602e579)"), a, new Apfloat("5e569")); a = ApcomplexMath.airyBiPrime(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2))); assertEquals("0.5 + 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("0.0100000000010011111111", 18, 2), new Apfloat("0.001111010001010101101", 18, 2)), a, new Apfloat("1e-19", 1, 2)); try { ApcomplexMath.airyBiPrime(new Apcomplex("0")); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testBesselJ() { Apcomplex a = ApcomplexMath.besselJ(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(0.399827,-0.359635)"), a, new Apfloat("5e-6")); } public static void testBesselI() { Apcomplex a = ApcomplexMath.besselI(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(-3.54535,-7.37327 )"), a, new Apfloat("5e-5")); } public static void testBesselY() { Apcomplex a = ApcomplexMath.besselY(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(0.357553,0.294736)"), a, new Apfloat("5e-6")); } public static void testBesselK() { Apcomplex a = ApcomplexMath.besselK(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(0.00282215,0.00595941)"), a, new Apfloat("5e-8")); } public static void testEllipticK() { Apcomplex a = ApcomplexMath.ellipticK(new Apcomplex("(3.00000,4.00000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(0.911196,0.631334)"), a, new Apfloat("5e-6")); a = ApcomplexMath.ellipticK(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2))); assertEquals("0.5 + 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("1.10010110101011111", 18, 2), new Apfloat("0.011001001001011001111", 18, 2)), a, new Apfloat("1e-17", 1, 2)); try { ApcomplexMath.ellipticK(new Apcomplex("1.00000")); fail("1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.ellipticK(new Apcomplex("0")); fail("Infinite expansion of pi/2"); } catch (InfiniteExpansionException iee) { // OK } try { ApcomplexMath.ellipticK(new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testEllipticE() { Apcomplex a = ApcomplexMath.ellipticE(new Apcomplex("(3.00000,4.00000)")); assertEquals("3 + 4i precision", 6, a.precision()); assertEquals("3 + 4i value", new Apcomplex("(1.49955,-1.57788)"), a, new Apfloat("5e-5")); a = ApcomplexMath.ellipticE(new Apcomplex("(55,66)").precision(80)); assertEquals("55 + 66i precision", 80, a.precision()); assertEquals("55 + 66i value", new Apcomplex("(4.0811432805851427433792385864776680345716395379587937142840046535853583006891006,-8.2188557700657038428087644147741544808312164555261128756030008732791464871734558)"), a, new Apfloat("5e-79")); a = ApcomplexMath.ellipticE(new Apcomplex("1.00000")); assertEquals("1 precision", 6, a.precision()); assertEquals("1 value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.ellipticE(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2))); assertEquals("0.5 + 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("1.0110101111110111101", 18, 2), new Apfloat("-0.010101110110101001", 18, 2)), a, new Apfloat("1e-17", 1, 2)); try { ApcomplexMath.ellipticE(new Apcomplex("0")); fail("Infinite expansion of pi/2"); } catch (InfiniteExpansionException iee) { // OK } try { ApcomplexMath.ellipticE(new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHermiteH() { Apcomplex a = ApcomplexMath.hermiteH(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(53.7166,89.7677)"), a, new Apfloat("5e-4")); a = ApcomplexMath.hermiteH(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("0")); assertEquals("3 + 4i, 0 precision", 6, a.precision()); assertEquals("3 + 4i, 0 value", new Apcomplex("(315.806,-267.626)"), a, new Apfloat("5e-3")); a = ApcomplexMath.hermiteH(new Apcomplex("1.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1, 5 + 6i precision", 6, a.precision()); assertEquals("1, 5 + 6i value", new Apcomplex("(10.0000,12.0000)"), a, new Apfloat("5e-4")); a = ApcomplexMath.hermiteH(new Apcomplex("2.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("2, 5 + 6i precision", 6, a.precision()); assertEquals("2, 5 + 6i value", new Apcomplex("(-46.000,240.000)"), a, new Apfloat("5e-3")); a = ApcomplexMath.hermiteH(new Apcomplex("-1.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-1, 5 + 6i precision", 6, a.precision()); assertEquals("-1, 5 + 6i value", new Apcomplex("(0.0414360,-0.0489105)"), a, new Apfloat("5e-7")); a = ApcomplexMath.hermiteH(new Apcomplex("-2.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-2, 5 + 6i precision", 6, a.precision()); assertEquals("-2, 5 + 6i value", new Apcomplex("(-0.000642876,-0.00406325)"), a, new Apfloat("5e-8")); a = ApcomplexMath.hermiteH(new Apcomplex("-1.20000"), new Apcomplex("1.90000")); assertEquals("-1.2, 1.9 precision", 6, a.precision()); assertEquals("-1.2, 1.9 value", new Apcomplex("0.175081"), a, new Apfloat("5e-6")); a = ApcomplexMath.hermiteH(new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)")); assertEquals("0, 5 + 6i precision", 6, a.precision()); assertEquals("0, 5 + 6i value", new Apcomplex("1"), a); a = ApcomplexMath.hermiteH(new Apcomplex("0"), new Apcomplex("0")); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 value", new Apcomplex("1"), a); a = ApcomplexMath.hermiteH(new Apcomplex("2.00000"), new Apcomplex("0.7071067811865475")); assertEquals("2, 1/sqrt(2) precision", 6, a.precision()); assertEquals("2, 1/sqrt(2) value", new Apcomplex("0"), a, new Apfloat("5e-16")); a = ApcomplexMath.hermiteH(new Apcomplex("3.00000"), new Apcomplex("0")); assertEquals("3, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("3, 0 value", new Apcomplex("0"), a); a = ApcomplexMath.hermiteH(new Apcomplex("4.00000"), new Apcomplex("0")); assertEquals("4, 0 precision", 6, a.precision()); assertEquals("4, 0 value", new Apcomplex("12.0000"), a, new Apfloat("5e-4")); a = ApcomplexMath.hermiteH(new Apcomplex("-3.00000"), new Apcomplex("0")); assertEquals("-3, 0 precision", 6, a.precision()); assertEquals("-3, 0 value", new Apcomplex("0.221557"), a, new Apfloat("5e-6")); a = ApcomplexMath.hermiteH(new Apcomplex("-4.00000"), new Apcomplex("0")); assertEquals("-4, 0 precision", 6, a.precision()); assertEquals("-4, 0 value", new Apcomplex("0.0833333"), a, new Apfloat("5e-7")); a = ApcomplexMath.hermiteH(new Apcomplex("3.500000000000000"), new Apcomplex("0.2770651806914138")); assertEquals("3.5, root precision", 16, a.precision()); assertEquals("3.5, root value", new Apcomplex("0"), a, new Apfloat("5e-16")); a = ApcomplexMath.hermiteH(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i value", new Apcomplex(new Apfloat("11.10000000101011011", 18, 2), new Apfloat("-10.110001100010111001", 18, 2)), a, new Apfloat("1e-16", 1, 2)); try { ApcomplexMath.hermiteH(Apfloat.ONE, new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testLaguerreL() { Apcomplex a = ApcomplexMath.laguerreL(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(-3204.7,13832.4)"), a, new Apfloat("5e-1")); a = ApcomplexMath.laguerreL(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i value", new Apcomplex(new Apfloat("0.101110111001010010", 18, 2), new Apfloat("0.100111010100100101", 18, 2)), a, new Apfloat("1e-18", 1, 2)); try { ApcomplexMath.laguerreL(Apfloat.ONE, new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testLaguerreLGeneralized() { Apcomplex a = ApcomplexMath.laguerreL(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1 + 2i, 3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("1 + 2i, 3 + 4i, 5 + 6i value", new Apcomplex("(21.8186,-11.884)"), a, new Apfloat("5e-4")); a = ApcomplexMath.laguerreL(new Apcomplex("-1.00000"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-1, 3 + 4i, 5 + 6i precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, 3 + 4i, 5 + 6i value", new Apcomplex("0"), a); a = ApcomplexMath.laguerreL(new Apcomplex("-1.00000"), new Apcomplex("-2.00000"), new Apcomplex("-1.00000")); assertEquals("-1, -2, -1 precision", 6, a.precision()); assertEquals("-1, -2, -1 value", new Apcomplex("0.183940"), a, new Apfloat("5e-6")); a = ApcomplexMath.laguerreL(new Apcomplex(new Apfloat("0.1", 19, 2), new Apfloat("0.11", 19, 2)), new Apcomplex(new Apfloat("-0.1", 19, 2), new Apfloat("-0.11", 19, 2)), new Apcomplex(new Apfloat("0.1", 19, 2), new Apfloat("-0.11", 19, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i value", new Apcomplex(new Apfloat("-0.1001100101100010101", 18, 2), new Apfloat("-1.001000000110101111", 18, 2)), a, new Apfloat("1e-17", 1, 2)); try { ApcomplexMath.laguerreL(new Apfloat("-0.5"), new Apfloat("-0.5"), new Apfloat(0)); fail("Gamma of 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.laguerreL(Apfloat.ONE, new Apfloat(4), new Apfloat(5)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testLegendreP() { Apcomplex a = ApcomplexMath.legendreP(new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(5.000000,6.000000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(22.7624,16.4401)"), a, new Apfloat("5e-4")); a = ApcomplexMath.legendreP(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i value", new Apcomplex(new Apfloat("10.0000100011011000", 18, 2), new Apfloat("-10.0100010011001100", 18, 2)), a, new Apfloat("1e-16", 1, 2)); try { ApcomplexMath.legendreP(new Apfloat("0.5"), new Apfloat("-1")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.legendreP(Apfloat.ONE, new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testLegendrePAssociated() { Apcomplex a = ApcomplexMath.legendreP(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(5.000000,6.000000)")); assertEquals("1 + 2i, 3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("1 + 2i, 3 + 4i, 5 + 6i value", new Apcomplex("(-2.94024,-11.8168)"), a, new Apfloat("5e-4")); a = ApcomplexMath.legendreP(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2)), new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i value", new Apcomplex(new Apfloat("0.11100010110110000111", 18, 2), new Apfloat("-0.0100100111100001101111", 18, 2)), a, new Apfloat("1e-18", 1, 2)); try { ApcomplexMath.legendreP(new Apfloat("0.5"), new Apfloat("0.1"), new Apfloat("-1")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.legendreP(Apfloat.ONE, new Apfloat(4), new Apfloat(5)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testLegendreQ() { Apcomplex a = ApcomplexMath.legendreQ(new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(5.000000,6.000000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(-25.8244,35.7548)"), a, new Apfloat("5e-4")); a = ApcomplexMath.legendreQ(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i value", new Apcomplex(new Apfloat("-11.1001110100000101", 18, 2), new Apfloat("-11.00011010110110111", 18, 2)), a, new Apfloat("1e-16", 1, 2)); try { ApcomplexMath.legendreQ(new Apfloat("0.5"), new Apfloat("1")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.legendreQ(new Apfloat("0.5"), new Apfloat("-1")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.legendreQ(Apfloat.ONE, new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testLegendreQAssociated() { Apcomplex a = ApcomplexMath.legendreQ(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1 + 2i, 3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("1 + 2i, 3 + 4i, 5 + 6i value", new Apcomplex("(-18.6108,4.58924)"), a, new Apfloat("5e-4")); a = ApcomplexMath.legendreQ(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(3.00000,2.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1 + 2i, 3 + 2i, 5 + 6i precision", 6, a.precision()); assertEquals("1 + 2i, 3 + 2i, 5 + 6i value", new Apcomplex("(2.62864,-3.38769)"), a, new Apfloat("5e-5")); a = ApcomplexMath.legendreQ(new Apcomplex("(1.00000,2.00000)"), new Apcomplex("(4.00000,2.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1 + 2i, 4 + 2i, 5 + 6i precision", 6, a.precision()); assertEquals("1 + 2i, 4 + 2i, 5 + 6i value", new Apcomplex("(-6.65987,-26.5379)"), a, new Apfloat("5e-4")); /* a = ApcomplexMath.legendreQ(new Apcomplex("(111.000,222.000)"), new Apcomplex("(333.000,444.000)"), new Apcomplex("(555.000,666.000)")); assertEquals("1 + 2i, 3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("1 + 2i, 3 + 4i, 5 + 6i value", new Apcomplex("(-1.51954e766,6.241444e766)"), a, new Apfloat("5e761")); */ a = ApcomplexMath.legendreQ(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2)), new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i value", new Apcomplex(new Apfloat("0.0110000011010011101", 18, 2), new Apfloat("-1.0101011110001011011", 18, 2)), a, new Apfloat("1e-17", 1, 2)); try { ApcomplexMath.legendreQ(new Apfloat("0.5"), new Apfloat("0.1"), new Apfloat("1")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.legendreQ(new Apfloat("0.5"), new Apfloat("0.1"), new Apfloat("-1")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.legendreQ(new Apfloat("0.5"), new Apfloat("-0.1"), new Apfloat("-1")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.legendreQ(new Apfloat("-1"), new Apfloat("-1"), new Apcomplex("(5,6)")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.legendreQ(new Apfloat("-1"), new Apfloat("-2"), new Apcomplex("(5,6)")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.legendreQ(Apfloat.ONE, new Apfloat(4), new Apfloat(5)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testSphericalHarmonicY() { // Note: Mathematica gives inconsistent results when real part of ϑ is > pi or negative and λ and μ are not integers Apcomplex a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(3.000000,6.000000)"), new Apcomplex("(7.000000,8.000000)")); assertEquals("1 + 2i, 3 + 4i, 3 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("1 + 2i, 3 + 4i, 3 + 6i, 7 + 8i value", new Apcomplex("(-1.00082e-15,-1.81859e-16)"), a, new Apfloat("5e-20")); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(-2.000000,-2.000000)"), new Apcomplex("(5.000000,6.000000)"), new Apcomplex("(7.000000,8.000000)")); assertEquals("1 + 2i, -2 - 2i, 5 + 6i, 7 + 8i precision", Apfloat.INFINITE, a.precision()); assertEquals("1 + 2i, -2 - 2i, 5 + 6i, 7 + 8i value", new Apcomplex("0"), a); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(-3.000000,4.000000)"), new Apcomplex("(3.000000,6.000000)"), new Apcomplex("(7.000000,8.000000)")); assertEquals("1 + 2i, -3 + 4i, 3 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("1 + 2i, -3 + 4i, 3 + 6i, 7 + 8i value", new Apcomplex("(8705220,328078)"), a, new Apfloat("5e1")); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(3.000000,-2.000000)"), new Apcomplex("(3.000000,6.000000)"), new Apcomplex("(7.000000,8.000000)")); assertEquals("1 + 2i, 3 - 2i, 3 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("1 + 2i, 3 - 2i, 3 + 6i, 7 + 8i value", new Apcomplex("(0.124816,-0.178021 )"), a, new Apfloat("5e-6")); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(-3.100000,4.000000)"), new Apcomplex("(3.000000,6.000000)"), new Apcomplex("(7.000000,8.000000)")); assertEquals("1 + 2i, -3.1 + 4i, 3 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("1 + 2i, -3.1 + 4i, 3 + 6i, 7 + 8i value", new Apcomplex("(1.81034e7,-7.51346e6)"), a, new Apfloat("5e2")); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("-1.00000"), new Apcomplex("-1.100000"), new Apcomplex("(3.00000,6.00000)"), new Apcomplex("(7.00000,8.00000)")); assertEquals("-1, -1.1, 3 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("-1, -1.1, 3 + 6i, 7 + 8i value", new Apcomplex("(-171.803,535.796)"), a, new Apfloat("5e-3")); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("-0.500000"), new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(7.00000,8.00000)")); assertEquals("-0.5, 3 + 4i, 5 + 6i, 7 + 8i precision", Apfloat.INFINITE, a.precision()); assertEquals("-0.5, 3 + 4i, 5 + 6i, 7 + 8i value", new Apcomplex("0"), a); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("(1.0000000,2.0000000)"), new Apcomplex("0"), new Apcomplex("(5.000000,6.000000)"), new Apcomplex("(7.000000,8.000000)")); assertEquals("1 + 2i, 0, 5 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("1 + 2i, 0, 5 + 6i, 7 + 8i value", new Apcomplex("(5.60421,4.50366)"), a, new Apfloat("5e-5")); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("-1.00000"), new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(7.00000,8.00000)")); assertEquals("-1, 0, 5 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("-1, 0, 5 + 6i, 7 + 8i value", new Apcomplex("(0.282095)"), a, new Apfloat("5e-6")); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("2.00000"), new Apcomplex("3.00000"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(7.00000,8.00000)")); assertEquals("2, 3, 5 + 6i, 7 + 8i precision", Apfloat.INFINITE, a.precision()); assertEquals("2, 3, 5 + 6i, 7 + 8i value", new Apcomplex("0"), a); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("0"), new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(7.00000,8.00000)")); assertEquals("0, 0, 5 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("0, 0, 5 + 6i, 7 + 8i value", new Apcomplex("(0.282095)"), a, new Apfloat("5e-6")); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex("1.00000"), new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(7.00000,8.00000)")); assertEquals("1, 0, 5 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("1, 0, 5 + 6i, 7 + 8i value", new Apcomplex("(27.9574,94.5092)"), a, new Apfloat("5e-4")); a = ApcomplexMath.sphericalHarmonicY(new Apcomplex(new Apfloat("0.1", 19, 2), new Apfloat("0.11", 19, 2)), new Apcomplex(new Apfloat("-0.1", 19, 2), new Apfloat("-0.11", 19, 2)), new Apcomplex(new Apfloat("0.11", 19, 2), new Apfloat("0.111", 19, 2)), new Apcomplex(new Apfloat("-0.11", 19, 2), new Apfloat("-0.111", 19, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.75 + 0.875i, -0.75 - 0.875i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.75 + 0.875i, -0.75 - 0.875i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.75 + 0.875i, -0.75 - 0.875i value", new Apcomplex(new Apfloat("0.000100111111001111110", 18, 2), new Apfloat("1.10011101000100100e-6", 18, 2)), a, new Apfloat("1e-21", 1, 2)); a = ApcomplexMath.sphericalHarmonicY(new Apfloat("11", 18, 2), new Apfloat("1", 18, 2), new Apcomplex(new Apfloat("0.11", 18, 2), new Apfloat("0.111", 18, 2)), new Apcomplex(new Apfloat("-0.11", 18, 2), new Apfloat("-0.111", 18, 2))); assertEquals("3, 1, 0.75 + 0.875i, -0.75 - 0.875i precision", 18, a.precision()); assertEquals("3, 1, 0.75 + 0.875i, -0.75 - 0.875i radix", 2, a.radix()); assertEquals("3, 1, 0.75 + 0.875i, -0.75 - 0.875i value", new Apcomplex(new Apfloat("-1.00110101111110011", 18, 2), new Apfloat("110.101001011111111", 18, 2)), a, new Apfloat("1e-15", 1, 2)); try { ApcomplexMath.sphericalHarmonicY(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(2.000000,2.000000)"), new Apcomplex("(5.000000,6.000000)"), new Apcomplex("(7.000000,8.000000)")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.sphericalHarmonicY(new Apfloat(3.1, Apfloat.INFINITE), new Apfloat(2), new Apfloat(5), new Apfloat(6)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } try { ApcomplexMath.sphericalHarmonicY(new Apfloat(3), new Apfloat(2), new Apfloat(5), new Apfloat(6)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testChebyshevT() { Apcomplex a = ApcomplexMath.chebyshevT(new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(5.000000,6.000000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(27.0758,49.6084)"), a, new Apfloat("5e-4")); a = ApcomplexMath.chebyshevT(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("0")); assertEquals("3 + 4i, 0 precision", 6, a.precision()); assertEquals("3 + 4i, 0 value", new Apcomplex("(0,267.745)"), a, new Apfloat("5e-3")); a = ApcomplexMath.chebyshevT(new Apcomplex("0"), new Apcomplex("0")); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 value", new Apcomplex("1"), a); a = ApcomplexMath.chebyshevT(new Apint(0, 9), new Apint(0, 9)); assertEquals("0, 0 precision radix 9", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 radix radix 9", 9, a.radix()); assertEquals("0, 0 value radix 9", new Apint(1, 9), a); try { ApcomplexMath.chebyshevT(new Apfloat(3), new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testChebyshevU() { Apcomplex a = ApcomplexMath.chebyshevU(new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(5.000000,6.000000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(54.5031,98.9294)"), a, new Apfloat("5e-4")); a = ApcomplexMath.chebyshevU(new Apcomplex("(2.00000,3.00000)"), new Apcomplex("0")); assertEquals("2 + 3i, 0 precision", 6, a.precision()); assertEquals("2 + 3i, 0 value", new Apcomplex("-55.6634"), a, new Apfloat("5e-4")); a = ApcomplexMath.chebyshevU(new Apcomplex("0"), new Apcomplex("0")); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 value", new Apcomplex("1"), a); a = ApcomplexMath.chebyshevU(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("1.00000")); assertEquals("3 + 4i, 1 precision", 6, a.precision()); assertEquals("3 + 4i, 1 value", new Apcomplex("(4.00000,4.00000)"), a, new Apfloat("5e-5")); a = ApcomplexMath.chebyshevU(new Apcomplex("3.00000"), new Apcomplex("-1.00000")); assertEquals("3, -1 precision", 6, a.precision()); assertEquals("3, -1 value", new Apcomplex("-4.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.chebyshevU(new Apcomplex("4.00000"), new Apcomplex("-1.00000")); assertEquals("4, -1 precision", 6, a.precision()); assertEquals("4, -1 value", new Apcomplex("5.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.chebyshevU(new Apcomplex("0"), new Apcomplex("(3.00000,4.00000)")); assertEquals("0, 3 + 4i precision", 6, a.precision()); assertEquals("0, 3 + 4i value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.chebyshevU(new Apcomplex(new Apfloat("0.1", 20, 2), new Apfloat("0.11", 20, 2)), new Apcomplex(new Apfloat("-0.1", 20, 2), new Apfloat("-0.11", 20, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i value", new Apcomplex(new Apfloat("100.1001100100111011", 18, 2), new Apfloat("-10.111000100101001111", 18, 2)), a, new Apfloat("1e-15", 1, 2)); a = ApcomplexMath.chebyshevU(new Apint(0, 9), new Apint(0, 9)); assertEquals("0, 0 precision radix 9", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 radix radix 9", 9, a.radix()); assertEquals("0, 0 value radix 9", new Apint(1, 9), a); try { ApcomplexMath.chebyshevU(new Apcomplex("(3.000000,4.000000)"), new Apcomplex("-1.000000")); fail("3 + 4i, -1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.chebyshevU(new Apfloat(3), new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testGegenbauerCRenormalized() { Apcomplex a = ApcomplexMath.gegenbauerC(new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(5.000000,6.000000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(22.3729,3.24175)"), a, new Apfloat("5e-4")); a = ApcomplexMath.gegenbauerC(new Apcomplex(new Apfloat("0.1", 19, 2), new Apfloat("0.11", 19, 2)), new Apcomplex(new Apfloat("-0.1", 19, 2), new Apfloat("-0.11", 19, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i value", new Apcomplex(new Apfloat("1.01000111000001010", 18, 2), new Apfloat("-111.0000101110111111", 18, 2)), a, new Apfloat("1e-15", 1, 2)); try { ApcomplexMath.gegenbauerC(new Apcomplex("0"), new Apcomplex("(5.000000,6.000000)")); fail("0, 5 + 6i accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.gegenbauerC(new Apfloat(3), new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testGegenbauerC() { Apcomplex a = ApcomplexMath.gegenbauerC(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(5.000000,6.000000)")); assertEquals("1 + 2i, 3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("1 + 2i, 3 + 4i, 5 + 6i value", new Apcomplex("(-5.65525,-1.46442)"), a, new Apfloat("5e-5")); a = ApcomplexMath.gegenbauerC(new Apcomplex("142.000"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("142, 3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("142, 3 + 4i, 5 + 6i value", new Apcomplex("(-1.22769e174,3.88388e174)"), a, new Apfloat("5e169")); a = ApcomplexMath.gegenbauerC(new Apcomplex("141.000"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("141, 3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("141, 3 + 4i, 5 + 6i value", new Apcomplex("(1.45386e173,2.1174e173)"), a, new Apfloat("5e168")); a = ApcomplexMath.gegenbauerC(new Apcomplex("2.00000"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("2, 3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("2, 3 + 4i, 5 + 6i value", new Apcomplex("(-3275.00,-1100.00)"), a, new Apfloat("5e-2")); a = ApcomplexMath.gegenbauerC(new Apcomplex("1.00000"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1, 3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("1, 3 + 4i, 5 + 6i value", new Apcomplex("(-18.0000,76.0000)"), a, new Apfloat("5e-4")); a = ApcomplexMath.gegenbauerC(new Apcomplex("-1.00000"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-1, 3 + 4i, 5 + 6i precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, 3 + 4i, 5 + 6i value", new Apcomplex("0"), a); a = ApcomplexMath.gegenbauerC(new Apcomplex("-1.00000"), new Apcomplex("0.500000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-1, 0.5, 5 + 6i precision", 6, a.precision()); assertEquals("-1, 0.5, 5 + 6i value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.gegenbauerC(new Apcomplex("-1.00000"), new Apcomplex("-0.500000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-1, -0.5, 5 + 6i precision", 6, a.precision()); assertEquals("-1, -0.5, 5 + 6i value", new Apcomplex("(6.00000,-30.0000)"), a, new Apfloat("5e-4")); a = ApcomplexMath.gegenbauerC(new Apcomplex("-1.00000"), new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-1, 0, 5 + 6i precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, 0, 5 + 6i value", new Apcomplex("0"), a); a = ApcomplexMath.gegenbauerC(new Apcomplex("-1.00000"), new Apcomplex("-1.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-1, -1, 5 + 6i precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, -1, 5 + 6i value", new Apcomplex("0"), a); a = ApcomplexMath.gegenbauerC(new Apcomplex("0"), new Apcomplex("-1.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("0, -1, 5 + 6i precision", 6, a.precision()); assertEquals("0, -1, 5 + 6i value", new Apcomplex("1.00000"), a); a = ApcomplexMath.gegenbauerC(new Apcomplex("0"), new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)")); assertEquals("0, 0, 5 + 6i precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0, 5 + 6i value", new Apcomplex("0"), a); a = ApcomplexMath.gegenbauerC(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2)), new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.5 - 0.75i value", new Apcomplex(new Apfloat("1.0001001011000001011", 18, 2), new Apfloat("-1011.110010001100001", 18, 2)), a, new Apfloat("1e-14", 1, 2)); a = ApcomplexMath.gegenbauerC(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat(0, 18, 2)), new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, 0, 0.5 - 0.75i precision", Apfloat.INFINITE, a.precision()); assertEquals("0.5 + 0.75i, 0, 0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, 0, 0.5 - 0.75i value", new Apfloat(0, 18, 2), a); a = ApcomplexMath.gegenbauerC(new Apcomplex(new Apfloat("0", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2)), new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0, -0.5 - 0.75i, 0.5 - 0.75i precision", 18, a.precision()); assertEquals("0, -0.5 - 0.75i, 0.5 - 0.75i radix", 2, a.radix()); assertEquals("0, -0.5 - 0.75i, 0.5 - 0.75i value", new Apfloat("1", 18, 2), a); a = ApcomplexMath.gegenbauerC(new Apcomplex(new Apfloat("1", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2)), new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("1, -0.5 - 0.75i, 0.5 - 0.75i precision", 18, a.precision()); assertEquals("1, -0.5 - 0.75i, 0.5 - 0.75i radix", 2, a.radix()); assertEquals("1, -0.5 - 0.75i, 0.5 - 0.75i value", new Apfloat("-1.101", 18, 2), a, new Apfloat("1e-17", 1, 2)); a = ApcomplexMath.gegenbauerC(new Apcomplex(new Apfloat("-1", 18, 2)), new Apcomplex(new Apfloat("-1", 18, 2)), new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("-1, -1, 0.5 - 0.75i precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, -1, 0.5 - 0.75i radix", 2, a.radix()); assertEquals("-1, -1, 0.5 - 0.75i value", new Apfloat("0", 18, 2), a); try { ApcomplexMath.gegenbauerC(new Apfloat("0.50"), new Apfloat("-0.25"), new Apfloat(0)); fail("1/2, -1/4, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.gegenbauerC(new Apfloat(-1), new Apfloat(4), new Apfloat(5)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testJacobiP() { Apcomplex a = ApcomplexMath.jacobiP(new Apcomplex("(1.000000,2.000000)"), new Apcomplex("(3.000000,4.000000)"), new Apcomplex("(5.000000,6.000000)"), new Apcomplex("(7.000000,8.000000)")); assertEquals("1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("1 + 2i, 3 + 4i, 5 + 6i, 7 + 8i value", new Apcomplex("(-7.16216,-0.261529)"), a, new Apfloat("5e-5")); a = ApcomplexMath.jacobiP(new Apcomplex("0"), new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)"), new Apcomplex("(7.00000,8.00000)")); assertEquals("0, 3 + 4i, 5 + 6i, 7 + 8i precision", 6, a.precision()); assertEquals("0, 3 + 4i, 5 + 6i, 7 + 8i value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.jacobiP(new Apfloat("1.00000"), new Apfloat("-0.500000"), new Apfloat("1.00000"), new Apfloat("-1.00000")); assertEquals("1, -0.5, 1, -1 precision", 6, a.precision()); assertEquals("1, -0.5, 1, -1 value", new Apcomplex("-2.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.jacobiP(new Apcomplex("-1.00000"), new Apcomplex("-1.00000"), new Apcomplex("-1.00000"), new Apcomplex("(7.00000,8.00000)")); assertEquals("-1, -1, -1, 7 + 8i precision", 6, a.precision()); assertEquals("-1, -1, -1, 7 + 8i value", new Apcomplex("(8.00000,-56.0000)"), a, new Apfloat("5e-4")); a = ApcomplexMath.jacobiP(new Apcomplex(new Apfloat("0.1", 19, 2), new Apfloat("0.11", 19, 2)), new Apcomplex(new Apfloat("-0.1", 19, 2), new Apfloat("-0.11", 19, 2)), new Apcomplex(new Apfloat("0.11", 19, 2), new Apfloat("0.111", 19, 2)), new Apcomplex(new Apfloat("-0.11", 19, 2), new Apfloat("-0.111", 19, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.75 + 0.875i, -0.75 - 0.875i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.75 + 0.875i, -0.75 - 0.875i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i, 0.75 + 0.875i, -0.75 - 0.875i value", new Apcomplex(new Apfloat("110.110101010011100", 18, 2), new Apfloat("-101.00010011100000011", 18, 2)), a, new Apfloat("1e-15", 1, 2)); try { ApcomplexMath.jacobiP(new Apfloat("-0.100000"), new Apfloat("1.00000"), new Apfloat("0"), new Apfloat("-1.00000")); fail("-0.1, 1, 0, -1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.jacobiP(new Apfloat("-0.500000"), new Apfloat("-0.500000"), new Apfloat("1.00000"), new Apfloat("1.00000")); fail("-1/2, -1/2, 1, 1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.jacobiP(new Apfloat(3), new Apfloat(4), new Apfloat(5), new Apfloat(6)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testFibonacci() { Apcomplex a = ApcomplexMath.fibonacci(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(723.269,975.240)"), a, new Apfloat("5e-3")); a = ApcomplexMath.fibonacci(new Apcomplex("(333.00000,444.00000)"), new Apcomplex("(5.00000000,6.00000000)")); assertEquals("333 + 444i, 5 + 6i precision", 4, a.precision()); assertEquals("333 + 444i, 5 + 6i value", new Apcomplex("(3.54e472,3.136e473)"), a, new Apfloat("5e470")); a = ApcomplexMath.fibonacci(new Apcomplex("0"), new Apcomplex("(3.00000,4.00000)")); assertEquals("0, 3 + 4i precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 3 + 4i value", new Apcomplex("0"), a); a = ApcomplexMath.fibonacci(new Apcomplex("1.00000"), new Apcomplex("(3.00000,4.00000)")); assertEquals("1, 3 + 4i precision", 6, a.precision()); assertEquals("1, 3 + 4i value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.fibonacci(new Apcomplex("4.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("4, 5 + 6i precision", 6, a.precision()); assertEquals("4, 5 + 6i value", new Apcomplex("(-405.000,246.000)"), a, new Apfloat("5e-3")); a = ApcomplexMath.fibonacci(new Apcomplex("0"), new Apcomplex("(0,2.00000)")); assertEquals("0, 2i precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 2i value", new Apcomplex("0"), a); a = ApcomplexMath.fibonacci(new Apcomplex("1.00000"), new Apcomplex("(0,2.00000)")); assertEquals("1, 2i precision", 6, a.precision()); assertEquals("1, 2i value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.fibonacci(new Apcomplex("5.00000"), new Apcomplex("(0,2.00000)")); assertEquals("5, 2i precision", 6, a.precision()); assertEquals("5, 2i value", new Apcomplex("5.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.fibonacci(new Apcomplex("3.00000"), new Apcomplex("(0,-2.00000)")); assertEquals("3, -2i precision", 6, a.precision()); assertEquals("3, -2i value", new Apcomplex("-3.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.fibonacci(new Apint(2, 9), new Apcomplex(new Apint(0, 9), new Apint(2, 9))); assertEquals("2, 2i precision radix 9", Apfloat.INFINITE, a.precision()); assertEquals("2, 2i radix radix 9", 9, a.radix()); assertEquals("2, 2i value radix 9", new Apcomplex(new Apint(0, 9), new Apint(2, 9)), a); a = ApcomplexMath.fibonacci(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i value", new Apcomplex(new Apfloat("-0.000111111111101011111111", 18, 2), new Apfloat("1.11110101100110111", 18, 2)), a, new Apfloat("1e-17", 1, 2)); try { ApcomplexMath.fibonacci(new Apfloat("0.500000"), new Apcomplex("(0,2.00000)")); fail("1/2, 2i accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.fibonacci(new Apfloat("0.500000"), new Apcomplex("(0,-2.00000)")); fail("1/2, -2i accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.fibonacci(new Apfloat(3), new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testEulerE() { Apcomplex a = ApcomplexMath.eulerE(4, new Apcomplex("(5.00000,6.00000)")); assertEquals("4, 5 + 6i precision", 6, a.precision()); assertEquals("4, 5 + 6i value", new Apcomplex("(-2644.00,-1782.00)"), a, new Apfloat("5e-2")); a = ApcomplexMath.eulerE(20, new Apcomplex("(5.00000,6.00000)")); assertEquals("20, 5 + 6i precision", 6, a.precision()); assertEquals("20, 5 + 6i value", new Apcomplex("(3.01307e17,1.96228e17)"), a, new Apfloat("5e12")); a = ApcomplexMath.eulerE(200, new Apcomplex("(5.00000,6.00000)")); assertEquals("200, 5 + 6i precision", 6, a.precision()); assertEquals("200, 5 + 6i value", new Apcomplex("(-1.65486e171,-2.86452e283)"), a, new Apfloat("5e278")); a = ApcomplexMath.eulerE(400, new Apcomplex("(5.00000,6.00000)")); assertEquals("400, 5 + 6i precision", 6, a.precision()); assertEquals("400, 5 + 6i value", new Apcomplex("(0,-8.64178e677)"), a, new Apfloat("5e672")); /* Very slow a = ApcomplexMath.eulerE(2000, new Apcomplex("(5.00000,6.00000)")); assertEquals("2000, 5 + 6i precision", 6, a.precision()); assertEquals("2000, 5 + 6i value", new Apcomplex("(0,-1.62571e4749)"), a, new Apfloat("5e4744")); */ a = ApcomplexMath.eulerE(200, new Apcomplex("(5000.00,6000.00)")); assertEquals("200, 5000 + 6000i precision", 6, a.precision()); assertEquals("200, 5000 + 6000i value", new Apcomplex("(2.571446e778,-2.199798e778)"), a, new Apfloat("5e773")); a = ApcomplexMath.eulerE(0, new Apcomplex("(5.00000,6.00000)")); assertEquals("0, 5 + 6i precision", 6, a.precision()); assertEquals("0, 5 + 6i value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.eulerE(0, new Apcomplex("0")); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 value", new Apcomplex("1"), a); a = ApcomplexMath.eulerE(4, new Apcomplex("0")); assertEquals("4, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("4, 0 value", new Apcomplex("0"), a); a = ApcomplexMath.eulerE(4, new Apcomplex("1.00000")); assertEquals("4, 1 precision", Apfloat.INFINITE, a.precision()); assertEquals("4, 1 value", new Apcomplex("0"), a, new Apfloat("5e-2")); a = ApcomplexMath.eulerE(17, new Apcomplex("0")); assertEquals("17, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("17, 0 value", new Aprational("-3202291/2"), a); a = ApcomplexMath.eulerE(17, new Apcomplex("0"), 6); assertEquals("17, 0 precision fixed", 6, a.precision()); assertEquals("17, 0 value fixed", new Apcomplex("-1601145.5"), a, new Apfloat("5e1")); a = ApcomplexMath.eulerE(3, new Apcomplex("-3.00000")); assertEquals("3, -3 precision", 6, a.precision()); assertEquals("3, -3 value", new Apcomplex("-40.2500"), a, new Apfloat("5e-4")); a = ApcomplexMath.eulerE(3, new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2))); assertEquals("3, 0.5 + 0.75i precision", 18, a.precision()); assertEquals("3, 0.5 + 0.75i radix", 2, a.radix()); assertEquals("3, 0.5 + 0.75i value", new Apcomplex(new Apfloat("0", 18, 2), new Apfloat("-0.111111", 18, 2)), a, new Apfloat("1e-18", 1, 2)); a = ApcomplexMath.eulerE(13, new Apint(0, 2)); assertEquals("13, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("13, 0 radix", 2, a.radix()); assertEquals("13, 0 value", new Aprational("-1010101010101/10", 2), a); try { ApcomplexMath.eulerE(-1, new Apcomplex("(1,2)")); fail("-1, 1+ 2i accepted"); } catch (IllegalArgumentException iae) { // OK, n < 0 } } public static void testBernoulliB() { Apcomplex a = ApcomplexMath.bernoulliB(4, new Apcomplex("(5.00000,6.00000)")); assertEquals("4, 5 + 6i precision", 6, a.precision()); assertEquals("4, 5 + 6i value", new Apcomplex("(-2660.03,-1728.00)"), a, new Apfloat("5e-2")); a = ApcomplexMath.bernoulliB(20, new Apcomplex("(5.00000,6.00000)")); assertEquals("20, 5 + 6i precision", 6, a.precision()); assertEquals("20, 5 + 6i value", new Apcomplex("(3.41535e17,-1.04603e16)"), a, new Apfloat("5e12")); a = ApcomplexMath.bernoulliB(200, new Apcomplex("(5.00000,6.00000)")); assertEquals("200, 5 + 6i precision", 6, a.precision()); assertEquals("200, 5 + 6i value", new Apcomplex("(-4.29963e231,7.90526e172)"), a, new Apfloat("5e278")); a = ApcomplexMath.bernoulliB(400, new Apcomplex("(5.00000,6.00000)")); assertEquals("400, 5 + 6i precision", 6, a.precision()); assertEquals("400, 5 + 6i value", new Apcomplex("-8.072036e565"), a, new Apfloat("5e560")); a = ApcomplexMath.bernoulliB(400, new Apcomplex("(5000.00,6000.00)")); assertEquals("400, 5000 + 6000i precision", 6, a.precision()); assertEquals("400, 5000 + 6000i value", new Apcomplex("(1.77260e1556,-1.13133e1557)"), a, new Apfloat("5e1552")); a = ApcomplexMath.bernoulliB(0, new Apcomplex("(5.00000,6.00000)")); assertEquals("0, 5 + 6i precision", 6, a.precision()); assertEquals("0, 5 + 6i value", new Apcomplex("1.00000"), a, new Apfloat("5e-5")); a = ApcomplexMath.bernoulliB(0, new Apcomplex("0")); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 value", new Apcomplex("1"), a); a = ApcomplexMath.bernoulliB(1, new Apcomplex("0")); assertEquals("1, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("1, 0 value", new Aprational("-1/2"), a); a = ApcomplexMath.bernoulliB(3, new Apcomplex("0")); assertEquals("3, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("3, 0 value", new Apcomplex("0"), a); a = ApcomplexMath.bernoulliB(16, new Apcomplex("0")); assertEquals("16, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("16, 0 value", new Aprational("-3617/510"), a); a = ApcomplexMath.bernoulliB(16, new Apcomplex("0"), 6); assertEquals("16, 0 precision fixed", 6, a.precision()); assertEquals("16, 0 value fixed", new Apcomplex("-7.09216"), a, new Apfloat("5e-5")); a = ApcomplexMath.bernoulliB(4, new Apcomplex("-3.00000")); assertEquals("4, -3 precision", 6, a.precision()); assertEquals("4, -3 value", new Apcomplex("143.967"), a, new Apfloat("5e-3")); a = ApcomplexMath.bernoulliB(1, new Apcomplex("-2.00000")); assertEquals("1, -2 precision", 6, a.precision()); assertEquals("1, -2 value", new Apcomplex("-2.50000"), a, new Apfloat("5e-5")); a = ApcomplexMath.bernoulliB(3, new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2))); assertEquals("3, 0.5 + 0.75i precision", 18, a.precision()); assertEquals("3, 0.5 + 0.75i radix", 2, a.radix()); assertEquals("3, 0.5 + 0.75i value", new Apcomplex(new Apfloat("0", 18, 2), new Apfloat("-0.100111", 18, 2)), a, new Apfloat("1e-18", 1, 2)); a = ApcomplexMath.bernoulliB(14, new Apint(0, 2)); assertEquals("14, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("14, 0 radix", 2, a.radix()); assertEquals("14, 0 value", new Aprational("111/110", 2), a); try { ApcomplexMath.bernoulliB(-1, new Apcomplex("(1,2)")); fail("-1, 1+ 2i accepted"); } catch (IllegalArgumentException iae) { // OK, n < 0 } } public static void testHarmonicNumber() { Apcomplex a = ApcomplexMath.harmonicNumber(new Apcomplex("(5.00000,6.00000)")); assertEquals("5 + 6i precision", 6, a.precision()); assertEquals("5 + 6i value", new Apcomplex("(2.67388,0.828222)"), a, new Apfloat("5e-5")); a = ApcomplexMath.harmonicNumber(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apcomplex("0"), a); a = ApcomplexMath.harmonicNumber(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2))); assertEquals("0.5 + 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("0.110011110100010001", 18, 2), new Apfloat("0.1001111010100111111", 18, 2)), a, new Apfloat("1e-18", 1, 2)); try { ApcomplexMath.harmonicNumber(new Apfloat("-1")); fail("-1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } } public static void testHarmonicNumberGeneralized() { Apcomplex a = ApcomplexMath.harmonicNumber(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(0.994430,0.0502165)"), a, new Apfloat("5e-6")); a = ApcomplexMath.harmonicNumber(new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)")); assertEquals("0, 5 + 6i precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 5 + 6i value", new Apcomplex("0"), a); a = ApcomplexMath.harmonicNumber(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("0")); assertEquals("3 + 4i, 0 precision", 6, a.precision()); assertEquals("3 + 4i, 0 value", new Apcomplex("(3.00000,4.00000)"), a, new Apfloat("5e-5")); a = ApcomplexMath.harmonicNumber(new Apcomplex("0"), new Apcomplex("0")); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 value", new Apcomplex("0"), a); a = ApcomplexMath.harmonicNumber(new Apcomplex("-1.00000"), new Apcomplex("-1.00000")); assertEquals("-1, -1 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, -1 value", new Apcomplex("0"), a); a = ApcomplexMath.harmonicNumber(new Apcomplex("-1.00000"), new Apcomplex("(-0.100000,1.00000)")); assertEquals("-1, -0.1 + i precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, -0.1 + i value", new Apcomplex("0"), a); a = ApcomplexMath.harmonicNumber(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("1")); assertEquals("3 + 4i, 1 precision", 6, a.precision()); assertEquals("3 + 4i, 1 value", new Apcomplex("(2.24758,0.850502)"), a, new Apfloat("5e-5")); a = ApcomplexMath.harmonicNumber(new Apcomplex(new Apfloat("0.1", 17, 2), new Apfloat("0.11", 17, 2)), new Apcomplex(new Apfloat("-0.1", 17, 2), new Apfloat("-0.11", 17, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i value", new Apcomplex(new Apfloat("0.0101000011011010011", 18, 2), new Apfloat("0.10000001101100111001", 18, 2)), a, new Apfloat("1e-18", 1, 2)); try { ApcomplexMath.harmonicNumber(new Apfloat("-1.00000"), new Apfloat("1.00000")); fail("-1, 1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.harmonicNumber(new Apfloat("-1.00000"), new Apfloat("1.50000")); fail("-1, 1.5 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } } public static void testPolylog() { Apcomplex a = ApcomplexMath.polylog(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("3 + 4i, 5 + 6i precision", 6, a.precision()); assertEquals("3 + 4i, 5 + 6i value", new Apcomplex("(27.2502,30.5992)"), a, new Apfloat("5e-4")); /* Very slow a = ApcomplexMath.polylog(new Apcomplex("(333.00000,444.00000)"), new Apcomplex("(555.00000,666.00000)")); assertEquals("333 + 444i, 555 + 666i precision", 6, a.precision()); assertEquals("333 + 444i, 555 + 666i value", new Apcomplex("(555.000,666.000)"), a, new Apfloat("5e-3")); */ a = ApcomplexMath.polylog(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("2.00000")); assertEquals("3 + 4i, 2 precision", 6, a.precision()); assertEquals("3 + 4i, 2 value", new Apcomplex("(1.64436,0.0209666)"), a, new Apfloat("5e-5")); a = ApcomplexMath.polylog(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("1.00000")); assertEquals("3 + 4i, 1 precision", 6, a.precision()); assertEquals("3 + 4i, 1 value", new Apcomplex("(0.890555,-0.00807595)"), a, new Apfloat("5e-6")); a = ApcomplexMath.polylog(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("0.500000")); assertEquals("3 + 4i, 0.5 precision", 6, a.precision()); assertEquals("3 + 4i, 0.5 value", new Apcomplex("(0.470416,-0.00634237)"), a, new Apfloat("5e-6")); a = ApcomplexMath.polylog(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(0.500000,0.100000)")); assertEquals("3 + 4i, 0.5 + 0.1i precision", 6, a.precision()); assertEquals("3 + 4i, 0.5 + 0.1i value", new Apcomplex("(0.472997,0.0818064)"), a, new Apfloat("5e-6")); a = ApcomplexMath.polylog(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("(0.500000,-0.100000)")); assertEquals("3 + 4i, 0.5 - 0.1i precision", 6, a.precision()); assertEquals("3 + 4i, 0.5 - 0.1i value", new Apcomplex("(0.469938,-0.0948103)"), a, new Apfloat("5e-6")); a = ApcomplexMath.polylog(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("0")); assertEquals("3 + 4i, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("3 + 4i, 0 value", new Apcomplex("0"), a); a = ApcomplexMath.polylog(new Apcomplex("(3.00000,4.00000)"), new Apcomplex("-0.500000")); assertEquals("3 + 4i, -0.5 precision", 6, a.precision()); assertEquals("3 + 4i, -0.5 value", new Apcomplex("(-0.527181,-0.0150122)"), a, new Apfloat("5e-6")); a = ApcomplexMath.polylog(new Apcomplex("4.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("4, 5 + 6i precision", 6, a.precision()); assertEquals("4, 5 + 6i value", new Apcomplex("(2.35058,7.05471)"), a, new Apfloat("5e-5")); a = ApcomplexMath.polylog(new Apcomplex("1.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("1, 5 + 6i precision", 6, a.precision()); assertEquals("1, 5 + 6i value", new Apcomplex("(-1.97562,2.15880)"), a, new Apfloat("5e-5")); a = ApcomplexMath.polylog(new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)")); assertEquals("0, 5 + 6i precision", 6, a.precision()); assertEquals("0, 5 + 6i value", new Apcomplex("(-1.07692,0.115385)"), a, new Apfloat("5e-5")); a = ApcomplexMath.polylog(new Apcomplex("4.00001"), new Apcomplex("(5.00000,6.00000)")); assertEquals("4.00001, 5 + 6i precision", 6, a.precision()); assertEquals("4.00001, 5 + 6i value", new Apcomplex("(2.35059,7.05471)"), a, new Apfloat("5e-5")); a = ApcomplexMath.polylog(new Apcomplex("2.000000000000000"), new Apcomplex("(9.993319736282411e-1,3.654595031305655e-2)")); assertEquals("2, 9.993319736282411e-1 + 3.654595031305655e-2i precision", 16, a.precision()); assertEquals("2, 9.993319736282411e-1 + 3.654595031305655e-2i value", new Apcomplex("(1.587849086339557,0.1575108716027421)"), a, new Apfloat("5e-15")); a = ApcomplexMath.polylog(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0.5 + 0.75i, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i, -0.5 - 0.75i value", new Apcomplex(new Apfloat("-0.0101111010000111111", 18, 2), new Apfloat("-0.0110110101101011100", 18, 2)), a, new Apfloat("1e-19", 1, 2)); a = ApcomplexMath.polylog(new Apcomplex(new Apfloat("0", 18, 2), new Apfloat("0", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("0, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("0, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("0, -0.5 - 0.75i value", new Apcomplex(new Apfloat("-0.011101110111011101111", 18, 2), new Apfloat("-0.010001000100010001001", 18, 2)), a, new Apfloat("1e-19", 1, 2)); a = ApcomplexMath.polylog(new Apcomplex(new Apfloat("1", 18, 2), new Apfloat("0", 18, 2)), new Apcomplex(new Apfloat("-0.1", 18, 2), new Apfloat("-0.11", 18, 2))); assertEquals("1, -0.5 - 0.75i precision", 18, a.precision()); assertEquals("1, -0.5 - 0.75i radix", 2, a.radix()); assertEquals("1, -0.5 - 0.75i value", new Apcomplex(new Apfloat("-0.100001000101110010", 18, 2), new Apfloat("-0.0111011010110001101", 18, 2)), a, new Apfloat("1e-18", 1, 2)); try { ApcomplexMath.polylog(new Apcomplex("(1.00000,4.00000)"), new Apcomplex("1.00000")); fail("1 + 4i, 1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApcomplexMath.polylog(new Apcomplex("(-3.00000,4.00000)"), new Apcomplex("1.00000")); fail("-3 + 4i, 1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } } public static void testLogisticSigmoid() { Apcomplex a = ApcomplexMath.logisticSigmoid(new Apcomplex(new Apfloat(3, 20), new Apfloat(4, 20))); assertEquals("(3,4), precision", 19, a.precision()); assertEquals("(3,4), value", new Apcomplex("(1.032072199588268518,-0.040195507655084086)"), a, new Apfloat("5e-18")); a = ApcomplexMath.logisticSigmoid(new Apcomplex(new Apfloat(3000, 19), new Apfloat(4, 19))); assertEquals("(3000,4), precision", 19, a.precision()); assertEquals("(3000,4), value", new Apcomplex("1.000000000000000000"), a, new Apfloat("5e-18")); a = ApcomplexMath.logisticSigmoid(new Apcomplex(new Apfloat(-3000, 19), new Apfloat(4, 19))); assertEquals("(-3000,4), precision", 16, a.precision()); assertEquals("(-3000,4), value", new Apcomplex("(-8.54860631834400e-1304,-9.89775832980675e-1304)"), a, new Apfloat("5e-1319")); a = ApcomplexMath.logisticSigmoid(new Apcomplex("(1.000000000000000000e-1000000000000000000,1.000000000000000000e-1000000000000000000)")); assertEquals("(1e-1000000000000000000,1e-1000000000000000000), precision", 19, a.precision()); assertEquals("(1e-1000000000000000000,1e-1000000000000000000), value", new Apcomplex("0.5000000000000000000"), a, new Apfloat("5e-19")); a = ApcomplexMath.logisticSigmoid(new Apcomplex("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Aprational("1/2"), a); a = ApcomplexMath.logisticSigmoid(new Apint(0, 9)); assertEquals("0 radix 9 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 radix 9 radix", 9, a.radix()); assertEquals("0 radix 9 value", new Aprational("1/2", 9), a); a = ApcomplexMath.logisticSigmoid(new Apcomplex(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2))); assertEquals("0.5 + 0.75i precision", 18, a.precision()); assertEquals("0.5 + 0.75i radix", 2, a.radix()); assertEquals("0.5 + 0.75i value", new Apcomplex(new Apfloat("0.1010001111011111101", 18, 2), new Apfloat("0.0010111011101101", 18, 2)), a, new Apfloat("1e-18", 1, 2)); try { ApcomplexMath.logisticSigmoid(new Apcomplex(Apfloat.ZERO, ApfloatMath.pi(25))); fail("i pi accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } } public static void testUlp() { assertEquals("ulp 0", new Apcomplex("0"), ApcomplexMath.ulp(new Apcomplex("0"))); Apfloat a = ApcomplexMath.ulp(new Apcomplex(new Apfloat(1))); assertEquals("ulp 1", new Apfloat("0"), a); assertEquals("ulp 1 precision", Apcomplex.INFINITE, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("1")); assertEquals("ulp 1.", new Apfloat("1"), a); assertEquals("ulp 1. precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("1.0")); assertEquals("ulp 1.0", new Apfloat("0.1"), a); assertEquals("ulp 1.0 precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("1.1")); assertEquals("ulp 1.1", new Apfloat("0.1"), a); assertEquals("ulp 1.1 precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("0.1")); assertEquals("ulp 0.1", new Apfloat("0.1"), a); assertEquals("ulp 0.1 precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("0.2")); assertEquals("ulp 0.2", new Apfloat("0.1"), a); assertEquals("ulp 0.2 precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("10")); assertEquals("ulp 10.", new Apfloat("1"), a); assertEquals("ulp 10. precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("1e1")); assertEquals("ulp 1e1", new Apfloat("1e1"), a); assertEquals("ulp 1e1 precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("-1e1")); assertEquals("ulp -1e1", new Apfloat("1e1"), a); assertEquals("ulp -1e1 precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex(Apfloat.ZERO, new Apfloat("1.a", 2, 11))); assertEquals("ulp (0, 1.a)", new Apfloat("0.1", 1, 11), a); assertEquals("ulp (0, 1.a) precision", 1, a.precision()); assertEquals("ulp (0, 1.a) radix", 11, a.radix()); a = ApcomplexMath.ulp(new Apcomplex("1e-9000000000000000000")); assertEquals("ulp 1e-9000000000000000000", new Apfloat("1e-9000000000000000000"), a); assertEquals("ulp 1e-9000000000000000000 precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex(new Apfloat("1e-9000000000000000000", 9000000000000000000L), new Apfloat("1e-9000000000000000000", 9000000000000000000L))); assertEquals("ulp (1e-9000000000000000000.000, 1e-9000000000000000000.000)", new Apfloat(0), a); assertEquals("ulp (1e-9000000000000000000.000, 1e-9000000000000000000.000) precision", Apcomplex.INFINITE, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("(1.11,-101.1)")); assertEquals("ulp (1.11,-101.1)", new Apfloat("0.1"), a); assertEquals("ulp (1.11,-101.1) precision", 1, a.precision()); a = ApcomplexMath.ulp(new Apcomplex("(-9.9,0.0000011)")); assertEquals("ulp (-9.9,0.0000011)", new Apfloat("0.1"), a); assertEquals("ulp (-9.9,0.0000011) precision", 1, a.precision()); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ApcomplexTest.java000066400000000000000000001330351461767713300252340ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.io.Writer; import java.io.PushbackReader; import java.io.StringReader; import java.io.StringWriter; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; import java.util.Formatter; import java.util.Locale; import junit.framework.TestSuite; /** * @version 1.13.0 * @author Mikko Tommila */ public class ApcomplexTest extends ApfloatTestCase { public ApcomplexTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApcomplexTest("testComparator")); suite.addTest(new ApcomplexTest("testConstructor")); suite.addTest(new ApcomplexTest("testStringConstructor")); suite.addTest(new ApcomplexTest("testStreamConstructor")); suite.addTest(new ApcomplexTest("testComplexMethods")); suite.addTest(new ApcomplexTest("testRadix")); suite.addTest(new ApcomplexTest("testPrecision")); suite.addTest(new ApcomplexTest("testScale")); suite.addTest(new ApcomplexTest("testSize")); suite.addTest(new ApcomplexTest("testIsZero")); suite.addTest(new ApcomplexTest("testIsInteger")); suite.addTest(new ApcomplexTest("testNegate")); suite.addTest(new ApcomplexTest("testAdd")); suite.addTest(new ApcomplexTest("testSubtract")); suite.addTest(new ApcomplexTest("testMultiply")); suite.addTest(new ApcomplexTest("testDivide")); suite.addTest(new ApcomplexTest("testNumberValues")); suite.addTest(new ApcomplexTest("testNumberValuesExact")); suite.addTest(new ApcomplexTest("testEqualDigits")); suite.addTest(new ApcomplexTest("testEquals")); suite.addTest(new ApcomplexTest("testTest")); suite.addTest(new ApcomplexTest("testHashCode")); suite.addTest(new ApcomplexTest("testToString")); suite.addTest(new ApcomplexTest("testWriteTo")); suite.addTest(new ApcomplexTest("testFormatTo")); suite.addTest(new ApcomplexTest("testSerialization")); return suite; } public static void testComparator() { assertEquals("REAL_IMAG 1 compare 2", -1, Apcomplex.REAL_IMAG_ORDER.compare(new Apcomplex("1"), new Apcomplex("2"))); assertEquals("REAL_IMAG 2 compare 2", 0, Apcomplex.REAL_IMAG_ORDER.compare(new Apcomplex("2"), new Apcomplex("2"))); assertEquals("REAL_IMAG 2 compare 1", 1, Apcomplex.REAL_IMAG_ORDER.compare(new Apcomplex("2"), new Apcomplex("1"))); assertEquals("REAL_IMAG (1, 2) compare (2, 1)", -1, Apcomplex.REAL_IMAG_ORDER.compare(new Apcomplex("(1,2)"), new Apcomplex("(2,1)"))); assertEquals("REAL_IMAG (2, 1) compare (2, 2)", -1, Apcomplex.REAL_IMAG_ORDER.compare(new Apcomplex("(2,1)"), new Apcomplex("(2,2)"))); assertEquals("REAL_IMAG (2, 2) compare (2, 2)", 0, Apcomplex.REAL_IMAG_ORDER.compare(new Apcomplex("(2,2)"), new Apcomplex("(2,2)"))); assertEquals("REAL_IMAG (2, 2) compare (2, 1)", 1, Apcomplex.REAL_IMAG_ORDER.compare(new Apcomplex("(2,2)"), new Apcomplex("(2,1)"))); assertEquals("REAL_IMAG (2, -2) compare (2, 1)", -1, Apcomplex.REAL_IMAG_ORDER.compare(new Apcomplex("(2,-2)"), new Apcomplex("(2,1)"))); assertEquals("REAL_IMAG (2, -2) compare (2, 2)", -1, Apcomplex.REAL_IMAG_ORDER.compare(new Apcomplex("(2,-2)"), new Apcomplex("(2,2)"))); assertEquals("REAL_ABS_IMAG 1 compare 2", -1, Apcomplex.REAL_ABS_IMAG_ORDER.compare(new Apcomplex("1"), new Apcomplex("2"))); assertEquals("REAL_ABS_IMAG 2 compare 2", 0, Apcomplex.REAL_ABS_IMAG_ORDER.compare(new Apcomplex("2"), new Apcomplex("2"))); assertEquals("REAL_ABS_IMAG 2 compare 1", 1, Apcomplex.REAL_ABS_IMAG_ORDER.compare(new Apcomplex("2"), new Apcomplex("1"))); assertEquals("REAL_ABS_IMAG (1, 2) compare (2, 1)", -1, Apcomplex.REAL_ABS_IMAG_ORDER.compare(new Apcomplex("(1,2)"), new Apcomplex("(2,1)"))); assertEquals("REAL_ABS_IMAG (2, 1) compare (2, 2)", -1, Apcomplex.REAL_ABS_IMAG_ORDER.compare(new Apcomplex("(2,1)"), new Apcomplex("(2,2)"))); assertEquals("REAL_ABS_IMAG (2, 2) compare (2, 2)", 0, Apcomplex.REAL_ABS_IMAG_ORDER.compare(new Apcomplex("(2,2)"), new Apcomplex("(2,2)"))); assertEquals("REAL_ABS_IMAG (2, 2) compare (2, 1)", 1, Apcomplex.REAL_ABS_IMAG_ORDER.compare(new Apcomplex("(2,2)"), new Apcomplex("(2,1)"))); assertEquals("REAL_ABS_IMAG (2, -2) compare (2, 1)", 1, Apcomplex.REAL_ABS_IMAG_ORDER.compare(new Apcomplex("(2,-2)"), new Apcomplex("(2,1)"))); assertEquals("REAL_ABS_IMAG (2, -2) compare (2, 2)", -1, Apcomplex.REAL_ABS_IMAG_ORDER.compare(new Apcomplex("(2,-2)"), new Apcomplex("(2,2)"))); } public static void testConstructor() { Apcomplex a = new Apcomplex(new Apfloat(5)); assertEquals("5 radix", 10, a.radix()); assertEquals("5 precision", Apfloat.INFINITE, a.precision()); assertEquals("5 String", "5", a.toString(true)); a = new Apcomplex(new Apfloat(5, Apfloat.DEFAULT, 12), new Apfloat(7, Apfloat.DEFAULT, 12)); assertEquals("(5, 7) radix", 12, a.radix()); assertEquals("(5, 7) precision", Apfloat.INFINITE, a.precision()); assertEquals("(5, 7) String", "(5, 7)", a.toString(true)); a = new Apcomplex(new Apfloat(7, Apfloat.DEFAULT, 12)); assertEquals("7 imag radix", 12, a.imag().radix()); assertEquals("7 precision", Apfloat.INFINITE, a.precision()); assertEquals("7 String", "7", a.toString(true)); a = new Apcomplex(new Apfloat(0, Apfloat.DEFAULT, 11), new Apfloat(7, Apfloat.DEFAULT, 12)); a = new Apcomplex(new Apfloat(7, Apfloat.DEFAULT, 11), new Apfloat(0, Apfloat.DEFAULT, 12)); try { a = new Apcomplex(new Apfloat(5, Apfloat.DEFAULT, 11), new Apfloat(7, Apfloat.DEFAULT, 12)); fail("Different radixes accepted"); } catch (IllegalArgumentException iae) { // OK: different radixes } } public static void testStringConstructor() { Apcomplex a = new Apcomplex("5"); assertEquals("5 String", "5", a.toString(true)); a = new Apcomplex("(5)"); assertEquals("(5) String", "5", a.toString(true)); a = new Apcomplex("( 5 )"); assertEquals("( 5 ) String", "5", a.toString(true)); a = new Apcomplex("(5,7)"); assertEquals("(5,7) String", "(5, 7)", a.toString(true)); a = new Apcomplex("( 5 , 7 )"); assertEquals("( 5 , 7 ) String", "(5, 7)", a.toString(true)); ApfloatContext.getContext().setDefaultRadix(12); a = new Apcomplex("(5)"); assertEquals("(5) imag radix", 12, a.imag().radix()); a = new Apcomplex("5"); assertEquals("5 imag radix", 12, a.imag().radix()); ApfloatContext.getContext().setDefaultRadix(10); try { a = new Apcomplex("(3,4"); fail("Missing end parenthesis accepted"); } catch (NumberFormatException nfe) { // OK: missing end parenthesis } } public static void testStreamConstructor() throws IOException { PushbackReader in = new PushbackReader(new StringReader("5")); Apcomplex a = new Apcomplex(in); assertEquals("5 String", "5", a.toString(true)); in = new PushbackReader(new StringReader("(5)")); a = new Apcomplex(in); assertEquals("(5) String", "5", a.toString(true)); in = new PushbackReader(new StringReader("( 5 )")); a = new Apcomplex(in); assertEquals("( 5 ) String", "5", a.toString(true)); in = new PushbackReader(new StringReader("(5,7)")); a = new Apcomplex(in); assertEquals("(5,7) String", "(5, 7)", a.toString(true)); in = new PushbackReader(new StringReader("( 5 , 7 )")); a = new Apcomplex(in); assertEquals("( 5 , 7 ) String", "(5, 7)", a.toString(true)); ApfloatContext.getContext().setDefaultRadix(12); in = new PushbackReader(new StringReader("(5)")); a = new Apcomplex(in); assertEquals("(5) imag radix", 12, a.imag().radix()); in = new PushbackReader(new StringReader("5")); a = new Apcomplex(in); assertEquals("5 imag radix", 12, a.imag().radix()); ApfloatContext.getContext().setDefaultRadix(10); try { a = new Apcomplex(new PushbackReader(new StringReader("(3,4"))); fail("Missing end parenthesis accepted"); } catch (NumberFormatException nfe) { // OK: missing end parenthesis } } public static void testComplexMethods() { Apcomplex a = new Apcomplex("(5, 7)"); assertEquals("real", new Apfloat(5), a.real()); assertEquals("imag", new Apfloat(7), a.imag()); assertEquals("conj", new Apcomplex("(5, -7)"), a.conj()); } public static void testRadix() { Apcomplex a = new Apcomplex(new Apfloat(2, 500, 5)); assertEquals("radix 5", 5, a.radix()); a = new Apcomplex(new Apfloat(2, 500, 6), new Apfloat(0, 500, 5)); assertEquals("radix 6", 6, a.radix()); a = new Apcomplex(new Apfloat(0, 500, 6), new Apfloat(2, 500, 7)); assertEquals("radix 7", 7, a.radix()); a = new Apcomplex(new Apfloat(0, 500, 8), new Apfloat(0, 500, 7)); assertEquals("radix 8", 8, a.radix()); a = new Apcomplex("(16,32)"); assertEquals("10 -> 16", new Apcomplex(new Apfloat("10", 2, 16), new Apfloat("20", 2, 16)), a.toRadix(16)); } public static void testPrecision() { Apcomplex a = new Apcomplex("(1, 1)"); assertEquals("(1, 1) precision", 1, a.precision()); a = new Apcomplex("(1, 10)"); assertEquals("(1, 10) precision", 2, a.precision()); a = new Apcomplex("(10, 1)"); assertEquals("(10, 1) precision", 2, a.precision()); a = new Apcomplex(new Apfloat(1), new Apfloat("1")); assertEquals("(1, 1.) precision", 1, a.precision()); a = new Apcomplex(new Apfloat("1"), new Apfloat(1)); assertEquals("(1., 1) precision", 1, a.precision()); a = new Apcomplex(new Apfloat(1), new Apfloat(1)); assertEquals("(infinite, infinite) -> 5", 5, a.precision(5).precision()); assertEquals("(infinite, infinite) -> 5 real", 5, a.precision(5).real().precision()); assertEquals("(infinite, infinite) -> 5 imag", 5, a.precision(5).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(1, 5)); assertEquals("(5, 5) -> infinite", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).precision()); assertEquals("(5, 5) -> infinite real", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).real().precision()); assertEquals("(5, 5) -> infinite imag", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).imag().precision()); a = new Apcomplex(new Apfloat(1), new Apfloat(1, 10)); assertEquals("(infinite, 10) -> 5", 5, a.precision(5).precision()); assertEquals("(infinite, 10) -> 5 real", 5, a.precision(5).real().precision()); assertEquals("(infinite, 10) -> 5 imag", 5, a.precision(5).imag().precision()); a = new Apcomplex(new Apfloat(1), new Apfloat(1, 5)); assertEquals("(infinite, 5) -> 10", 10, a.precision(10).precision()); assertEquals("(infinite, 5) -> 10 real", 10, a.precision(10).real().precision()); assertEquals("(infinite, 5) -> 10 imag", 10, a.precision(10).imag().precision()); a = new Apcomplex(new Apfloat(1, 10), new Apfloat(1)); assertEquals("(10, infinite) -> 5", 5, a.precision(5).precision()); assertEquals("(10, infinite) -> 5 real", 5, a.precision(5).real().precision()); assertEquals("(10, infinite) -> 5 imag", 5, a.precision(5).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(1)); assertEquals("(5, infinite) -> 10", 10, a.precision(10).precision()); assertEquals("(5, infinite) -> 10 real", 10, a.precision(10).real().precision()); assertEquals("(5, infinite) -> 10 imag", 10, a.precision(10).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(10, 6)); assertEquals("(5, 6) -> 10", 10, a.precision(10).precision()); assertEquals("(5, 6) -> 10 real", 9, a.precision(10).real().precision()); assertEquals("(5, 6) -> 10 imag", 10, a.precision(10).imag().precision()); a = new Apcomplex(new Apfloat(10, 6), new Apfloat(1, 5)); assertEquals("(6, 5) -> 10", 10, a.precision(10).precision()); assertEquals("(6, 5) -> 10 real", 10, a.precision(10).real().precision()); assertEquals("(6, 5) -> 10 imag", 9, a.precision(10).imag().precision()); a = new Apcomplex(new Apfloat(1, 10), new Apfloat(10, 11)); assertEquals("(10, 11) -> 5", 5, a.precision(5).precision()); assertEquals("(10, 11) -> 5 real", 4, a.precision(5).real().precision()); assertEquals("(10, 11) -> 5 imag", 5, a.precision(5).imag().precision()); a = new Apcomplex(new Apfloat(10, 11), new Apfloat(1, 10)); assertEquals("(11, 10) -> 5", 5, a.precision(5).precision()); assertEquals("(11, 10) -> 5 real", 5, a.precision(5).real().precision()); assertEquals("(11, 10) -> 5 imag", 4, a.precision(5).imag().precision()); a = new Apcomplex(new Apfloat(1), new Apfloat(1, 5)); assertEquals("(infinite, 5) -> infinite", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).precision()); assertEquals("(infinite, 5) -> infinite real", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).real().precision()); assertEquals("(infinite, 5) -> infinite imag", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(1)); assertEquals("(5, infinite) -> infinite", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).precision()); assertEquals("(5, infinite) -> infinite real", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).real().precision()); assertEquals("(5, infinite) -> infinite imag", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(1, 5)); assertEquals("(5, 5) -> infinite", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).precision()); assertEquals("(5, 5) -> infinite real", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).real().precision()); assertEquals("(5, 5) -> infinite imag", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(10, 6)); assertEquals("(5, 6) -> infinite", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).precision()); assertEquals("(5, 6) -> infinite real", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).real().precision()); assertEquals("(5, 6) -> infinite imag", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).imag().precision()); a = new Apcomplex(new Apfloat(10, 6), new Apfloat(1, 5)); assertEquals("(6, 5) -> infinite", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).precision()); assertEquals("(6, 5) -> infinite real", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).real().precision()); assertEquals("(6, 5) -> infinite imag", Apcomplex.INFINITE, a.precision(Apcomplex.INFINITE).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(1, 5)); assertEquals("(5, 5) -> 5", 5, a.precision(5).precision()); assertEquals("(5, 5) -> 5 real", 5, a.precision(5).real().precision()); assertEquals("(5, 5) -> 5 imag", 5, a.precision(5).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(10, 6)); assertEquals("(5, 6) -> 6", 6, a.precision(6).precision()); assertEquals("(5, 6) -> 6 real", 5, a.precision(6).real().precision()); assertEquals("(5, 6) -> 6 imag", 6, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(10, 6), new Apfloat(1, 5)); assertEquals("(6, 5) -> 6", 6, a.precision(6).precision()); assertEquals("(6, 5) -> 6 real", 6, a.precision(6).real().precision()); assertEquals("(6, 5) -> 6 imag", 5, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(10), new Apfloat(1)); assertEquals("(10/inf, 1/inf) -> 6 value", new Apcomplex(new Apfloat(10), new Apfloat(1)), a.precision(6)); assertEquals("(10/inf, 1/inf) -> 6", 6, a.precision(6).precision()); assertEquals("(10/inf, 1/inf) -> 6 real", 6, a.precision(6).real().precision()); assertEquals("(10/inf, 1/inf) -> 6 imag", 5, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(1), new Apfloat(10)); assertEquals("(1/inf, 10/inf) -> 6 value", new Apcomplex(new Apfloat(1), new Apfloat(10)), a.precision(6)); assertEquals("(1/inf, 10/inf) -> 6", 6, a.precision(6).precision()); assertEquals("(1/inf, 10/inf) -> 6 real", 5, a.precision(6).real().precision()); assertEquals("(1/inf, 10/inf) -> 6 imag", 6, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(10), new Apfloat(1, 5)); assertEquals("(10/inf, 1/5) -> 6 value", new Apcomplex(new Apfloat(10), new Apfloat(1)), a.precision(6)); assertEquals("(10/inf, 1/5) -> 6", 6, a.precision(6).precision()); assertEquals("(10/inf, 1/5) -> 6 real", 6, a.precision(6).real().precision()); assertEquals("(10/inf, 1/5) -> 6 imag", 5, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(10)); assertEquals("(1/5, 10/inf) -> 6 value", new Apcomplex(new Apfloat(1), new Apfloat(10)), a.precision(6)); assertEquals("(1/5, 10/inf) -> 6", 6, a.precision(6).precision()); assertEquals("(1/5, 10/inf) -> 6 real", 5, a.precision(6).real().precision()); assertEquals("(1/5, 10/inf) -> 6 imag", 6, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(10, 10), new Apfloat(1, 5)); assertEquals("(10/10, 1/5) -> 6 value", new Apcomplex(new Apfloat(10), new Apfloat(1)), a.precision(6)); assertEquals("(10/10, 1/5) -> 6", 6, a.precision(6).precision()); assertEquals("(10/10, 1/5) -> 6 real", 6, a.precision(6).real().precision()); assertEquals("(10/10, 1/5) -> 6 imag", 5, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(1, 5), new Apfloat(10, 10)); assertEquals("(1/5, 10/10) -> 6 value", new Apcomplex(new Apfloat(1), new Apfloat(10)), a.precision(6)); assertEquals("(1/5, 10/10) -> 6", 6, a.precision(6).precision()); assertEquals("(1/5, 10/10) -> 6 real", 5, a.precision(6).real().precision()); assertEquals("(1/5, 10/10) -> 6 imag", 6, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(10, 6), new Apfloat(1)); assertEquals("(10/6, 1/inf) -> 6 value", new Apcomplex(new Apfloat(10), new Apfloat(1)), a.precision(6)); assertEquals("(10/6, 1/inf) -> 6", 6, a.precision(6).precision()); assertEquals("(10/6, 1/inf) -> 6 real", 6, a.precision(6).real().precision()); assertEquals("(10/6, 1/inf) -> 6 imag", 5, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(1), new Apfloat(10, 6)); assertEquals("(1/inf, 10/6) -> 6 value", new Apcomplex(new Apfloat(1), new Apfloat(10)), a.precision(6)); assertEquals("(1/inf, 10/6) -> 6", 6, a.precision(6).precision()); assertEquals("(1/inf, 10/6) -> 6 real", 5, a.precision(6).real().precision()); assertEquals("(1/inf, 10/6) -> 6 imag", 6, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(10, 6), new Apfloat(1, 10)); assertEquals("(10/6, 1/10) -> 6 value", new Apcomplex(new Apfloat(10), new Apfloat(1)), a.precision(6)); assertEquals("(10/6, 1/10) -> 6", 6, a.precision(6).precision()); assertEquals("(10/6, 1/10) -> 6 real", 6, a.precision(6).real().precision()); assertEquals("(10/6, 1/10) -> 6 imag", 5, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(1, 10), new Apfloat(10, 6)); assertEquals("(1/10, 10/6) -> 6 value", new Apcomplex(new Apfloat(1), new Apfloat(10)), a.precision(6)); assertEquals("(1/10, 10/6) -> 6", 6, a.precision(6).precision()); assertEquals("(1/10, 10/6) -> 6 real", 5, a.precision(6).real().precision()); assertEquals("(1/10, 10/6) -> 6 imag", 6, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(10), new Apfloat(0)); assertEquals("(10, 0) -> 6 value", new Apcomplex(new Apfloat(10), new Apfloat(0)), a.precision(6)); assertEquals("(10, 0) -> 6", 6, a.precision(6).precision()); assertEquals("(10, 0) -> 6 real", 6, a.precision(6).real().precision()); a = new Apcomplex(new Apfloat(0), new Apfloat(10)); assertEquals("(0, 10) -> 6 value", new Apcomplex(new Apfloat(0), new Apfloat(10)), a.precision(6)); assertEquals("(0, 10) -> 6", 6, a.precision(6).precision()); assertEquals("(0, 10) -> 6 imag", 6, a.precision(6).imag().precision()); a = new Apcomplex(new Apfloat(100000), new Apfloat(1)); assertEquals("(100000, 1) -> 6 value", new Apcomplex(new Apfloat(100000), new Apfloat(1)), a.precision(6)); a = new Apcomplex(new Apfloat(1), new Apfloat(100000)); assertEquals("(1, 100000) -> 6 value", new Apcomplex(new Apfloat(1), new Apfloat(100000)), a.precision(6)); a = new Apcomplex(new Apfloat(1000000), new Apfloat(1)); assertEquals("(1000000, 1) -> 6 value", new Apcomplex(new Apfloat(1000000), new Apfloat(0)), a.precision(6)); a = new Apcomplex(new Apfloat(1), new Apfloat(1000000)); assertEquals("(1, 1000000) -> 6 value", new Apcomplex(new Apfloat(0), new Apfloat(1000000)), a.precision(6)); a = new Apcomplex(new Apfloat(0), new Apfloat(0)); assertEquals("(0, 0) -> 6 value", new Apcomplex(new Apfloat(0), new Apfloat(0)), a.precision(6)); a = new Apcomplex(new Apfloat("1", 1, 12), new Apfloat("10", 2, 12)); assertEquals("(1, 10) -> 1 value", new Apcomplex(Apfloat.ZERO, new Apfloat("10", 1, 12)), a.precision(1)); assertEquals("(1, 10) -> 1 real radix", 12, a.precision(1).real().radix()); a = new Apcomplex(new Apfloat("10", 2, 12), new Apfloat("1", 1, 12)); assertEquals("(10, 1) -> 1 value", new Apcomplex(new Apfloat("10", 1, 12), Apfloat.ZERO), a.precision(1)); assertEquals("(10, 1) -> 1 imag radix", 12, a.precision(1).imag().radix()); } public static void testNegate() { Apcomplex z = new Apcomplex("(2,3)"); assertEquals("(2,3)", new Apcomplex("(-2,-3)"), z.negate()); z = new Apcomplex("0"); assertEquals("0", new Apcomplex("0"), z.negate()); } public static void testScale() { Apcomplex a = new Apcomplex("(1, 1)"); assertEquals("(1, 1) scale", 1, a.scale()); a = new Apcomplex("(1, 10)"); assertEquals("(1, 10) scale", 2, a.scale()); a = new Apcomplex("(0, 10)"); assertEquals("(0, 10) scale", 2, a.scale()); a = new Apcomplex("(10, 0)"); assertEquals("(10, 0) scale", 2, a.scale()); a = new Apcomplex("0"); assertEquals("0 scale", -Apfloat.INFINITE, a.scale()); } public static void testSize() { Apcomplex a = new Apcomplex("(1, 1)"); assertEquals("(1, 1) size", 1, a.size()); a = new Apcomplex("(1, 11)"); assertEquals("(1, 11) size", 2, a.size()); a = new Apcomplex("(0, 10)"); assertEquals("(0, 10) size", 1, a.size()); a = new Apcomplex("(10, 0)"); assertEquals("(10, 0) size", 1, a.size()); a = new Apcomplex("0"); assertEquals("0 size", 0, a.size()); } public static void testIsZero() { Apcomplex a = new Apcomplex("(1, 1)"); assertFalse("(1, 1)", a.isZero()); a = new Apcomplex("(1.5, 0)"); assertFalse("(1.5, 0)", a.isZero()); a = new Apcomplex("(0, 1)"); assertFalse("(0, 1)", a.isZero()); a = new Apcomplex("0"); assertTrue("0", a.isZero()); } public static void testIsInteger() { Apcomplex a = new Apcomplex("(1, 1)"); assertFalse("(1, 1)", a.isInteger()); a = new Apcomplex("(1.5, 0)"); assertFalse("(1.5, 0)", a.isInteger()); a = new Apcomplex("(1, 0)"); assertTrue("(1, 0)", a.isInteger()); } public static void testAdd() { Apcomplex a = new Apcomplex("(2, 3)"), b = new Apcomplex("(4, 5)"); assertEquals("(2, 3) + (4, 5) precision", 1, a.add(b).precision()); assertEquals("(2, 3) + (4, 5) value", new Apcomplex("(6, 8)"), a.add(b)); } public static void testSubtract() { Apcomplex a = new Apcomplex("(2, 3)"), b = new Apcomplex("(4, 1)"); assertEquals("(2, 3) - (4, 1) precision", 1, a.subtract(b).precision()); assertEquals("(2, 3) - (4, 1) value", new Apcomplex("(-2, 2)"), a.subtract(b)); } public static void testMultiply() { Apcomplex a = new Apcomplex("(2.0, 3.0)"), b = new Apcomplex("(4.0, 5.0)"); assertEquals("(2, 3) * (4, 5) precision", 2, a.multiply(b).precision()); assertEquals("(2, 3) * (4, 5) value", new Apcomplex("(-7, 22)"), a.multiply(b)); a = new Apcomplex(new Apfloat(2, 50), new Apfloat("3e10", 100)); b = new Apcomplex(new Apfloat("3e20", 100), new Apfloat(5, 50)); assertEquals("a precision", 60, a.precision()); assertEquals("b precision", 70, b.precision()); assertEquals("(2, 3e10) * (3e20, 5) precision", 60, a.multiply(b).precision()); assertEquals("(2, 3e10) * (3e20, 5) value", new Apcomplex("(599999999850000000000, 9000000000000000000000000000010)"), a.multiply(b)); } public static void testDivide() { Apcomplex a = new Apcomplex("(-7,22)"), b = new Apcomplex("(2.0,3.0)"); assertEquals("(-7,22) / (2,3) precision", 2, a.divide(b).precision()); assertEquals("(-7,22) / (2,3) value", new Apcomplex("(4,5)"), a.divide(b)); assertEquals("0 / (2,3)", new Apcomplex("0"), new Apcomplex("0").divide(b)); assertEquals("(2,3) / 1 precision", 1, b.divide(new Apcomplex("1")).precision()); assertEquals("(2,3) / 1 value", new Apcomplex("(2,3)"), b.divide(new Apcomplex("1"))); assertEquals("(2,3) / i precision", 1, b.divide(new Apcomplex("(0,1)")).precision()); assertEquals("(2,3) / i value", new Apcomplex("(3,-2)"), b.divide(new Apcomplex("(0,1)"))); assertEquals("(6,8) / 2 precision", 1, new Apcomplex("(6,8)").divide(new Apcomplex("2")).precision()); assertEquals("(6,8) / 2 value", new Apcomplex("(3,4)"), new Apcomplex("(6,8)").divide(new Apcomplex("2"))); assertEquals("(6,8) / 2i precision", 1, new Apcomplex("(6,8)").divide(new Apcomplex("(0,2)")).precision()); assertEquals("(6,8) / 2i value", new Apcomplex("(4,-3)"), new Apcomplex("(6,8)").divide(new Apcomplex("(0,2)"))); assertEquals("8 / 4 precision", 1, new Apcomplex("8").divide(new Apcomplex("4")).precision()); assertEquals("8 / 4 value", new Apcomplex("2"), new Apcomplex("8").divide(new Apcomplex("4"))); a = new Apcomplex("(202020202020202020202,303030303030303030303)"); b = new Apcomplex("(0,101010101010101010101)"); assertEquals("(202020202020202020202,303030303030303030303) / 101010101010101010101i precision", 21, a.divide(b).precision()); assertEquals("(202020202020202020202,303030303030303030303) / 101010101010101010101i value", new Apcomplex("(3.00000000000000000000,-2.00000000000000000000)"), a.divide(b), new Apfloat("0.00000000000000000001")); a = new Apcomplex("(606060606060606060606,808080808080808080808)"); b = new Apcomplex("202020202020202020202"); assertEquals("(606060606060606060606,808080808080808080808) / 202020202020202020202 precision", 21, a.divide(b).precision()); assertEquals("(606060606060606060606,808080808080808080808) / 202020202020202020202 value", new Apcomplex("(3.00000000000000000000,4.00000000000000000000)"), a.divide(b), new Apfloat("0.00000000000000000001")); b = new Apcomplex("(0,202020202020202020202)"); assertEquals("(606060606060606060606,808080808080808080808) / 202020202020202020202i precision", 21, a.divide(b).precision()); assertEquals("(606060606060606060606,808080808080808080808) / 202020202020202020202i value", new Apcomplex("(4.00000000000000000000,-3.00000000000000000000)"), a.divide(b), new Apfloat("0.00000000000000000001")); a = new Apcomplex("(-6172839504938271605,12345679009876543210)"); b = new Apcomplex("(3333333333,4444444444)"); assertEquals("(-6172839504938271605,12345679009876543210) / (3333333333,4444444444) precision", 10, a.divide(b).precision()); assertEquals("(-6172839504938271605,12345679009876543210) / (3333333333,4444444444) value", new Apcomplex("(1111111111,2222222222)"), a.divide(b), new Apfloat(1)); a = new Apcomplex("(-6172839504938271605,12345679009876543210)"); b = new Apcomplex("(3333333333.0000000000,4444444444.0000000000)"); assertEquals("(-6172839504938271605,12345679009876543210) / (3333333333.0000000000,4444444444.0000000000) precision", 20, a.divide(b).precision()); assertEquals("(-6172839504938271605,12345679009876543210) / (3333333333.0000000000,4444444444.0000000000) value", new Apcomplex("(1111111111.0000000000,2222222222.0000000000)"), a.divide(b), new Apfloat("0.0000000001")); try { a.divide(new Apcomplex("0")); fail("Division by zero allowed"); } catch (ArithmeticException ae) { // OK: division by zero } } public static void testNumberValues() { Apcomplex a = new Apcomplex("(5,6)"); assertEquals("5 longValue", 5, a.longValue()); assertEquals("5 intValue", 5, a.intValue()); assertEquals("5 shortValue", 5, a.shortValue()); assertEquals("5 byteValue", 5, a.byteValue()); assertEquals("5 doubleValue", 5.0, a.doubleValue(), 0.0); assertEquals("5 floatValue", 5.0f, a.floatValue(), 0.0f); } public static void testNumberValuesExact() { Apcomplex a = new Apcomplex("5"); assertEquals("5 longValueExact", 5, a.longValueExact()); assertEquals("5 intValueExact", 5, a.intValueExact()); assertEquals("5 shortValueExact", 5, a.shortValueExact()); assertEquals("5 byteValueExact", 5, a.byteValueExact()); a = new Apcomplex("-5"); assertEquals("-5 longValueExact", -5, a.longValueExact()); assertEquals("-5 intValueExact", -5, a.intValueExact()); assertEquals("-5 shortValueExact", -5, a.shortValueExact()); assertEquals("-5 byteValueExact", -5, a.byteValueExact()); try { new Apcomplex("5.5").longValueExact(); fail("Non-integer number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apcomplex("5.5").intValueExact(); fail("Non-integer number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apcomplex("5.5").shortValueExact(); fail("Non-integer number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apcomplex("5.5").byteValueExact(); fail("Non-integer number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apcomplex("(5,6)").longValueExact(); fail("Nonreal number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apcomplex("(5,6)").intValueExact(); fail("Nonreal number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apcomplex("(5,6)").shortValueExact(); fail("Nonreal number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apcomplex("(5,6)").byteValueExact(); fail("Nonreal number accepted"); } catch (ArithmeticException ae) { // OK } } public static void testEqualDigits() { Apcomplex a = new Apcomplex("(5,6)"), b = new Apcomplex("(6,6)"); assertEquals("(5,6) eq (6,6)", 0, a.equalDigits(b)); a = new Apcomplex("(6,5)"); b = new Apcomplex("(6,6)"); assertEquals("(6,5) eq (6,6)", 0, a.equalDigits(b)); a = new Apcomplex("(10,11)"); b = new Apcomplex("(11,12)"); assertEquals("(10,11) eq (11,12)", 1, a.equalDigits(b)); a = new Apcomplex("(10,11)"); b = new Apcomplex("(10,12)"); assertEquals("(10,11) eq (10,12)", 1, a.equalDigits(b)); a = new Apcomplex("(10,12)"); b = new Apcomplex("(11,12)"); assertEquals("(10,12) eq (11,12)", 1, a.equalDigits(b)); a = new Apcomplex("(10,11)"); b = new Apcomplex("(10,11)"); assertEquals("(10,11) eq (10,11)", 2, a.equalDigits(b)); a = new Apcomplex(new Apfloat(10), new Apfloat(11)); b = new Apcomplex(new Apfloat(10),new Apfloat(11)); assertEquals("(10,11) eq (10,11) infinite", Apfloat.INFINITE, a.equalDigits(b)); a = new Apcomplex("0"); b = new Apcomplex("0"); assertEquals("0 eq 0", Apfloat.INFINITE, a.equalDigits(b)); a = new Apcomplex("0"); b = new Apcomplex("1"); assertEquals("0 eq 1", 0, a.equalDigits(b)); a = new Apcomplex("1"); b = new Apcomplex("0"); assertEquals("1 eq 0", 0, a.equalDigits(b)); a = new Apcomplex("0"); b = new Apcomplex("(0,1)"); assertEquals("0 eq i", 0, a.equalDigits(b)); a = new Apcomplex("(0,1)"); b = new Apcomplex("0"); assertEquals("i eq 0", 0, a.equalDigits(b)); a = new Apcomplex("(1000,100)"); b = new Apcomplex("(1000,100)"); assertEquals("(1000,100) eq (1000,100)", 4, a.equalDigits(b)); a = new Apcomplex(new Apfloat(1000), new Apfloat(100)); b = new Apcomplex(new Apfloat(1000), new Apfloat(100)); assertEquals("(1000,100) eq (1000,100) infinite", Apfloat.INFINITE, a.equalDigits(b)); a = new Apcomplex("(1000,100)"); b = new Apcomplex("(1000,101)"); assertEquals("(1000,100) eq (1000,101)", 3, a.equalDigits(b)); a = new Apcomplex("(1000,0)"); b = new Apcomplex("(1000,100)"); assertEquals("(1000,0) eq (1000,100)", 1, a.equalDigits(b)); a = new Apcomplex("(1000,1)"); b = new Apcomplex("(1000,0)"); assertEquals("(1000,1) eq (1000,0)", 3, a.equalDigits(b)); a = new Apcomplex("(0.01000,0.00100)"); b = new Apcomplex("(0.01000,0.00100)"); assertEquals("(0.01000,0.00100) eq (0.01000,0.00100)", 4, a.equalDigits(b)); a = new Apcomplex(new Apfloat("0.01000", Apfloat.INFINITE), new Apfloat("0.00100", Apfloat.INFINITE)); b = new Apcomplex(new Apfloat("0.01000", Apfloat.INFINITE), new Apfloat("0.00100", Apfloat.INFINITE)); assertEquals("(0.01000,0.00100) eq (0.01000,0.00100) infinite", Apfloat.INFINITE, a.equalDigits(b)); a = new Apcomplex("(0.01000,0.00100)"); b = new Apcomplex("(0.01000,0.00101)"); assertEquals("(0.01000,0.00100) eq (0.01000,0.00101)", 3, a.equalDigits(b)); a = new Apcomplex("(0.01000,0)"); b = new Apcomplex("(0.01000,0.00100)"); assertEquals("(0.01000,0) eq (0.01000,0.00100)", 1, a.equalDigits(b)); a = new Apcomplex("(0.01000,0.00001)"); b = new Apcomplex("(0.01000,0)"); assertEquals("(0.01000,0.00001) eq (0.01000,0)", 3, a.equalDigits(b)); a = new Apcomplex("(1000,0)"); b = new Apcomplex("(1001,0)"); assertEquals("(1000,0) eq (1001,0)", 3, a.equalDigits(b)); a = new Apcomplex("(0,1000)"); b = new Apcomplex("(0,1001)"); assertEquals("(0,1000) eq (0,1001)", 3, a.equalDigits(b)); a = new Apcomplex("5e-1"); b = new Apcomplex("1e-38"); assertEquals("5e-1 eq 1e-38", 0, a.equalDigits(b)); a = new Apcomplex("1.5e-2"); b = new Apcomplex("4.0e-3"); assertEquals("1.5e-2 eq 4.0e-3", 0, a.equalDigits(b)); } public static void testEquals() { Apcomplex a = new Apcomplex("0"), b = new Apcomplex("1"); assertEquals("0 == 1", false, a.equals(b)); a = new Apcomplex("(5,5)"); b = new Apcomplex("(5,6)"); assertEquals("(5,5) == (5,6)", false, a.equals(b)); a = new Apcomplex("(5,6)"); b = new Apcomplex("(5,5)"); assertEquals("(5,6) == (5,5)", false, a.equals(b)); a = new Apcomplex("(5,5)"); b = new Apcomplex("(6,5)"); assertEquals("(5,5) == (6,5)", false, a.equals(b)); a = new Apcomplex("(6,5)"); b = new Apcomplex("(5,5)"); assertEquals("(6,5) == (5,5)", false, a.equals(b)); a = new Apcomplex("(5,-5)"); b = new Apcomplex("(5,5)"); assertEquals("(5,-5) == (5,5)", false, a.equals(b)); a = new Apcomplex("(5,5)"); b = new Apcomplex("(5,-5)"); assertEquals("(5,5) == (5,-5)", false, a.equals(b)); a = new Apcomplex("(-5,5)"); b = new Apcomplex("(5,5)"); assertEquals("(-5,5) == (5,5)", false, a.equals(b)); a = new Apcomplex("(5,5)"); b = new Apcomplex("(-5,5)"); assertEquals("(5,5) == (-5,5)", false, a.equals(b)); a = new Apcomplex("(6,6)"); b = new Apcomplex("(6,6)"); assertEquals("(6,6) == (6,6)", true, a.equals(b)); assertEquals("a == a", true, a.equals(a)); assertEquals("(6,6) == something else", false, a.equals("bogus")); } public static void testTest() { Apcomplex a = new Apcomplex("0"), b = new Apcomplex("0"); assertTrue("0 test 0", a.test(b)); a = new Apcomplex("0"); b = new Apcomplex("1"); assertFalse("0 test 1", a.test(b)); a = new Apcomplex("(0,0)"); b = new Apcomplex("(0,1)"); assertFalse("0 test i", a.test(b)); } public static void testHashCode() { Apcomplex a = new Apcomplex("0"), b = new Apcomplex("1"); assertTrue("0 != 1", a.hashCode() != b.hashCode()); a = new Apcomplex("(5,5)"); b = new Apcomplex("(5,6)"); assertTrue("(5,5) != (5,6)", a.hashCode() != b.hashCode()); a = new Apcomplex("(6,5)"); b = new Apcomplex("(5,6)"); assertTrue("(6,5) != (5,6)", a.hashCode() != b.hashCode()); a = new Apcomplex("(6,6)"); b = new Apcomplex("(6,6)"); assertEquals("(6,6) == (6,6)", a.hashCode(), b.hashCode()); } public static void testToString() { Apcomplex a = new Apcomplex("0"); assertEquals("0", "0", "" + a); a = new Apcomplex("6"); assertEquals("6", "6", "" + a); a = new Apcomplex("(5,6)"); assertEquals("(5,6)", "(5, 6)", "" + a); a = new Apcomplex("(50,60)"); assertEquals("(50,60)", "(5e1, 6e1)", "" + a); a = new Apcomplex("(50,60)"); assertEquals("(50,60) pretty", "(50, 60)", a.toString(true)); } public static void testWriteTo() throws IOException { StringWriter out = new StringWriter(); Apcomplex a = new Apcomplex("0"); a.writeTo(out); a = new Apcomplex("6"); a.writeTo(out); a = new Apcomplex("(50,60)"); a.writeTo(out); a.writeTo(out, true); assertEquals("string", "06(5e1, 6e1)(50, 60)", out.toString()); } public static void testFormatTo() throws IOException { System.setProperty("java.locale.providers", "COMPAT,SPI"); // Required since Java 10 to have all locale providers available Locale locale = null; assertEquals("null %s", "(1.23456789e5, 1.23456e2)", String.format(locale, "%s", new Apcomplex("(123456.789,123.456)"))); assertEquals("null %S", "(1.23456789E5, 1.23456E2)", String.format(locale, "%S", new Apcomplex("(123456.789,123.456)"))); assertEquals("null %#s", "(123456.789, 123.456)", String.format(locale, "%#s", new Apcomplex("(123456.789,123.456)"))); assertEquals("null %.3s", "(1.23e5, 1.23e2)", String.format(locale, "%.3s", new Apcomplex("(123456.789,123.456)"))); assertEquals("null %.26s", "(1.23456789e5, 1.23456e2)", String.format(locale, "%.26s", new Apcomplex("(123456.789,123.456)"))); assertEquals("null %26s", " (1.23456789e5, 1.23456e2)", String.format(locale, "%26s", new Apcomplex("(123456.789,123.456)"))); assertEquals("null %-26s", "(1.23456789e5, 1.23456e2) ", String.format(locale, "%-26s", new Apcomplex("(123456.789,123.456)"))); assertEquals("null %#26s", " (123456.789, 123.456)", String.format(locale, "%#26s", new Apcomplex("(123456.789,123.456)"))); assertEquals("null %#-26s", "(123456.789, 123.456) ", String.format(locale, "%#-26s", new Apcomplex("(123456.789,123.456)"))); assertEquals("null %s apfloat", "1.23456789e5", String.format(locale, "%s", new Apcomplex("123456.789"))); locale = new Locale("fi", "FI"); assertEquals("fi_FI %s", "(1,23456789e5, 1,23456e2)", String.format(locale, "%s", new Apcomplex("(123456.789,123.456)"))); assertEquals("fi_FI %s radix 11", "(1,23456e5, 1,23456e5)", String.format(locale, "%s", new Apcomplex(new Apfloat("123456", 6, 11), new Apfloat("123456", 6, 11)))); locale = new Locale("hi", "IN"); assertEquals("hi_IN %#.6s", "(१२३४५६, १२३४५६)", String.format(locale, "%#.6s", new Apcomplex(new Apfloat("123456.7890123456"), new Apfloat("123456.7890123456")))); assertEquals("hi_IN %#s radix 9", "(१२३४५६, १२३४५६)", String.format(locale, "%#s", new Apcomplex(new Apfloat("123456", 6, 9), new Apfloat("123456", 6, 9)))); assertEquals("hi_IN %s radix 11", "(1.23456e5, 1.23456e5)", String.format(locale, "%s", new Apcomplex(new Apfloat("123456", 6, 11), new Apfloat("123456", 6, 11)))); Writer writer = new Writer() { @Override public void write(char cbuf[], int off, int len) throws IOException { throw new IOException(); } @Override public void flush() throws IOException { throw new IOException(); } @Override public void close() throws IOException { throw new IOException(); } }; Formatter formatter = new Formatter(writer); new Apcomplex("123456.789").formatTo(formatter, 0, -1, -1); } public static void testSerialization() throws IOException, ClassNotFoundException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(buffer); Apcomplex a = new Apcomplex("(5,6)"); out.writeObject(a); out.close(); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray())); Apcomplex b = (Apcomplex) in.readObject(); assertEquals("(5,6) equals", a, b); assertNotSame("(5,6) !=", a, b); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ApfloatContextTest.java000066400000000000000000000404251461767713300262370ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.Properties; import java.util.Enumeration; import java.util.concurrent.Executors; import java.util.function.Supplier; import org.apfloat.internal.Java9ClassLoader; import java.util.concurrent.ExecutorService; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.14.0 * @author Mikko Tommila */ public class ApfloatContextTest extends TestCase { public ApfloatContextTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApfloatContextTest("testSetGetProperties")); suite.addTest(new ApfloatContextTest("testSetGetExtraProperty")); suite.addTest(new ApfloatContextTest("testSetGetAttributes")); suite.addTest(new ApfloatContextTest("testFields")); suite.addTest(new ApfloatContextTest("testClone")); suite.addTest(new ApfloatContextTest("testException")); suite.addTest(new ApfloatContextTest("testThreadContexts")); suite.addTest(new ApfloatContextTest("testSystemOverride")); suite.addTest(new ApfloatContextTest("testCheckInterrupted")); return suite; } @SuppressWarnings("deprecation") public static void testSetGetProperties() { ApfloatContext ctx = ApfloatContext.getContext(); Properties properties = new Properties(); properties.setProperty(ApfloatContext.BUILDER_FACTORY, "org.apfloat.internal.DoubleBuilderFactory"); properties.setProperty(ApfloatContext.DEFAULT_RADIX, "11"); properties.setProperty(ApfloatContext.MAX_MEMORY_BLOCK_SIZE, "1048576"); properties.setProperty(ApfloatContext.CACHE_L1_SIZE, "16384"); properties.setProperty(ApfloatContext.CACHE_L2_SIZE, "524288"); properties.setProperty(ApfloatContext.CACHE_BURST, "128"); properties.setProperty(ApfloatContext.MEMORY_THRESHOLD, "131072"); properties.setProperty(ApfloatContext.SHARED_MEMORY_TRESHOLD, "262144"); properties.setProperty(ApfloatContext.BLOCK_SIZE, "131072"); properties.setProperty(ApfloatContext.NUMBER_OF_PROCESSORS, "8"); properties.setProperty(ApfloatContext.FILE_PATH, "./"); properties.setProperty(ApfloatContext.FILE_INITIAL_VALUE, "42"); properties.setProperty(ApfloatContext.FILE_SUFFIX, ".dat"); properties.setProperty(ApfloatContext.CLEANUP_AT_EXIT, "false"); ctx.setProperties(properties); properties = ctx.getProperties(); assertEquals("size", 15, properties.size()); assertEquals("ApfloatContext.BUILDER_FACTORY", "org.apfloat.internal.DoubleBuilderFactory", ctx.getProperty(ApfloatContext.BUILDER_FACTORY)); assertEquals("ApfloatContext.DEFAULT_RADIX", "11", ctx.getProperty(ApfloatContext.DEFAULT_RADIX)); assertEquals("ApfloatContext.MAX_MEMORY_BLOCK_SIZE", "1048576", ctx.getProperty(ApfloatContext.MAX_MEMORY_BLOCK_SIZE)); assertEquals("ApfloatContext.CACHE_L1_SIZE", "16384", ctx.getProperty(ApfloatContext.CACHE_L1_SIZE)); assertEquals("ApfloatContext.CACHE_L2_SIZE", "524288", ctx.getProperty(ApfloatContext.CACHE_L2_SIZE)); assertEquals("ApfloatContext.CACHE_BURST", "128", ctx.getProperty(ApfloatContext.CACHE_BURST)); assertEquals("ApfloatContext.MEMORY_TRESHOLD", "131072", ctx.getProperty(ApfloatContext.MEMORY_TRESHOLD)); assertEquals("ApfloatContext.MEMORY_THRESHOLD", "131072", ctx.getProperty(ApfloatContext.MEMORY_THRESHOLD)); assertEquals("ApfloatContext.SHARED_MEMORY_TRESHOLD", "262144", ctx.getProperty(ApfloatContext.SHARED_MEMORY_TRESHOLD)); assertEquals("ApfloatContext.BLOCK_SIZE", "131072", ctx.getProperty(ApfloatContext.BLOCK_SIZE)); assertEquals("ApfloatContext.NUMBER_OF_PROCESSORS", "8", ctx.getProperty(ApfloatContext.NUMBER_OF_PROCESSORS)); assertEquals("ApfloatContext.FILE_PATH", "./", ctx.getProperty(ApfloatContext.FILE_PATH)); assertEquals("ApfloatContext.FILE_INITIAL_VALUE", "42", ctx.getProperty(ApfloatContext.FILE_INITIAL_VALUE)); assertEquals("ApfloatContext.FILE_SUFFIX", ".dat", ctx.getProperty(ApfloatContext.FILE_SUFFIX)); assertEquals("ApfloatContext.CLEANUP_AT_EXIT", "false", ctx.getProperty(ApfloatContext.CLEANUP_AT_EXIT)); assertEquals("ApfloatContext.BUILDER_FACTORY", "org.apfloat.internal.DoubleBuilderFactory", ctx.getBuilderFactory().getClass().getName()); assertEquals("ApfloatContext.DEFAULT_RADIX", 11, ctx.getDefaultRadix()); assertEquals("ApfloatContext.MAX_MEMORY_BLOCK_SIZE", 1048576, ctx.getMaxMemoryBlockSize()); assertEquals("ApfloatContext.CACHE_L1_SIZE", 16384, ctx.getCacheL1Size()); assertEquals("ApfloatContext.CACHE_L2_SIZE", 524288, ctx.getCacheL2Size()); assertEquals("ApfloatContext.CACHE_BURST", 128, ctx.getCacheBurst()); assertEquals("ApfloatContext.MEMORY_TRESHOLD", 131072, ctx.getMemoryTreshold()); assertEquals("ApfloatContext.MEMORY_THRESHOLD", 131072, ctx.getMemoryThreshold()); assertEquals("ApfloatContext.SHARED_MEMORY_TRESHOLD", 262144, ctx.getSharedMemoryTreshold()); assertEquals("ApfloatContext.BLOCK_SIZE", 131072, ctx.getBlockSize()); assertEquals("ApfloatContext.NUMBER_OF_PROCESSORS", 8, ctx.getNumberOfProcessors()); assertEquals("ApfloatContext.CLEANUP_AT_EXIT", false, ctx.getCleanupAtExit()); assertEquals("Filename", "./42.dat", ctx.getFilenameGenerator().generateFilename()); // Memory treshold vs. threshold properties.setProperty(ApfloatContext.MEMORY_TRESHOLD, "4294967296"); properties.remove(ApfloatContext.MEMORY_THRESHOLD); ctx.setProperties(properties); assertEquals("ApfloatContext.MEMORY_TRESHOLD 4G", Integer.MAX_VALUE, ctx.getMemoryTreshold()); assertEquals("ApfloatContext.MEMORY_THRESHOLD 4G", 4294967296L, ctx.getMemoryThreshold()); ctx.setProperty(ApfloatContext.MEMORY_TRESHOLD, "" + (6L << 30)); assertEquals("ApfloatContext.MEMORY_TRESHOLD 6G", Integer.MAX_VALUE, ctx.getMemoryTreshold()); assertEquals("ApfloatContext.MEMORY_THRESHOLD 6G", 6L << 30, ctx.getMemoryThreshold()); ctx.setProperty(ApfloatContext.MEMORY_THRESHOLD, "" + (8L << 30)); assertEquals("ApfloatContext.MEMORY_TRESHOLD 8G", Integer.MAX_VALUE, ctx.getMemoryTreshold()); assertEquals("ApfloatContext.MEMORY_THRESHOLD 8G", 8L << 30, ctx.getMemoryThreshold()); ctx.setMemoryThreshold(9L << 30); assertEquals("ApfloatContext.MEMORY_TRESHOLD 9G", Integer.MAX_VALUE, ctx.getMemoryTreshold()); assertEquals("ApfloatContext.MEMORY_THRESHOLD 9G", 9L << 30, ctx.getMemoryThreshold()); } public static void testSetGetExtraProperty() { ApfloatContext ctx = ApfloatContext.getContext(); assertEquals("Extra property default value", "default", ctx.getProperty("extra", "default")); ctx.setProperty("extra", "value"); assertEquals("Extra property value", "value", ctx.getProperty("extra")); assertEquals("Extra property value, not default", "value", ctx.getProperty("extra", "default")); assertNull("Nonexistent property value", ctx.getProperty("bogus")); } public static void testSetGetAttributes() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setAttribute("string", "value"); assertEquals("string", "value", ctx.getAttribute("string")); Enumeration attributeNames = ctx.getAttributeNames(); assertTrue("has 1 attribute", attributeNames.hasMoreElements()); assertEquals("attribute name", "string", attributeNames.nextElement()); assertFalse("has no more than 1 attribute", attributeNames.hasMoreElements()); ctx.setAttribute("integer", 6); assertEquals("integer", 6, ctx.getAttribute("integer")); assertEquals("update integer", 6, ctx.setAttribute("integer", 5)); assertEquals("updated integer", 5, ctx.getAttribute("integer")); assertEquals("remove integer", 5, ctx.removeAttribute("integer")); assertNull("removed integer", ctx.getAttribute("integer")); assertNull("remove removed integer", ctx.removeAttribute("integer")); } public static void testFields() { ApfloatContext ctx = ApfloatContext.getContext(); ExecutorService executorService = Executors.newCachedThreadPool(); assertNotSame("Old ExecutorService", executorService, ctx.getExecutorService()); ctx.setExecutorService(executorService); assertSame("New ExecutorService", executorService, ctx.getExecutorService()); Object lock = new Object(); assertNotSame("Old sharedMemoryLock", lock, ctx.getSharedMemoryLock()); ctx.setSharedMemoryLock(lock); assertSame("New sharedMemoryLock", lock, ctx.getSharedMemoryLock()); } public static void testClone() { ApfloatContext ctx = ApfloatContext.getContext(), cloneCtx = (ApfloatContext) ctx.clone(); assertNotSame("ctx", ctx, cloneCtx); assertSame("BuilderFactory", ctx.getBuilderFactory(), cloneCtx.getBuilderFactory()); assertSame("FilenameGenerator", ctx.getFilenameGenerator(), cloneCtx.getFilenameGenerator()); assertSame("SharedMemoryLock", ctx.getSharedMemoryLock(), cloneCtx.getSharedMemoryLock()); assertNotSame("Properties", ctx.getProperties(), cloneCtx.getProperties()); assertEquals("Properties size", ctx.getProperties().size(), cloneCtx.getProperties().size()); ctx.setAttribute("bogus", "bogus"); assertNull("Attribute", cloneCtx.getAttribute("bogus")); } public static void testException() { ApfloatContext ctx = ApfloatContext.getContext(); try { ctx.setProperty(ApfloatContext.BUILDER_FACTORY, "bogus"); fail("Bogus class accepted"); } catch (ApfloatConfigurationException ace) { // OK } } public static void testThreadContexts() throws InterruptedException { ApfloatContext ctx = ApfloatContext.getContext(), cloneCtx = (ApfloatContext) ctx.clone(); assertSame("Context is global", ApfloatContext.getGlobalContext(), ApfloatContext.getContext()); assertNull("Current thread context is null", ApfloatContext.getThreadContext()); ApfloatContext.setThreadContext(cloneCtx); assertNotSame("Context is not global", ApfloatContext.getGlobalContext(), ApfloatContext.getContext()); ApfloatContext.removeThreadContext(); assertSame("Context is global again", ApfloatContext.getGlobalContext(), ApfloatContext.getContext()); Thread thread = new Thread() { @Override public void run() { assertNotSame("In-thread context is not global", ApfloatContext.getGlobalContext(), ApfloatContext.getContext()); assertNotSame("In-thread thread context is not global", ApfloatContext.getGlobalContext(), ApfloatContext.getThreadContext()); } }; assertNull("Thread context is null", ApfloatContext.getThreadContext(thread)); ApfloatContext.setThreadContext(cloneCtx, thread); assertNotNull("Thread context is set", ApfloatContext.getThreadContext(thread)); assertNotSame("Thread context is not global", ApfloatContext.getGlobalContext(), ApfloatContext.getThreadContext(thread)); assertSame("Current context is still global", ApfloatContext.getGlobalContext(), ApfloatContext.getContext()); thread.start(); thread.join(); ApfloatContext.clearThreadContexts(); assertNull("Thread context is removed", ApfloatContext.getThreadContext(thread)); } public void testSystemOverride() throws Exception { System.setProperty("apfloat.cacheBurst", "512"); System.setProperty("apfloat.cleanupAtExit", "false"); // To avoid access error at test exit Java9ClassLoader classLoader = new Java9ClassLoader(getClass().getClassLoader()); classLoader.loadJava8Class(ConcurrentWeakHashMap.class.getName()); // Depending on this package-private class classLoader.loadJava8Class(ApfloatContext.class.getName() + "$CleanupThread"); // Depending on this private class Class apfloatContextClass = classLoader.loadJava8Class(ApfloatContext.class.getName()); Object apfloatContext = apfloatContextClass.getMethod("getContext").invoke(null); Object cacheBurst = apfloatContextClass.getMethod("getCacheBurst").invoke(apfloatContext); assertEquals("Global context cacheBurst", 512, cacheBurst); apfloatContext = apfloatContextClass.getConstructor(Properties.class).newInstance(new Properties()); cacheBurst = apfloatContextClass.getMethod("getCacheBurst").invoke(apfloatContext); assertEquals("New context cacheBurst", 512, cacheBurst); System.clearProperty("apfloat.cacheBurst"); System.clearProperty("apfloat.cleanupAtExit"); } public static void testCheckInterrupted() { Object a = withTimeout(ApfloatContextTest::slowApfloatCalculation); assertNull("Slow result", a); a = withTimeout(ApfloatContextTest::fastApfloatCalculation); assertNotNull("Fast result", a); } private static T withTimeout(Supplier supplier) { final long TIMEOUT_MILLIS = 3000; Thread currentThread = Thread.currentThread(); Thread timeoutThread = new Thread(() -> { try { Thread.sleep(TIMEOUT_MILLIS); } catch (InterruptedException e) { return; // Calculation finished in time } currentThread.interrupt(); // Indicate a timeout to the calculation thread }); timeoutThread.start(); T result; try { // Perform calculation result = supplier.get(); } catch (ApfloatInterruptedException e) { // Too slow calculation timed out result = null; } timeoutThread.interrupt(); try { timeoutThread.join(); } catch (InterruptedException e) { // Ignore - race condition } Thread.interrupted(); // Clear interrupted state of current thread if calculation actually finished at the same time it timed out (it's a race) return result; } private static Object slowApfloatCalculation() throws ApfloatInterruptedException { int hash = 0; while (Boolean.TRUE) { hash += ApfloatContext.getContext().hashCode(); } return hash; } private static Object fastApfloatCalculation() { return new Object(); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ApfloatHelperTest.java000066400000000000000000000404251461767713300260320ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.13.0 * @author Mikko Tommila */ public class ApfloatHelperTest extends TestCase { public ApfloatHelperTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApfloatHelperTest("testGetMatchingPrecisions2")); suite.addTest(new ApfloatHelperTest("testGetMatchingPrecisions4")); suite.addTest(new ApfloatHelperTest("testLimitPrecision")); suite.addTest(new ApfloatHelperTest("testEnsurePrecision")); suite.addTest(new ApfloatHelperTest("testExtendPrecision")); suite.addTest(new ApfloatHelperTest("testReducePrecision")); suite.addTest(new ApfloatHelperTest("testSetPrecision")); suite.addTest(new ApfloatHelperTest("testLongValueExact")); return suite; } public static void testGetMatchingPrecisions2() { long[] precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(12345678, 5), new Apfloat(12345, 5)); assertEquals("5-2 [0]", 5, precisions[0]); assertEquals("5-2 [1]", 2, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(12345678, 10), new Apfloat(12345, 5)); assertEquals("8-5 [0]", 8, precisions[0]); assertEquals("8-5 [1]", 5, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(0), new Apfloat(12345, 5)); assertEquals("0-0 [0]", 0, precisions[0]); assertEquals("0-0 [1]", 0, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(12345678, 6), new Apfloat(12, 2)); assertEquals("6-0 [0]", 6, precisions[0]); assertEquals("6-0 [1]", 0, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(12345678, 5), new Apfloat(12, 2)); assertEquals("5-0 [0]", 5, precisions[0]); assertEquals("5-0 [1]", 0, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(10), new Apfloat(100, 2)); assertEquals("10, 100 2 [0]", 1, precisions[0]); assertEquals("10, 100 2 [1]", 2, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(10), new Apfloat(100, 3)); assertEquals("10, 100 3 [0]", 2, precisions[0]); assertEquals("10, 100 3 [1]", 3, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(10), new Apfloat(1, 2)); assertEquals("10, 1 2 [0]", 3, precisions[0]); assertEquals("10, 1 2 [1]", 2, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(10), new Apfloat(1, 3)); assertEquals("10, 1 3 [0]", 4, precisions[0]); assertEquals("10, 1 3 [1]", 3, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(10), new Apfloat(10)); assertEquals("10, 10 MAX [0]", Apfloat.INFINITE, precisions[0]); assertEquals("10, 10 MAX [1]", Apfloat.INFINITE, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(10), new Apfloat(100)); assertEquals("10, 100 MAX [0]", Apfloat.INFINITE, precisions[0]); assertEquals("10, 100 MAX [1]", Apfloat.INFINITE, precisions[1]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat("1e9000000000000000000", Apfloat.INFINITE), new Apfloat("1e-9000000000000000000", Apfloat.INFINITE)); assertEquals("MAX-MIN [0]", Apfloat.INFINITE, precisions[0]); assertEquals("MAX-MIN [1]", 0, precisions[1]); } public static void testGetMatchingPrecisions4() { // xxxxx000 * xxxxx + xxx00000 * xxx0 = // xxxxxx0000000 + xxxx00000000 = // xxxxx00000000 + xxxx00000000 = // xxxx000000000 / xxxx00000000 long[] precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(12345678, 8), new Apfloat(12345, 5), new Apfloat(12345678, 5), new Apfloat(1234, 3)); assertEquals("5-4-4 [0]", 5, precisions[0]); assertEquals("5-4-4 [1]", 4, precisions[1]); assertEquals("5-4-4 [2]", 4, precisions[2]); // xxxxx000 * xxxxx + x * x = // xxxxxx0000000 + xx = // xxxxx00000000 / xxxxx0000000 precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat(12345678, 8), new Apfloat(12345, 5), new Apfloat(1, 1), new Apfloat(2, 1)); assertEquals("6-0-5 [0]", 6, precisions[0]); assertEquals("6-0-5 [1]", 0, precisions[1]); assertEquals("6-0-5 [2]", 5, precisions[2]); precisions = ApfloatHelper.getMatchingPrecisions(new Apfloat("1e4500000000000000000", Apfloat.INFINITE), new Apfloat("1e4500000000000000000", Apfloat.INFINITE), new Apfloat("1e-4500000000000000000", Apfloat.INFINITE), new Apfloat("1e-4500000000000000000", Apfloat.INFINITE)); assertEquals("MAX-0-MAX [0]", Apfloat.INFINITE, precisions[0]); assertEquals("MAX-0-MAX [1]", 0, precisions[1]); assertEquals("MAX-0-MAX [2]", Apfloat.INFINITE, precisions[2]); } public static void testLimitPrecision() { Apfloat x = ApfloatHelper.limitPrecision(new Apfloat("1.23"), 2); assertEquals("1.23, 2 value", new Apfloat("1.2"), x); assertEquals("1.23, 2 precision", 2, x.precision()); x = ApfloatHelper.limitPrecision(new Apfloat("1.23"), 4); assertEquals("1.23, 4 value", new Apfloat("1.23"), x); assertEquals("1.23, 4 precision", 3, x.precision()); Apcomplex z = ApfloatHelper.limitPrecision(new Apcomplex("(1.23,4.56)"), 2); assertEquals("(1.23, 4.56), 2 value", new Apcomplex("(1.2,4.5)"), z); assertEquals("(1.23, 4.56), 2 precision", 2, z.precision()); z = ApfloatHelper.limitPrecision(new Apcomplex("(1.23,4.56)"), 4); assertEquals("(1.23, 4.56), 4 value", new Apcomplex("(1.23,4.56)"), z); assertEquals("(1.23, 4.56), 4 precision", 3, z.precision()); } public static void testEnsurePrecision() { Apfloat x = ApfloatHelper.ensurePrecision(new Apfloat("1.23"), 2); assertEquals("1.23, 2 value", new Apfloat("1.23"), x); assertEquals("1.23, 2 precision", 3, x.precision()); x = ApfloatHelper.ensurePrecision(new Apfloat("1.23"), 4); assertEquals("1.23, 4 value", new Apfloat("1.23"), x); assertEquals("1.23, 4 precision", 4, x.precision()); Apcomplex z = ApfloatHelper.ensurePrecision(new Apcomplex("(1.23,4.56)"), 2); assertEquals("(1.23, 4.56), 2 value", new Apcomplex("(1.23,4.56)"), z); assertEquals("(1.23, 4.56), 2 precision", 3, z.precision()); z = ApfloatHelper.ensurePrecision(new Apcomplex("(1.23,4.56)"), 4); assertEquals("(1.23, 4.56), 4 value", new Apcomplex("(1.23,4.56)"), z); assertEquals("(1.23, 4.56), 4 precision", 4, z.precision()); } public static void testExtendPrecision() { Apfloat x = ApfloatHelper.extendPrecision(new Apfloat("1.23"), 2); assertEquals("1.23, 2 value", new Apfloat("1.23"), x); assertEquals("1.23, 2 precision", 5, x.precision()); x = ApfloatHelper.extendPrecision(new Apfloat("1.23")); assertEquals("1.23 value", new Apfloat("1.23"), x); assertEquals("1.23 precision", 3 + Apfloat.EXTRA_PRECISION, x.precision()); Apcomplex z = ApfloatHelper.extendPrecision(new Apcomplex("(1.23,4.56)"), 2); assertEquals("(1.23, 4.56), 2 value", new Apcomplex("(1.23,4.56)"), z); assertEquals("(1.23, 4.56), 2 precision", 5, z.precision()); z = ApfloatHelper.extendPrecision(new Apcomplex("(1.23,4.56)")); assertEquals("(1.23, 4.56) value", new Apcomplex("(1.23,4.56)"), z); assertEquals("(1.23, 4.56) precision", 3 + Apcomplex.EXTRA_PRECISION, z.precision()); } public static void testReducePrecision() { Apfloat x = ApfloatHelper.reducePrecision(new Apfloat("1.23").precision(3 + Apfloat.EXTRA_PRECISION)); assertEquals("1.23 value", new Apfloat("1.23"), x); assertEquals("1.23 precision", 3, x.precision()); Apcomplex z = ApfloatHelper.reducePrecision(new Apcomplex("(1.23,4.56)").precision(3 + Apcomplex.EXTRA_PRECISION)); assertEquals("(1.23, 4.56) value", new Apcomplex("(1.23,4.56)"), z); assertEquals("(1.23, 4.56) precision", 3, z.precision()); try { ApfloatHelper.reducePrecision(new Apfloat("1.23").precision(Apfloat.EXTRA_PRECISION)); fail("1.23 accepted"); } catch (LossOfPrecisionException lope) { // OK } try { ApfloatHelper.reducePrecision(new Apcomplex("(1.23,4.56)").precision(Apcomplex.EXTRA_PRECISION)); fail("(1.23, 4.56) accepted"); } catch (LossOfPrecisionException lope) { // OK } } public static void testSetPrecision() { Apcomplex a = ApfloatHelper.setPrecision(new Apcomplex(new Apfloat(2), Apfloat.ZERO), 20); assertEquals("(2, 0) real prec", 20, a.real().precision()); assertEquals("(2, 0) real value", new Apfloat(2, 20), a.real()); assertEquals("(2, 0) imag prec", Apfloat.INFINITE, a.imag().precision()); assertEquals("(2, 0) imag value", Apfloat.ZERO, a.imag()); assertEquals("(2, 0) prec", 20, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex(Apfloat.ZERO, new Apfloat(2)), 20); assertEquals("(0, 2) real prec", Apfloat.INFINITE, a.real().precision()); assertEquals("(0, 2) real value", Apfloat.ZERO, a.real()); assertEquals("(0, 2) imag prec", 20, a.imag().precision()); assertEquals("(0, 2) imag value", new Apfloat(2, 20), a.imag()); assertEquals("(0, 2) prec", 20, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex("(0.0000000000123, 1.123456789012345)"), 11); assertEquals("(0.0000000000123, 1.123456789012345) real prec", Apfloat.INFINITE, a.real().precision()); assertEquals("(0.0000000000123, 1.123456789012345) real value", Apfloat.ZERO, a.real()); assertEquals("(0.0000000000123, 1.123456789012345) imag prec", 11, a.imag().precision()); assertEquals("(0.0000000000123, 1.123456789012345) imag value", new Apfloat("1.1234567890"), a.imag()); assertEquals("(0.0000000000123, 1.123456789012345) prec", 11, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex("(1.123456789012345, 0.0000000000123)"), 11); assertEquals("(1.123456789012345, 0.0000000000123) real prec", 11, a.real().precision()); assertEquals("(1.123456789012345, 0.0000000000123) real real value", new Apfloat("1.1234567890"), a.real()); assertEquals("(1.123456789012345, 0.0000000000123) imag prec", Apfloat.INFINITE, a.imag().precision()); assertEquals("(1.123456789012345, 0.0000000000123) imag value", Apfloat.ZERO, a.imag()); assertEquals("(1.123456789012345, 0.0000000000123) prec", 11, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex("(0.0000000000987, 1.098765432109876)"), 13); assertEquals("(0.0000000000987, 1.098765432109876) real prec", 2, a.real().precision()); assertEquals("(0.0000000000987, 1.098765432109876) real value", new Apfloat("0.000000000098"), a.real()); assertEquals("(0.0000000000987, 1.098765432109876) imag prec", 15, a.imag().precision()); assertEquals("(0.0000000000987, 1.098765432109876) imag value", new Apfloat("1.09876543210987"), a.imag()); assertEquals("(0.0000000000987, 1.098765432109876) prec", 13, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex("(1.098765432109876, 0.0000000000987)"), 13); assertEquals("(1.098765432109876, 0.0000000000987) real prec", 15, a.real().precision()); assertEquals("(1.098765432109876, 0.0000000000987) real real value", new Apfloat("1.09876543210987"), a.real()); assertEquals("(1.098765432109876, 0.0000000000987) imag prec", 2, a.imag().precision()); assertEquals("(1.098765432109876, 0.0000000000987) imag value", new Apfloat("0.000000000098"), a.imag()); assertEquals("(1.098765432109876, 0.0000000000987) prec", 13, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex(new Apfloat(111), new Apfloat("22.2")), 10); assertEquals("(111, 22.2) real prec", Apfloat.INFINITE, a.real().precision()); assertEquals("(111, 22.2) real value", new Apfloat(111), a.real()); assertEquals("(111, 22.2) imag prec", 9, a.imag().precision()); assertEquals("(111, 22.2) imag value", new Apfloat("22.2"), a.imag()); assertEquals("(111, 22.2) prec", 10, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex(new Apfloat("22.2"), new Apfloat(111)), 10); assertEquals("(22.2, 111) real prec", 9, a.real().precision()); assertEquals("(22.2, 111) real real value", new Apfloat("22.2"), a.real()); assertEquals("(22.2, 111) imag prec", Apfloat.INFINITE, a.imag().precision()); assertEquals("(22.2, 111) imag value", new Apfloat(111), a.imag()); assertEquals("(22.2, 111) prec", 10, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex("(22, 3.33)"), 5); assertEquals("(22, 3.33) real prec", 5, a.real().precision()); assertEquals("(22, 3.33) real real value", new Apfloat("22"), a.real()); assertEquals("(22, 3.33) imag prec", 6, a.imag().precision()); assertEquals("(22, 3.33) imag value", new Apfloat("3.33"), a.imag()); assertEquals("(22, 3.33) prec", 5, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex("(3.33, 22)"), 5); assertEquals("(3.33, 22) real prec", 6, a.real().precision()); assertEquals("(3.33, 22) real value", new Apfloat("3.33"), a.real()); assertEquals("(3.33, 22) imag prec", 5, a.imag().precision()); assertEquals("(3.33, 22) imag value", new Apfloat("22"), a.imag()); assertEquals("(3.33, 22) prec", 5, a.precision()); a = ApfloatHelper.setPrecision(new Apcomplex(new Apfloat(1, 1, 12), new Apfloat(12, 2, 12)), 1); assertEquals("(1, 12) real radix", 12, a.real().radix()); a = ApfloatHelper.setPrecision(new Apcomplex(new Apfloat(12, 2, 12), new Apfloat(1, 1, 12)), 1); assertEquals("(12, 1) imag radix", 12, a.imag().radix()); } public static void testLongValueExact() { assertEquals("Valid", 6, ApfloatHelper.longValueExact(new Apint(6))); assertEquals("Max", Long.MAX_VALUE, ApfloatHelper.longValueExact(new Apint(Long.MAX_VALUE))); assertEquals("Min", Long.MIN_VALUE, ApfloatHelper.longValueExact(new Apint(Long.MIN_VALUE))); try { ApfloatHelper.longValueExact(new Apint(Long.MAX_VALUE).add(Apint.ONE)); fail("Overflow allowed"); } catch (OverflowException oe) { // OK: overflow } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ApfloatMathTest.java000066400000000000000000014045311461767713300255070ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import java.util.Arrays; import junit.framework.TestSuite; import static java.math.RoundingMode.*; /** * @version 1.14.0 * @author Mikko Tommila */ public class ApfloatMathTest extends ApfloatTestCase { public ApfloatMathTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApfloatMathTest("testIntegerPow")); suite.addTest(new ApfloatMathTest("testScale")); suite.addTest(new ApfloatMathTest("testInverseRoot")); suite.addTest(new ApfloatMathTest("testRoot")); suite.addTest(new ApfloatMathTest("testAbs")); suite.addTest(new ApfloatMathTest("testCopySign")); suite.addTest(new ApfloatMathTest("testFloor")); suite.addTest(new ApfloatMathTest("testCeil")); suite.addTest(new ApfloatMathTest("testTruncate")); suite.addTest(new ApfloatMathTest("testFrac")); suite.addTest(new ApfloatMathTest("testRound")); suite.addTest(new ApfloatMathTest("testRoundToPrecision")); suite.addTest(new ApfloatMathTest("testRoundToInteger")); suite.addTest(new ApfloatMathTest("testRoundToPlaces")); suite.addTest(new ApfloatMathTest("testRoundToMultiple")); suite.addTest(new ApfloatMathTest("testNegate")); suite.addTest(new ApfloatMathTest("testModf")); suite.addTest(new ApfloatMathTest("testFmod")); suite.addTest(new ApfloatMathTest("testMultiplyAdd")); suite.addTest(new ApfloatMathTest("testMultiplySubtract")); suite.addTest(new ApfloatMathTest("testAgm")); suite.addTest(new ApfloatMathTest("testFactorial")); suite.addTest(new ApfloatMathTest("testDoubleFactorial")); suite.addTest(new ApfloatMathTest("testPi")); suite.addTest(new ApfloatMathTest("testLog")); suite.addTest(new ApfloatMathTest("testLogBase")); suite.addTest(new ApfloatMathTest("testExp")); suite.addTest(new ApfloatMathTest("testPow")); suite.addTest(new ApfloatMathTest("testAcosh")); suite.addTest(new ApfloatMathTest("testAsinh")); suite.addTest(new ApfloatMathTest("testAtanh")); suite.addTest(new ApfloatMathTest("testCosh")); suite.addTest(new ApfloatMathTest("testSinh")); suite.addTest(new ApfloatMathTest("testTanh")); suite.addTest(new ApfloatMathTest("testAcos")); suite.addTest(new ApfloatMathTest("testAsin")); suite.addTest(new ApfloatMathTest("testAtan")); suite.addTest(new ApfloatMathTest("testAtan2")); suite.addTest(new ApfloatMathTest("testCos")); suite.addTest(new ApfloatMathTest("testSin")); suite.addTest(new ApfloatMathTest("testTan")); suite.addTest(new ApfloatMathTest("testSinc")); suite.addTest(new ApfloatMathTest("testW")); suite.addTest(new ApfloatMathTest("testToRadians")); suite.addTest(new ApfloatMathTest("testToDegrees")); suite.addTest(new ApfloatMathTest("testProduct")); suite.addTest(new ApfloatMathTest("testSum")); suite.addTest(new ApfloatMathTest("testE")); suite.addTest(new ApfloatMathTest("testEuler")); suite.addTest(new ApfloatMathTest("testCatalan")); suite.addTest(new ApfloatMathTest("testGlaisher")); suite.addTest(new ApfloatMathTest("testKhinchin")); suite.addTest(new ApfloatMathTest("testGamma")); suite.addTest(new ApfloatMathTest("testGammaIncomplete")); suite.addTest(new ApfloatMathTest("testGammaIncompleteGeneralized")); suite.addTest(new ApfloatMathTest("testLogGamma")); suite.addTest(new ApfloatMathTest("testDigamma")); suite.addTest(new ApfloatMathTest("testPolygamma")); suite.addTest(new ApfloatMathTest("testBeta")); suite.addTest(new ApfloatMathTest("testBetaIncomplete")); suite.addTest(new ApfloatMathTest("testBetaIncompleteGeneralized")); suite.addTest(new ApfloatMathTest("testPochhammer")); suite.addTest(new ApfloatMathTest("testBinomial")); suite.addTest(new ApfloatMathTest("testZeta")); suite.addTest(new ApfloatMathTest("testZetaHurwitz")); suite.addTest(new ApfloatMathTest("testHypergeometric0F1")); suite.addTest(new ApfloatMathTest("testHypergeometric1F1")); suite.addTest(new ApfloatMathTest("testHypergeometric2F1")); suite.addTest(new ApfloatMathTest("testHypergeometric0F1Regularized")); suite.addTest(new ApfloatMathTest("testHypergeometric1F1Regularized")); suite.addTest(new ApfloatMathTest("testHypergeometric2F1Regularized")); suite.addTest(new ApfloatMathTest("testHypergeometricU")); suite.addTest(new ApfloatMathTest("testErf")); suite.addTest(new ApfloatMathTest("testErfc")); suite.addTest(new ApfloatMathTest("testErfi")); suite.addTest(new ApfloatMathTest("testInverseErf")); suite.addTest(new ApfloatMathTest("testInverseErfc")); suite.addTest(new ApfloatMathTest("testFresnelS")); suite.addTest(new ApfloatMathTest("testFresnelC")); suite.addTest(new ApfloatMathTest("testExpIntegralE")); suite.addTest(new ApfloatMathTest("testExpIntegralEi")); suite.addTest(new ApfloatMathTest("testLogIntegral")); suite.addTest(new ApfloatMathTest("testSinIntegral")); suite.addTest(new ApfloatMathTest("testCosIntegral")); suite.addTest(new ApfloatMathTest("testSinhIntegral")); suite.addTest(new ApfloatMathTest("testCoshIntegral")); suite.addTest(new ApfloatMathTest("testAiryAi")); suite.addTest(new ApfloatMathTest("testAiryAiPrime")); suite.addTest(new ApfloatMathTest("testAiryBi")); suite.addTest(new ApfloatMathTest("testAiryBiPrime")); suite.addTest(new ApfloatMathTest("testBesselJ")); suite.addTest(new ApfloatMathTest("testBesselI")); suite.addTest(new ApfloatMathTest("testBesselY")); suite.addTest(new ApfloatMathTest("testBesselK")); suite.addTest(new ApfloatMathTest("testEllipticK")); suite.addTest(new ApfloatMathTest("testEllipticE")); suite.addTest(new ApfloatMathTest("testHermiteH")); suite.addTest(new ApfloatMathTest("testLaguerreL")); suite.addTest(new ApfloatMathTest("testLaguerreLGeneralized")); suite.addTest(new ApfloatMathTest("testLegendreP")); suite.addTest(new ApfloatMathTest("testLegendrePAssociated")); suite.addTest(new ApfloatMathTest("testLegendreQ")); suite.addTest(new ApfloatMathTest("testLegendreQAssociated")); suite.addTest(new ApfloatMathTest("testChebyshevT")); suite.addTest(new ApfloatMathTest("testChebyshevU")); suite.addTest(new ApfloatMathTest("testGegenbauerCRenormalized")); suite.addTest(new ApfloatMathTest("testGegenbauerC")); suite.addTest(new ApfloatMathTest("testJacobiP")); suite.addTest(new ApfloatMathTest("testFibonacci")); suite.addTest(new ApfloatMathTest("testEulerE")); suite.addTest(new ApfloatMathTest("testBernoulliB")); suite.addTest(new ApfloatMathTest("testHarmonicNumber")); suite.addTest(new ApfloatMathTest("testHarmonicNumberGeneralized")); suite.addTest(new ApfloatMathTest("testPolylog")); suite.addTest(new ApfloatMathTest("testLogisticSigmoid")); suite.addTest(new ApfloatMathTest("testRandom")); suite.addTest(new ApfloatMathTest("testRandomGaussian")); suite.addTest(new ApfloatMathTest("testContinuedFraction")); suite.addTest(new ApfloatMathTest("testConvergents")); suite.addTest(new ApfloatMathTest("testMax")); suite.addTest(new ApfloatMathTest("testMin")); suite.addTest(new ApfloatMathTest("testNextAfter")); suite.addTest(new ApfloatMathTest("testNextUp")); suite.addTest(new ApfloatMathTest("testNextDown")); suite.addTest(new ApfloatMathTest("testUlp")); return suite; } public static void testIntegerPow() { Apfloat x = new Apfloat(2, 1000); assertEquals("2^30", new Apfloat(1 << 30), ApfloatMath.pow(x, 30)); assertEquals("2^60", new Apfloat(1L << 60), ApfloatMath.pow(x, 60)); assertEquals("2^-1", new Apfloat("0.5"), ApfloatMath.pow(x, -1)); assertEquals("2^-3", new Apfloat("0.125"), ApfloatMath.pow(x, -3)); assertEquals("2^0", new Apfloat(1), ApfloatMath.pow(x, 0)); assertEquals("2^1000000000", ApfloatMath.pow(x, 1000000000).precision(10), ApfloatMath.pow(x.precision(11), 1000000000).precision(10)); x = new Apfloat("1.00000000000000000000000000000000000000001", 50); assertEquals("1.00000000000000000000000000000000000000001^0x7FFFFFFFFFFFFFFF", new Apfloat("1.0000000000000000000000922337203685477580700042535"), ApfloatMath.pow(x, 0x7FFFFFFFFFFFFFFFL), new Apfloat(1e-48)); assertEquals("1.00000000000000000000000000000000000000001^0x8000000000000000", new Apfloat("0.99999999999999999999990776627963145224192000425352"), ApfloatMath.pow(x, 0x8000000000000000L), new Apfloat(1e-48)); assertEquals("2^1000 * 5^1000 = 10^1000", ApfloatMath.pow(new Apfloat(10), 1000), ApfloatMath.pow(new Apfloat(2), 1000).multiply(ApfloatMath.pow(new Apfloat(5), 1000))); assertEquals("2^10000 * 5^10000 = 10^10000", ApfloatMath.pow(new Apfloat(10), 10000), ApfloatMath.pow(new Apfloat(2), 10000).multiply(ApfloatMath.pow(new Apfloat(5), 10000))); assertEquals("2^100000 * 5^100000 = 10^100000", ApfloatMath.pow(new Apfloat(10), 100000), ApfloatMath.pow(new Apfloat(2), 100000).multiply(ApfloatMath.pow(new Apfloat(5), 100000))); assertEquals("2^1000000 * 5^1000000 = 10^1000000", ApfloatMath.pow(new Apfloat(10), 1000000), ApfloatMath.pow(new Apfloat(2), 1000000).multiply(ApfloatMath.pow(new Apfloat(5), 1000000))); try { ApfloatMath.pow(new Apfloat(0), 0); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } } public static void testScale() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { Apfloat x = ApfloatMath.scale(new Apfloat(1, 5, radix), 5); assertEquals("1 precision", 5, x.precision()); assertEquals("1 string", "100000", x.toString(true)); x = ApfloatMath.scale(new Apfloat(-1, 5, radix), -5); assertEquals("-1 precision", 5, x.precision()); assertEquals("-1 string", "-0.00001", x.toString(true)); x = ApfloatMath.scale(new Apfloat(1, 5, radix), Long.MIN_VALUE / 2); x = ApfloatMath.scale(x, Long.MAX_VALUE); assertEquals("-2^62 precision", 5, x.precision()); assertEquals("-2^62 string", "1e4611686018427387903", x.toString()); x = ApfloatMath.scale(new Apfloat(1, 5, radix), Long.MIN_VALUE / -2); x = ApfloatMath.scale(x, Long.MIN_VALUE); assertEquals("2^62 precision", 5, x.precision()); assertEquals("2^62 string", "1e-4611686018427387904", x.toString()); x = ApfloatMath.scale(new Apfloat(1, 5, radix), Long.MIN_VALUE / 2); x = ApfloatMath.scale(x, Long.MIN_VALUE / 2); assertEquals("underflow", "0", x.toString()); x = ApfloatMath.scale(new Apfloat(1, 5, radix), Long.MIN_VALUE / 2); x = ApfloatMath.scale(x, Long.MIN_VALUE); assertEquals("underflow 2", "0", x.toString()); x = ApfloatMath.scale(new Apfloat(radix - 1, 5, radix), 5); assertEquals("9 precision", 5, x.precision()); assertEquals("9 string", Character.forDigit(radix - 1, radix) + "00000", x.toString(true)); } } public static void testInverseRoot() { Apfloat x = new Apfloat("1.2345678901234567890123456789"), invX, invSqrtX; assertEquals("1.2345678901234567890123456789^-1", new Apfloat("0.810000007290000066339000603685715"), ApfloatMath.inverseRoot(x, 1), new Apfloat(1e-30)); assertEquals("-2^-1/3", new Apfloat(-0.79370052598409973737585281963615), ApfloatMath.inverseRoot(new Apfloat(-2.0), 3), new Apfloat(1e-15)); assertEquals("-2^-1/5", new Apfloat(-0.87055056329612413913627001747975), ApfloatMath.inverseRoot(new Apfloat(-2.0), 5), new Apfloat(1e-15)); assertEquals("-2^-1/7", new Apfloat(-0.9057236642639066715941728732151), ApfloatMath.inverseRoot(new Apfloat(-2.0), 7), new Apfloat(1e-15)); x = new Apfloat("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151557485724245415069595082953311686172785588907509838175463746493931925506040092770167113900984882401285836160356370766010471018194295559619894676783744944825537977472684710404753464620804668425906949129331367702898915210475216205696602405803815019351125338243003558764024749647326391419927260426992279678235478163600934172164121992458631503028618297455570674983850549458858692699569092721079750930295532116534498720275596023648066549911988183479775356636980742654252786255181841757467289097777279380008164706001614524919217321721477235014144197356854816136115735255213347574184946843852332390739414333454776241686251898356948556209921922218427255025425688767179049460165346680498862723279178608578438382796797668145410095388378636095068006422512520511739298489608412848862694560424196528502221066118630674427862203919494504712371378696095636437191728746776465757396241389086583264599581339047802759009946576407895126946839835259570982582262052248940772671947826848260147699090264013639443745530506820349625245174939965143142980919065925093722169646151570985838741059788595977297549893016175392846813826868386894277415599185592524595395943104997252468084598727364469584865383673622262609912460805124388439045124413654976278079771569143599770012961608944169486855584840635342207222582848864815845602850601684273945226746767889525213852254995466672782398645659611635488623057745649803559363456817432411251507606947945109659609402522887971089314566913686722874894056010150330861792868092087476091782493858900971490967598526136554978189312978482168299894872265880485756401427047755513237964145152374623436454285844479526586782105114135473573952311342716610213596953623144295248493718711014576540359027993440374200731057853906219838744780847848968332144571386875194350643021845319104848100537061468067491927819119793995206141966342875444064374512371819217999839101591956181467514269123974894090718649423196156794520809514655022523160388193014209376213785595663893778708303906979207734672218256259966150142150306803844773454920260541466592520149744285073251866600213243408819071048633173464965145390579626856100550810665879699816357473638405257145910289706414011097120628043903975951567715770042033786993600723055876317635942187312514712053292819182618612586732157919841484882916447060957527069572209175671167229109816909152801735067127485832228718352093539657251210835791513698820914442100675103346711031412671113699086585163983150197016515116851714376576183515565088490998985998238734552833163550764791853589322618548963213293308985706420467525907091548141654985946163718027098199430992448895757128289059232332609729971208443357326548938239119325974636673058360414281388303203824903758985243744170291327656180937734440307074692112019130203303801976211011004492932151608424448596376698389522868478312355265821314495768572624334418930396864262434107732269780280731891544110104468232527162010526522721116603966655730925471105578537634668206531098965269186205647693125705863566201855810072936065987648611791045334885034611365768675324944166803962657978771855608455296541266540853061434443185867697514566140680070023787765913440171274947042056223053899456131407112700040785473326993908145466464588079727082668306343285878569830523580893306575740679545716377525420211495576158140025012622859413021647155097925923099079654737612551765675135751782966645477917450112996148903046399471329621073404375189573596145890193897131117904297828564750320319869151402870808599048010941214722131794764777262241425485454033215718530614228813758504306332175182979866223717215916077166925474873898665494945011465406284336639379003976926567214638530673609657120918076383271664162748888007869256029022847210403172118608204190004229661711963779213375751149595015660496318629472654736425230817703675159067350235072835405670403867435136222247715891504953098444893330963408780769325993978054193414473774418426312986080998886874132604721569516239658645730216315981931951673538129741677294786724229246543668009806769282382806899640048243540370141631496589794092432378969070697794223625082216889573837986230015937764716512289357860158816175578297352334460428151262720373431465319777741603199066554187639792933441952154134189948544473456738316249934191318148092777710386387734317720754565453220777092120190516609628049092636019759882816133231666365286193266863360627356763035447762803504507772355471058595487027908143562401451718062464362679456127531813407833033625423278394497538243720583531147711992606381334677687969597030983391307710987040859133746414428227726346594704745878477872019277152807317679077071572134447306057007334924369311383504931631284042512192565179806941135280131470130478164378851852909285452011658393419656213491434159562586586557055269049652098580338507224264829397285847831630577775606888764462482468579260395352773480304802900587607582510474709164396136267604492562742042083208566119062545433721315359584506877246029016187667952406163425225771954291629919306455377991403734043287526288896399587947572917464263574552540790914513571113694109119393251910760208252026187985318877058429725916778131496990090192116971737278476847268608490033770242429165130050051683233643503895170298939223345172201381280696501178440874519601212285993716231301711444846409038906449544400619869075485160263275052983491874078668088183385102283345085048608250393021332197155184306354550076682829493041377655279397517546139539846833936383047461199665385815384205685338621867252334028308711232827892125077126294632295639898989358211674562701021835646220134967151881909730381198004973407239610368540664319395097901906996395524530054505806855019567302292191393391856803449039820595510022635353619204199474553859381023439554495977837790237421617271117236434354394782218185286240851400666044332588856986705431547069657474585503323233421073015459405165537906866273337995851156257843229882737231989875714159578111963583300594087306812160287649628674460477464915995054973742562690104903778198683593814657412680492564879855614537234786733039046883834363465537949864192705638729317487233208376011230299113679386270894387993620162951541337142489283072201269014754668476535761647737946752004907571555278196536213239264061601363581559074220202031872776052772190055614842555187925303435139844253223415762336106425063904975008656271095359194658975141310348227693062474353632569160781547818115284366795706110861533150445212747392454494542368288606134084148637767009612071512491404302725386076482363414334623518975766452164137679690314950191085759844239198629164219399490723623464684411739403265918404437805133389452574239950829659122850855582157250310712570126683024029295252201187267675622041542051618416348475651699981161410100299607838690929160302884002691041407928862150784245167090870006992821206604183718065355672525325675328612910424877618258297651579598470356222629348600341587229805349896502262917487882027342092222453398562647669149055628425039127577102840279980663658254889264880254566101729670266407655904290994568150652653053718294127033693137851786090407086671149655834343476933857817113864558736781230145876871266034891390956200993936103102916161528813843790990423174733639480457593149314052976347574811935670911013775172100803155902485309066920376719220332290943346768514221447737939375170344366199104033751117354719185504644902636551281622882446257591633303910722538374218214088350865739177150968288747826569959957449066175834413752239709683408005355984917541738188399944697486762655165827658483588453142775687900290951702835297163445621296404352311760066510124120065975585127617858382920419748442360800719304576189323492292796501987518721272675079812554709589045563579212210333466974992356302549478024901141952123828153091140790738602515227429958180724716259166854513331239480494707911915326734302824418604142636395480004480026704962482017928964766975831832713142517029692348896276684403232609275249603579964692565049368183609003238092934595889706953653494060340216654437558900456328822505452556405644824651518754711962184439658253375438856909411303150952617937800297412076651479394259029896959469955657612186561967337862362561252163208628692221032748892186543648022967807057656151446320469279068212073883778142335628236089632080682224680122482611771858963814091839036736722208883215137556003727983940041529700287830766709444745601345564172543709069793961225714298946715435784687886144458123145935719849225284716050492212424701412147805734551050080190869960330276347870810817545011930714122339086639383395294257869050764310063835198343893415961318543475464955697810382930971646514384070070736041123735998434522516105070270562352660127648483084076118301305279320542746286540360367453286510570658748822569815793678976697422057505968344086973502014102067235850200724522563265134105592401902742162484391403599895353945909440704691209140938700126456001623742880210927645793106579229552498872758461012648369998922569596881592056001016552563756785667227966198857827948488558343975187445455129656344348039664205579829368043522027709842942325330225763418070394769941597915945300697521482933665556615678736400536665641654732170439035213295435291694145990416087532018683793702348886894791510716378529023452924407736594956305100742108714261349745956151384987137570471017879573104229690666702144986374645952808243694457897723300487647652413390759204340196340391147320233807150952220106825634274716460243354400515212669324934196739770415956837535551667302739007497297363549645332888698440611964961627734495182736955882207573551766515898551909866653935494810688732068599075407923424023009259007017319603622547564789406475483466477604114632339056513433068449539790709030234604614709616968868850140834704054607429586991382966824681857103188790652870366508324319744047718556789348230894310682870272280973624809399627060747264553992539944280811373694338872940630792615959954626246297070625948455690347119729964090894180595343932512362355081349490043642785271383159125689892951964272875739469142725343669415323610045373048819855170659412173524625895487301676002988659257866285612496655235338294287854253404830833070165372285635591525347844598183134112900199920598135220511733658564078264849427644113763938669248031183644536985891754426473998822846218449008777697763127957226726555625962825427653183001340709223343657791601280931794017185985999338492354956400570995585611349802524990669842330173503580440811685526531170995708994273287092584878944364600504108922669178352587078595129834417295351953788553457374260859029081765155780390594640873506123226112009373108048548526357228257682034160504846627750450031262008007998049254853469414697751649327095049346393824322271885159740547021482897111777923761225788734771881968254629812686858170507402725502633290449762778944236216741191862694396506715157795867564823993917604260176338704549901761436412046921823707648878341968968611815581587360629386038101712158552726683008238340465647588040513808016336388742163714064354955618689641122821407533026551004241048967835285882902436709048871181909094945331442182876618103100735477054981596807720094746961343609286148494178501718077930681085469000944589952794243981392135055864221964834915126390128038320010977386806628779239718014613432445726400973742570073592100315415089367930081699805365202760072774967458400283624053460372634165542590276018348403068113818551059797056640075094260878857357960373245141467867036880988060971642584975951380693094494015154222219432913021739125383559150310033303251117491569691745027149433151558854039221640972291011290355218157628232831823425483261119128009282525619020526301639114772473314857391077758744253876117465786711694147764214411112635835538713610110232679877564102468240322648346417663698066378576813492045302240819727856471983963087815432211669122464159117767322532643356861461865452226812688726844596844241610785401676814208088502800541436131462308210259417375623899420757136275167457318918945628352570441335437585753426986994725470316566139919996826282472706413362221789239031760854289437339356188916512504244040089527198378738648058472689546243882343751788520143956005710481194988423906061369573423155907967034614914344788636041031823507365027785908975782727313050488939890099239135033732508559826558670892426124294736701939077271307068691709264625484232407485503660801360466895118400936686095463250021458529309500009071510582362672932645373821049387249966993394246855164832611341461106802674466373343753407642940266829738652209357016263846485285149036293201991996882851718395366913452224447080459239660281715655156566611135982311225062890585491450971575539002439315351909021071194573002438801766150352708626025378817975194780610137150044899172100222013350131060163915415895780371177927752259787428919179155224171895853616805947412341933984202187456492564434623925319531351033114763949119950728584306583619353693296992898379149419394060857248639688369032655643642166442576079147108699843157337496488352927693282207629472823815374099615455987982598910937171262182830258481123890119682214294576675807186538065064870261338928229949725745303328389638184394477077940228435988341003583854238973542439564755568409522484455413923941000162076936368467764130178196593799715574685419463348937484391297423914336593604100352343777065888677811394986164787471407932638587386247328896456435987746676384794665040741118256583788784548581489629612739984134427260860618724554523606431537101127468097787044640947582803487697589483282412392929605829486191966709189580898332012103184303401284951162035342801441276172858302435598300320420245120728725355811958401491809692533950757784000674655260314461670508276827722235341911026341631571474061238504258459884199076112872580591139356896014316682831763235673254170734208173322304629879928049085140947903688786878949305469557030726190095020764334933591060245450864536289354568629585313153371838682656178622736371697577418302398600659148161640494496501173213138957470620884748023653710311508984279927544268532779743113951435741722197597993596852522857452637962896126915723579866205734083757668738842664059909935050008133754324546359675048442352848747014435454195762584735642161981340734685411176688311865448937769795665172796623267148103386439137518659467300244345005449953997423723287124948347060440634716063258306498297955101095418362350303094530973358344628394763047756450150085075789495489313939448992161255255977014368589435858775263796255970816776438001254365023714127834679261019955852247172201777237004178084194239487254068015560359983905489857235467456423905858502167190313952629445543913166313453089390620467843877850542393905247313620129476918749751910114723152893267725339181466073000890277689631148109022097245207591672970078505807171863810549679731001678708506942070922329080703832634534520380278609905569001341371823683709919495164896007550493412678764367463849020639640197666855923356546391383631857456981471962108410809618846054560390384553437291414465134749407848844237721751543342603066988317683310011331086904219390310801437843341513709243530136776310849135161564226984750743032971674696406665315270353254671126675224605511995818319637637076179919192035795820075956053023462677579439363074630569010801149427141009391369138107258137813578940055995001835425118417213605572752210352680373572652792241737360575112788721819084490061780138897107708229310027976659358387589093956881485602632243937265624727760378908144588378550197028437793624078250527048758164703245812908783952324532378960298416692254896497156069811921865849267704039564812781021799132174163058105545988013004845629976511212415363745150056350701278159267142413421033015661653560247338078430286552572227530499988370153487930080626018096238151613669033411113865385109193673938352293458883225508870645075394739520439680790670868064450969865488016828743437861264538158342807530618454859037982179945996811544197425363443996029025100158882721647450068207041937615845471231834600726293395505482395571372568402322682130124767945226448209102356477527230820810635188991526928891084555711266039650343978962782500161101532351605196559042118449499077899920073294769058685778787209829013529566139788848605097860859570177312981553149516814671769597609942100361835591387778176984587581044662839988060061622984861693533738657877359833616133841338536842119789389001852956919678045544828584837011709672125353387586215823101331038776682721157269495181795897546939926421979155233857662316762754757035469941489290413018638611943919628388705436777432242768091323654494853667680000010652624854730558615989991401707698385483188750142938908995068545307651168033373222651756622075269517914422528081651716677667279303548515420402381746089232839170327542575086765511785939500279338959205766827896776445318404041855401043513483895312013263783692835808271937831265496174599705674507183320650345566440344904536275600112501843356073612227659492783937064784264567633881880756561216896050416113903906396016202215368494109260538768871483798955999911209916464644119185682770045742434340216722764455893301277815868695250694993646101756850601671453543158148010545886056455013320375864548584032402987170934809105562116715468484778039447569798042631809917564228098739987669732376957370158080682290459921236616890259627304306793165311494017647376938735140933618332161428021497633991898354848756252987524238730775595559554651963944018218409984124898262367377146722606163364329640633572810707887581640438148501884114318859882769449011932129682715888413386943468285900666408063140777577257056307294004929403024204984165654797367054855804458657202276378404668233798528271057843197535417950113472736257740802134768260450228515797957976474670228409995616015691089038458245026792659420555039587922981852648007068376504183656209455543461351341525700659748819163413595567196496540321872716026485930490397874895890661272507948282769389535217536218507962977851461884327192232238101587444505286652380225328438913752738458923844225354726530981715784478342158223270206902872323300538621634798850946954720047952311201504329322662827276321779088400878614802214753765781058197022263097174950721272484794781695729614236585957820908307332335603484653187302930266596450137183754288975579714499246540386817992138934692447419850973346267933210726868707680626399193619650440995421676278409146698569257150743157407938053239252394775574415918458215625181921552337096074833292349210345146264374498055961033079941453477845746999921285999993996122816152193148887693880222810830019860165494165426169685867883726095877456761825072759929508931805218729246108676399589161458550583972742098090978172932393010676638682404011130402470073508578287246271349463685318154696904669686939254725194139929146524238577625500474852954768147954670070503479995888676950161249722820403039954632788306959762493615101024365553522306906129493885990157346610237122354789112925476961760050479749280607212680392269110277722610254414922157650450812067717357120271802429681062037765788371669091094180744878140490755178203856539099104775941413215432844062503018027571696508209642734841469572639788425600845312140659358090412711359200419759851362547961606322887361813673732445060792441176399759746193835845749159880976674470930065463424234606342374746660804317012600520559284936959414340814685298150539471789004518357551541252235905906872648786357525419112888773717663748602766063496035367947026923229718683277173932361920077745221262475186983349515101986426988784717193966497690708252174233656627259284406204302141137199227852699846988477023238238400556555178890876613601304770984386116870523105531491625172837327286760072481729876375698163354150746088386636406934704372066886512756882661497307886570156850169186474885416791545965072342877306998537139043002665307839877638503238182155355973235306860430106757608389086270498418885951380910304235957824951439885901131858358406674723702971497850841458530857813391562707603563907639473114554958322669457024941398316343323789759556808568362972538679132750555425244919435891284050452269538121791319145135009938463117740179715122837854601160359554028644059024964669307077690554810288502080858008781157738171917417760173307385547580060560143377432990127286772530431825197579167929699650414607066457125888346979796429316229655201687973000356463045793088403274807718115553309098870255052076804630346086581653948769519600440848206596737947316808641564565053004988161649057883115434548505266006982309315777650037807046612647060214575057932709620478256152471459189652236083966456241051955105223572397395128818164059785914279148165426328920042816091369377737222999833270820829699557377273756676155271139225880552018988762011416800546873655806334716037342917039079863965229613128017826797172898229360702880690877686605932527463784053976918480820410219447197138692560841624511239806201131845412447820501107987607171556831540788654390412108730324020106853419472304766667217498698685470767812051247367924791931508564447753798537997322344561227858432968466475133365736923872014647236794278700425032555899268843495928761240075587569464137056251400117971331662071537154360068764773186755871487839890810742953094106059694431584775397009439883949144323536685392099468796450665339857388878661476294434140104988899316005120767810358861166020296119363968213496075011164983278563531614516845769568710900299976984126326650234771672865737857908574664607722834154031144152941880478254387617707904300015669867767957609099669360755949651527363498118964130433116627747123388174060373174397054067031096767657486953587896700319258662594105105335843846560233917967492678447637084749783336555790073841914731988627135259546251816043422537299628632674968240580602964211463864368642247248872834341704415734824818333016405669596688667695634914163284264149745333499994800026699875888159350735781519588990053951208535103572613736403436753471410483601754648830040784641674521673719048310967671134434948192626811107399482506073949507350316901973185211955263563258433909982249862406703107683184466072912487475403161796994113973877658998685541703188477886759290260700432126661791922352093822787888098863359911608192353555704646349113208591897961327913197564909760001399623444553501434642686046449586247690943470482932941404111465409239883444351591332010773944111840741076849810663472410482393582740194493566516108846312567852977697346843030614624180358529331597345830384554103370109167677637427621021370135485445092630719011473184857492331816720721372793556795284439254815609137281284063330393735624200160456645574145881660521666087387480472433912129558777639069690370788285277538940524607584962315743691711317613478388271941686066257210368513215664780014767523103935786068961112599602818393095487090590738613519145918195102973278755710497290114871718971800469616977700179139196137914171627070189584692143436967629274591099400600849835684252019155937037010110497473394938778859894174330317853487076032219829705797511914405109942358830345463534923498268836240433272674155403016195056806541809394099820206099941402168909007082133072308966211977553066591881411915778362729274615618571037217247100952142369648308641025928874579993223749551912219519034244523075351338068568073544649951272031744871954039761073080602699062580760202927314552520780799141842906388443734996814582733720726639176702011830046481900024130835088465841521489912761065137415394356572113903285749187690944137020905170314877734616528798482353382972601361109845148418238081205409961252745808810994869722161285248974255555160763716750548961730168096138038119143611439921063800508321409876045993093248510251682944672606661381517457125597549535802399831469822036133808284993567055755247129027453977621404931820146580080215665360677655087838043041343105918046068008345911366408348874080057412725867047922583191274157390809143831384564241509408491339180968402511639919368532255573389669537490266209232613188558915808324555719484538756287861288590041060060737465014026278240273469625282171749415823317492396835301361786536737606421667781377399510065895288774276626368418306801908046098498094697636673356622829151323527888061577682781595886691802389403330764419124034120223163685778603572769415417788264352381319050280870185750470463129333537572853866058889045831114507739429352019943219711716422350056440429798920815943071670198574692738486538334361457946341759225738985880016980147574205429958012429581054565108310462972829375841611625325625165724980784920998979906200359365099347215829651741357984910471116607915874369865412223483418877229294463351786538567319625598520260729476740726167671455736498121056777168934849176607717052771876011999081441130586455779105256843048114402619384023224709392498029335507318458903553971330884461741079591625117148648744686112476054286734367090466784686702740918810142497111496578177242793470702166882956108777944050484375284433751088282647719785400065097040330218625561473321177711744133502816088403517814525419643203095760186946490886815452856213469883554445602495566684366029221951248309106053772019802183101032704178386654471812603971906884623708575180800353270471856594994761242481109992886791589690495639476246084240659309486215076903149870206735338483495508363660178487710608098042692471324100094640143736032656451845667924566695510015022983307984960799498824970617236744936122622296179081431141466094123415935930958540791390872083227335495720807571651718765994498569379562387555161757543809178052802946420044721539628074636021132942559160025707356281263873310600589106524570802447493754318414940148211999627645310680066311838237616396631809314446712986155275982014514102756006892975024630401735148919457636078935285550531733141645705049964438909363084387448478396168405184527328840323452024705685164657164771393237755172947951261323982296023945485797545865174587877133181387529598094121742273003522965080891777050682592488223221549380483714547816472139768209633205083056479204820859204754998573203888763916019952409189389455767687497308569559580106595265030362661597506622250840674288982659075106375635699682115109496697445805472886936310203678232501823237084597901115484720876182124778132663304120762165873129708112307581598212486398072124078688781145016558251361789030708608701989758898074566439551574153631931919810705753366337380382721527988493503974800158905194208797113080512339332219034662499171691509485414018710603546037946433790058909577211808044657439628061867178610171567409676620802957665770512912099079443046328929473061595104309022214393718495606340561893425130572682914657832933405246350289291754708725648426003496296116541382300773133272983050016025672401418515204189070115428857992081219844931569990591820118197335001261877280368124819958770702075324063612593134385955425477819611429351635612234966615226147353996740515849986035529533292457523888101362023476246690558164389678630976273655047243486430712184943734853006063876445662721866617012381277156213797461498613287441177145524447089971445228856629424402301847912054784985745216346964489738920624019435183100882834802492490854030778638751659113028739587870981007727182718745290139728366148421428717055317965430765045343246005363614726181809699769334862640774351999286863238350887566835950972655748154319401955768504372480010204137498318722596773871549583997184449072791419658459300839426370208756353982169620553248032122674989114026785285996734052420310917978999057188219493913207534317079800237365909853755202389116434671855829068537118979526262344924833924963424497146568465912489185566295893299090352392333336474352037077010108438800329075983421701855422838616172104176030116459187805393674474720599850235828918336929223373239994804371084196594731626548257480994825099918330069765693671596893644933488647442135008407006608835972350395323401795825570360169369909886711321097988970705172807558551912699306730992507040702455685077867906947661262980822516331363995211709845280926303759224267425755998928927837047444521893632034894155210445972618838003006776179313813991620580627016510244588692476492468919246121253102757313908404700071435613623169923716948481325542009145304103713545329662063921054798243921251725401323149027405858920632175894943454890684639931375709103463327141531622328055229729795380188016285907357295541627886764982741861642187898857410716490691918511628152854867941736389066538857642291583425006736124538491606741373401735727799563410433268835695078149313780073623541800706191802673285511919426760912210359874692411728374931261633950012395992405084543756985079570462226646190001035004901830341535458428337643781119885563187777925372011667185395418359844383052037628194407615941068207169703022851522505731260930468984234331527321313612165828080752126315477306044237747535059522871744026663891488171730864361113890694202790881431194487994171540421034121908470940802540239329429454938786402305129271190975135360009219711054120966831115163287054230284700731206580326264171161659576132723515666625366727189985341998952368848309993027574199164638414270779887088742292770538912271724863220288984251252872178260305009945108247835729056919885554678860794628053712270424665431921452817607414824038278358297193010178883456741678113989547504483393146896307633966572267270433932167454218245570625247972199786685427989779923395790575818906225254735822052364248507834071101449804787266919901864388229323053823185597328697809222535295910173414073348847610055640182423921926950620831838145469839236646136398910121021770959767049083050818547041946643713122996923588953849301363565761861060622287055994233716310212784574464639897381885667462608794820186474876727272220626764653380998019668836809941590757768526398651462533363124505364026105696055131838131742611844201890888531963569869627950367384243130113317533053298020166888174813429886815855778103432317530647849832106297184251843855344276201282345707169885305183261796411785796088881503296022907056144762209150947390359466469162353968092013945781758910889319921122600739281491694816152738427362642980982340632002440244958944561291670495082358124873917996486411334803247577752197089327722623494860150466526814398770516153170266969297049283162855042128981467061953319702695072143782304768752802873541261663917082459251700107141808548006369232594620190022780874098597719218051585321473926532515590354102092846659252999143537918253145452905984158176370589279069098969111643811878094353715213322614436253144901274547726957393934815469163116249288735747188240715039950094467319543161938554852076657388251396391635767231510055560372633948672082078086537349424401157996675073607111593513319591971209489647175530245313647709420946356969822266737752099451684506436238242118535348879893956731878066061078854400055082765703055874485418057788917192078814233511386629296671796434687600770479995378833878703487180218424373421122739402557176908196030920182401884270570460926225641783752652633583242406612533115294234579655695025068100183109004112453790153329661569705223792103257069370510908307894799990049993953221536227484766036136776979785673865846709366795885837887956259464648913766521995882869338018360119323685785585581955560421562508836502033220245137621582046181067051953306530606065010548871672453779428313388716313955969058320834168984760656071183471362181232462272588419902861420872849568796393254642853430753011052857138296437099903569488852851904029560473461311382638788975517885604249987483163828040468486189381895905420398898726506976202019955484126500053944282039301274816381585303964399254702016727593285743666616441109625663373054092195196751483287348089574777752783442210910731113518280460363471981856555729571447476825528578633493428584231187494400032296906977583159038580393535213588600796003420975473922967333106493956018122378128545843176055617338611267347807458506760630482294096530411183066710818930311088717281675195796753471885372293096161432040063813224658411111577583585811350185690478153689381377184728147519983505047812977185990847076219746058874232569958288925350419379582606162118423687685114183160683158679946016520577405294230536017803133572632670547903384012573059123396018801378254219270947673371919872873852480574212489211834708766296672072723256505651293331260595057777275424712416483128329820723617505746738701282095755443059683955556868611883971355220844528526400812520276655576774959696266126045652456840861392382657685833846984997787267065551918544686984694784957346226062942196245570853712727765230989554501930377321666491825781546772920052126671434632096378918523232150189761260343736840671941930377468809992968775824410478781232662531818459604538535438391144967753128642609252115376732588667226040425234910870269580996475958057946639734190640100363619040420331135793365424263035614570090112448008900208014780566037101541223288914657223931450760716706435568274377439657890679726874384730763464516775621030986040927170909512808630902973850445271828927496892121066700816485833955377359191369501531620189088874842107987068991148046692706509407620465027725286507289053285485614331608126930056937854178610969692025388650345771831766868859236814884752764984688219497397297077371871884004143231276365048145311228509900207424092558592529261030210673681543470152523487863516439762358604191941296976904052648323470099111542426012734380220893310966863678986949779940012601642276092608234930411806438291383473546797253992623387915829984864592717340592256207491053085315371829116816372193951887009577881815868504645076993439409874335144316263303172477474868979182092394808331439708406730840795893581089665647758599055637695252326536144247802308268118310377358870892406130313364773710116282146146616794040905186152603600925219472188909181073358719641421444786548995285823439470500798303885388608310357193060027711945580219119428999227223534587075662469261776631788551443502182870266856106650035310502163182060176092179846849368631612937279518730789726373537171502563787335797718081848784588665043358243770041477104149349274384575871071597315594394264125702709651251081155482479394035976811881172824721582501094960966253933953809221955919181885526780621499231727631632183398969380756168559117529984501320671293924041445938623988093812404521914848316462101473891825101090967738690664041589736104764365000680771056567184862814963711188321924456639458144914861655004956769826903089111856879869294705135248160917432430153836847072928989828460222373014526556798986277679680914697983782687643115988321090437156112997665215396354644208691975673700057387649784376862876817924974694384274652563163230055513041742273416464551278127845777724575203865437542828256714128858345444351325620544642410110379554641905811686230596447695870540721419852121067343324107567675758184569906930460475227701670056845439692340417110898889934163505851578873534308155208117720718803791040469830695786854739376564336319797868036718730796939242363214484503547763156702553900654231179201534649779290662415083288583952905426376876689688050333172278001858850697362324038947004718976193473443084374437599250341788079722358591342458131440498477017323616947197657153531977549971627856631190469126091825912498903676541769799036237552865263757337635269693443544004730671988689019681474287677908669796885225016369498567302175231325292653758964151714795595387842784998664563028788319620998304945198743963690706827626574858104391122326187940599415540632701319898957037611053236062986748037791537675115830432084987209202809297526498125691634250005229088726469252846661046653921714820801305022980526378364269597337070539227891535105688839381132497570713310295044303467159894487868471164383280506925077662745001220035262037094660234146489983902525888301486781621967751945831677187627572005054397944124599007711520515461993050983869825428464072555409274031325716326407929341833421470904125425335232480219322770753555467958716383587501815933871742360615511710131235256334858203651461418700492057043720182617331947157008675785393360786227395581857975872587441025420771054753612940474601000940954449596628814869159038990718659805636171376922272907641977551777201042764969496110562205925024202177042696221549587264539892276976603105249808557594716310758701332088614632664125911486338812202844406941694882615295776253250198703598706743804698219420563812558334364219492322759372212890564209430823525440841108645453694049692714940033197828613181861888111184082578659287574263844500599442295685864604810330153889114994869354360302218109434667640000223625505736312946262960961987605642599639461386923308371962659547392346241345977957485246478379807956931986508159776753505539189911513352522987361127791827485420086895396583594219633315028695611920122988898870060799927954111882690230789131076036176347794894320321027733594169086500719328040171638406449878717537567811853213284082165711075495282949749362146082155832056872321855740651610962748743750980922302116099826330339154694946444910045152809250897450748967603240907689836529406579201983152654106581368237919840906457124689484702093577611931399802468134052003947819498662026240089021501661638135383815150377350229660746279529103840686855690701575166241929872444827194293310048548244545807188976330032325258215812803274679620028147624318286221710543528983482082734516801861317195933247110746622285087106661177034653528395776259977446721857158161264111432717943478859908928084866949141390977167369002777585026866465405659503948678411107901161040085727445629384254941675946054871172359464291058509099502149587931121961359083158826206823321561530868337308381732793281969838750870834838804638847844188400318471269745437093732983624028751979208023218787448828728437273780178270080587824107493575148899789117397461293203510814327032514090304874622629423443275712600866425083331876886507564292716055252895449215376517514921963671810494353178583834538652556566406572513635750643532365089367904317025978781771903148679638408288102094614900797151377170990619549696400708676671023300486726314755105372317571143223174114116806228642063889062101923552235467116621374996932693217370431059872250394565749246169782609702533594750209138366737728944386964000281103440260847128990007468077648440887113413525033678773167977093727786821661178653442317322646378476978751443320953400016506921305464768909850502030150448808342618452087305309731894929164253229336124315143065782640702838984098416029503092418971209716016492656134134334222988279099217860426798124572853458013382609958771781131021673402565627440072968340661984806766158050216918337236803990279316064204368120799003162644491461902194582296909921227885539487835383056468648816555622943156731282743908264506116289428035016613366978240517701552196265227254558507386405852998303791803504328767038092521679075712040612375963276856748450791511473134400018325703449209097124358094479004624943134550289006806487042935340374360326258205357901183956490893543451013429696175452495739606214902887289327925206965353863964432253883275224996059869747598823299162635459733244451637553343774929289905811757863555556269374269109471170021654117182197505198317871371060510637955585889055688528879890847509157646390746936198815078146852621332524738376511929901561091897779220087057933964638274906806987691681974923656242260871541761004306089043779766785196618914041449252704808819714988015420577870065215940092897776013307568479669929554336561398477380603943688958876460549838714789684828053847017308711177611596635050399793438693391197898871091565417091330826076474063057114110988393880954814378284745288383680794188843426662220704387228874139478010177213922819119923654055163958934742639538248296090369002883593277458550608013179884071624465639979482757836501955142215513392819782269842786383916797150912624105487257009240700454884856929504481107380879965474815689139353809434745569721289198271770207666136024895814681191336141212587838955773571949863172108443989014239484966592517313881716026632619310653665350414730708044149391693632623737677770958503132559900957627319573086480424677012123270205337426670531424482081681303063973787366424836725398374876909806021827857862165127385635132901489035098832706172589325753639939790557291751600976154590447716922658063151110280384360173747421524760851520990161585823125715907334217365762671423904782795872815050956330928026684589376496497702329736413190609827406335310897924642421345837409011693919642504591288134034988106354008875968200544083643865166178805576089568967275315380819420773325979172784376256611843198910250074918290864751497940031607038455494653859460274524474668123146879434416109933389089926384118474252570445725174593257389895651857165759614812660203107976282541655905060424791140169579003383565748692528007430256234194982864679144763227740055294609039401775363356554719310001754300475047191448998410400158679461792416100164547165513370740739502604427695385538343975505488710997852054011751697475813449260794336895437832211724506873442319898788441285420647428097356258070669831069799352606933921356858813912148073547284632277849080870024677763036055512323866562951788537196730346347012229395816067925091532174890308408865160611190114984434123501246469280288059961342835118847154497712784733617662850621697787177438243625657117794500644777183702219991066950216567576440449979407650379999548450027106659878136038023141268369057831904607927652972776940436130230517870805465115424693952651271010529270703066730244471259739399505146284047674313637399782591845411764133279064606365841529270190302760173394748669603486949765417524293060407270050590395031485229213925755948450788679779252539317651564161971684435243697944473559642606333910551268260615957262170366985064732812667245219890605498802807828814297963366967441248059821921463395657457221022986775997467381260693670691340815594120161159601902377535255563006062479832612498812881929373434768626892192397778339107331065882568137771723283153290825250927330478507249771394483338925520811756084529665905539409655685417060011798572938139982583192936791003918440992865756059935989100029698644609747147184701015312837626311467742091455740418159088000649432378558393085308283054760767995243573916312218860575496738322431956506554608528812019023636447127037486344217272578795034284863129449163184753475314350413920961087960577309872013524840750576371992536504709085825139368634638633680428917671076021111598288755399401200760139470336617937153963061398636554922137415979051190835882900976566473007338793146789131814651093167615758213514248604422924453041131606527009743300884990346754055186406773426035834096086055337473627609356588531097609942383473822220872924644976845605795625167655740884103217313456277358560523582363895320385340248422733716391239732159954408284216666360232965456947035771848734420342277066538373875061692127680157661810954200977083636043611105924091178895403380214265239489296864398089261146354145715351943428507213534530183158756282757338982688985235577992957276452293915674775666760510878876484534936360682780505646228135988858792599409464460417052044700463151379754317371877560398159626475014109066588661621800382669899619655805872086397211769952194667898570117983324406018115756580742841829106151939176300591943144346051540477105700543390001824531177337189558576036071828605063564799790041397618089553636696031621931132502238517916720551806592635180362512145759262383693482226658955769946604919381124866090997981285718234940066155521961122072030922776462009993152442735894887105766238946938894464950939603304543408421024624010487233287500817491798755438793873814398942380117627008371960530943839400637561164585609431295175977139353960743227924892212670458081833137641658182695621058728924477400359470092686626596514220506300785920024882918608397437323538490839643261470005324235406470420894992102504047267810590836440074663800208701266642094571817029467522785400745085523777208905816839184465928294170182882330149715542352359117748186285929676050482038643431087795628929254056389466219482687110428281638939757117577869154301650586029652174595819888786804081103284327398671986213062055598552660364050462821523061545944744899088390819997387474529698107762014871340001225355222466954093152131153379157980269795557105085074738747507580687653764457825244326380461430428892359348529610582693821034980004052484070844035611678171705128133788057056434506161193304244407982603779511985486945591520519600930412710072778493015550388953603382619293437970818743209499141595933963681106275572952780042548630600545238391510689989135788200194117865356821491185282078521301255185184937115034221595422445119002073935396274002081104655302079328672547405436527175958935007163360763216147258154076420530200453401835723382926619153083540951202263291650544261236191970516138393573266937601569144299449437448568097756963031295887191611292946818849363386473927476012269641588489009657170861605981472044674286642087653347998582220906198021732116142304194777549907387385679411898246609130916917722742072333676350326783405863019301932429963972044451792881228544782119535308989101253429755247276357302262813820918074397486714535907786335301608215599113141442050914472935350222308171936635093468658586563148555758624478186201087118897606529698992693281787055764351433820601410773292610634315253371822433852635202177354407152818981376987551575745469397271504884697936195004777209705617939138289898453274262272886471088832701737232588182446584362495805925603381052156062061557132991560848920643403033952622634514542836786982880742514225674518061841495646861116354049718976821542277224794740335715274368194098920501136534001238467142965518673441537416150425632567134302476551252192180357801692403266995417460875924092070046693403965101781348578356944407604702325407555577647284507518268904182939661133101601311190773986324627782190236506603740416067249624901374332172464540974129955705291424382080760983648234659738866913499197840131080155813439791948528304367390124820824448141280954437738983200598649091595053228579145768849625786658859991798675205545580990045564611787552493701245532171701942828846174027366499784755082942280202329012216301023097721515694464279098021908266898688342630716092079140851976952355534886577434252775311972474308730436195113961190800302558783876442060850447306312992778889427291897271698905759252446796601897074829609491906487646937027507738664323919190422542902353189233772931667360869962280325571853089192844038050710300647768478632431910002239297852553723755662136447400967605394398382357646069924652600890906241059042154539279044115295803453345002562441010063595300395988644661695956263518780606885137234627079973272331346939714562855426154676506324656766202792452085813477176085216913409465203076733918411475041401689241213198268815686645614853802875393311602322925556189410429953356400957864953409351152664540244187759493169305604486864208627572011723195264050230997745676478384889734643172159806267876718380052476968840849891850861490034324034767426862459523958903585821350064509981782446360873177543788596776729195261112138591947254514003011805034378752776644027626189410175768726804281766238606804778852428874302591452470739505465251353394595987896197789110418902929438185672050709646062635417329446495766126519534957018600154126239622864138977967333290705673769621564981845068422636903678495559700260798679962610190393312637685569687670292953711625280055431007864087289392257145124811357786276649024251619902774710903359333093049483805978566288447874414698414990671237647895822632949046798120899848571635710878311918486302545016209298058292083348136384054217200561219893536693713367333924644161252231969434712064173754912163570085736943973059797097197266666422674311177621764030686813103518991122713397240368870009968629225464650063852886203938005047782769128356033725482557939129852515068299691077542576474883253414121328006267170940090982235296579579978030182824284902214707481111240186076134151503875698309186527806588966823625239378452726345304204188025084423631903833183845505223679923577529291069250432614469501098610888999146585518818735825281643025209392852580779697376208456374821144339881627100317031513344023095263519295886806908213558536801610002137408511544849126858412686958991741491338205784928006982551957402018181056412972508360703568510553317878408290000415525118657794539633175385320921497205266078312602819611648580986845875251299974040927976831766399146553861089375879522149717317281315179329044311218158710235187407572221001237687219447472093493123241070650806185623725267325407333248757544829675734500193219021991199607979893733836732425761039389853492787774739805080800155447640610535222023254094435677187945654304067358964910176107759483645408234861302547184764851895758366743997915085128580206078205544629917232020282229148869593997299742974711553718589242384938558585954074381048826246487880533042714630119415898963287926783273224561038521970111304665871005000832851773117764897352309266612345888731028835156264460236719966445547276083101187883891511493409393447500730258558147561908813987523578123313422798665035227253671712307568610450045489703600795698276263923441071465848957802414081584052295369374997106655948944592462866199635563506526234053394391421112718106910522900246574236041"); invX = new Apfloat("0.31830988618379067153776752674502872406891929148091289749533468811779359526845307018022760553250617191214568545351591607378582369222915730575593482146339967845847993387481815514615549279385061537743478579243479532338672478048344725802366476022844539951143188092378017380534791224097882187387568817105744619989288680049734469547891922179664619356614981233397292560939889730437576314957313392848207799174827869721996773619839992488575117034235771686223503753432109309507397601947892072951866753611860498899327061065431355100644064955563279433204589349623919633168121203360607199626782397499766557330887055951014003248135512877769914262176024439875229536275552947578126613609291595696352262485462813992155004900059551971417811380559357026305042003263549204184962321248112291240629296817849691838287042315081511240174305321360443431828151494916544519549257079975031065878162796354481871650959414665743808139995181531541569869407871796561743468512807337902332509141188665526253730005224543594230642251990087733589007525112167263423390519516256449883246668629021224707375712622727338433428413949392025850115667210623921718901967911343741990949302086324763103516167888595994199901050877513225889176661369210157058303028208097859770127763215523939861468207799915738378119618747554412375086445437860273251052247756077507776221362813530868165655705386685359911214158077212070547799249025199149855259404718819116860232965928237115542481150889891404357953958481898065458954043329920713063630708800768137974943538317752638193301392880955394137536731355620955959090070679151660376367737587553224962990611993116043816719750207025425808646316099743937375551893132692442068408881710995700758547738858707323875565857471875686940646047429167584711423727268385892036636458392833001756615866270699558199491729858053490121978737818917661006740610761094624643161886395352064566262837961949964487667034871397969500207900136776007957344719921604800547802174990970957584713652227989780653799485416699222984165780755356948607100913691216734295861691344665407097078511240417367864819912442350663678804194158714154993099761737213272193732393407494908420566243850369244966998232229913311207593935227986256599215521655598020156607200467654597581708047752311489086185202382010867599677809309842496590321414570601045442047203504662634635951862210065631021874782727929061158521436016723590975344929196094795458489621840187425157383666579177256798087173733327951346890281900727465438348622776132766145184605519469012109642555607413067556606434197546993313698160065397701348358292936701656323370662867232146199029970623963946751688841968331190830450128678862572888076776712301759543290034129413503754912118321743371571587845246951266342226599731188319378143970137748846011503839541138007643678512440677484707251361670831303459421762344359187366512977037499949741710623319661220278428908920322976905540502282214049704347949020773347280774572019934978634712362414234809577987377731138461569700461141142881272772640473704021482011497184562231443936007956495190600333917044246069283754730087093529291313194380224616953419861941718256729333838355387758286663113301339626432830420179142345724768521413569035202226901601398953684471397924976103155196190679416170950119507253129806878890841163577287136608400063019118948687850508970134982858172950288460664266491390232698913550787884807218108766710565848684406989687323029326457204955333320990628131468715106028181655976182957338686984547520526999565991403632392864246628095152579496816578234819495652757983633998789749954303979637453325892036610791665504184727013707778456936494519945056601533713875167319445839648859494812327636622791661348869703385719476647478532480486900399561988080437922696685472273528998276543083321268496587274837012245221722642399726692569419883679885485911831256667980960764235002322423334410382515860710585848226880623226822499063677185391698088769361569819479656177105940903061079828019773976817673096733044493372481745080280801823574842440904615066947945076298807768381173684623189264548867813225032478621256639064776678426306911276302350407021749191164022475087195363106803748147886807267956077634420090633836590389759183534790835575848705523481449211878320546456575893638729825789942990686510544718331859614495997161225380146643768905358867009116039049851326124097532322687306798405750904171106882881981025965454909318236264446568102333231301419675114867459097262408224343276183121232233146400016661222921236256065251739190320492643322771532296094398654155426328824031899202212656610415191669700610158191169965964373480579677102766479140416152795100858451969529414203285394876900861833172905672064986720870931447511583227326482409156199394313268044317610915886265655601104922641778037484242184897820820104309936194227441508011421926813286271490879831953887157784158685123556604447402297284985047849745742626404353347215132911965452191483132046875748725826421949717943014261478208145287082835941144453095960763025519158248005068936096440523468459800204096612492606759294935638100362366075030760575904686683910042713795418258112286357575841724114899985157951380369842064841294277038227762951280419521109791587570282808290610303167928564653081204120662378317314054417250053983278750305577472121622911389684206448155454548433027284687339854326806188106149613053701860331784273842828625874268212314307428124079569523685300595615721253393992161836844695267009549343803490090289233276569241648173471902047426058088875588170700689088526682612526149190276606204586293868933665703532656483030420358845288791436243434043512984392889879306444437531697648902381880268100886427971725724216635878792168877960382957477954466205726202629739104252410365561269891423732555651319766201070310463331968788180443612628909042425957946894297748251653644772047205421996238304113764694479671602673213675726577358572394647345072133704337126402389795614679168383813319167735705882483743643455975012207892129639171491240121784245683278874769309917986405696247286693223941464861909171814672375725812637003302125351537024327151773926149039984400215533536618939629951245364869587342621682420439041798963824888097502342118368827981577891155036924323808306186908760561787725614647515723053559422866464839397156112752603617687732812143507366427252593424485218857080221926436525530240234045105858579311189216409876818138152138400790929238328004313467203581926374578399726868217380640115932742062572247139776352807285050816741962162967038062426372494456362101690247380381293264471877744909261474545617579660082037897182734748517883624811345838247600661268999643926316077276210849157869001691065606270237686820147461211913088747249775425852579614847078148123573811568886210548525283535660116442972924578723859338598406609338665687631610712972814636888119909937870754636734532262602172471760425760865786891242809595789084674721170126540879963865271833374683887313567802563824405632459000666024472183717511840391816244830735899819089776219951783978162316232707778326788058474440996967504484724182016681951335834201683359140446635794214205857769794026199067990848830670121251687842904867729280686488131463495510681080896201235522513816949292286595308780001676530422904203247328622395974638055023828824272339240913872052672204711924280934058024313592837471493671746344662009491926679546495408983777026883072752018307512853487690033244278743861349741257631909296395503844154204734865781253814182358388255524244902344709354231280866715441233323129348949254611245826664061906681102768343638921064300285265600175910362659350994569340376731485068500339884621383126862132520868244104276631759422301509081265813140496977297394805744074519738562298721254807684665749884664357157550147114371408757475938680467380582289392289729953943886905493488592061788743850810533177814213241251510198607599533167358722256274902209943012307567487159111735944258717528926187514406442640492113132225994262055173822569208650368686538310585691714699194300851307986042243698944642647610330996058198393536302360449663850254744399584268662135284374968852431970243352793558705965970391709078421391576117370624655509086645832397810637810745078316444584651945562668556365121297646675214393620289629063966724758215342510035057652703672984207145174820713147789389750889388036351846121874165629300371485064993842552924849566442153094750113639766912820709160545225045710063086500791836978379652609975182308126420708527780025674852310375754636751724710350757013913199140056023168251774030006034051833492604168482489825678476105154502947428246204603451279366111071665256807672763153736569286609136119880374002143904185940355981166432835159736233173094295497929433095897662428086367215968862811146235869935552747979786045553121411706081674955052818948701407904290494033677681418174122943888744513005646291745991739476633794253703878084594221442701513956074525091628219007654077797472903256964036093657641165827067802767129828860080314130197758534308349014133737775668761111670023934917246816119065449455687658518791543168073771881979878510483376757587145593590330815334785406251283752192438048609398697197839812002595549384290659408433556345230357013060171051199958804199389108630905491713408807373360857296809025762364619586993925443672985871032405974493916659896386595667160691804645410522508422887416871916988867672767766355036823217634225025584667491544386796416380108126585875550613813214830609995365294248815537634497346843371763019826684415186189434771031868161791424882126944178638982576156715262316588010994178360467331921541418551980210540563017377956570988680745285458524206974027985737707100124123028686157330792171990011742987828330413060414017053124814940732147321066761052753351440376789945540944443072677022709669272492397108519877438667349640844194899913345405010892846487915013739182660387493838285961998684846110034533042418482911925192110885518190399364862616855938742264140420996464763914943519710390037292618805951887263889001838301232098457528646384259406892187168518534552773628726619713706557204866428210466152131768299171743639414248599191845356234559288777075935262785486284559062290001298442530002665372460431016746003513775558810587844378058848287783721805046040250144163829027118504896351748383060570842065377511439449950927826426833300260179969716009976369079424512557274848252076805253856102723282665982389645813423013533004343968123962130504267757832524299484749694022604373981191164460281089039538437008176219733899445844176810864773182888155227187167954086324060396967375161567152859994769646120528195067782203075700577700417750904464632016941176937122876574110853156561177667992650926998254548402940776612698163428269088178582370057748198639904551810929084338471712072910258172872513660074428979164926926021822543871560844616406735147644404347926074768860714637494101419725893628372265822608705781448937379465685834561638466173235019283777004703332308249672335018842773064055917471768152436930049504428432012686249272166473692328817558690302093512221677348535803607139749886940727002041171722162758166656000901959523060808250058972636234349635676705601116797999808890671245024375564214712282394710970016156067445197859322415069173378388774053357402576471767323264413087334808055532709235040068569287459234129212021812930398061656304640357906735526998851296925934209906533447707809409874310919954446488719593409654497942355073152580991746564527959837216380371023870321914768491492386762037729080796682886873067588930525845740096672775261052948684868526985305878987875303117248011979824432169008475181061422849300205310598561989029972166767143129921706248328470488872837678942947888993166114114068253627356617233057021238427785828096359098664805921281629010206120947645458933494502182941877705430379409021807920139622198981123276358972143516850048225068615477612149255885420905169720764622836127232289341185572846045343756318840206774624473263283423131064768512032400111379981169700259229304807643436270808879879534910404294664402567794589367777982010382583362909088005604335764414160010759288562292152873623524505317394238168984464851935459064349889266138282932671393092420283275738591958761709969926576251664483226249816553028039644459805293792079467914141624238057372652274019277936872978155912626853840736399135192857152969773930747626241094761881516121582228793671596957779148404020788645289451865813100403876914178628793552398838460578135327614243559439393803973118169783032762648747744473149431801168177231960714397103628420163625418192143936653542760395022942288931649838566862878113092984559860304535885130301079088401379405046647843645084077765689431887369248209103654436668611118896632095484527747772095183265928053973287091221765853531171941913206757793163983495562337709826817065800612307708793779871433797577150768100298204751083471648749075258857509653420745939086548795584784560923565499709947736700826982916313809964661748770439328449919695431629630125413906750141595952044745138803382922749720191423844938457266256365374320319061644703496274909819618304581291791254043853053643146280720903695033240258752981040166210945934288742929576003776985534595464470610690191000198985136455678236144990268123862510662302739798510815069761716448888107855978658497754044274358105005502516206505755404304534146182486653358420220836763003479376082546767350868083505920971520080034411049098854964438468668491627487371005709736689189579652744948526769018919390001311437885950901835426890393760282517677967351181042478349925727085981315654858103667802769813941505646284232745290809172891269965915564753703207165412639118060919769757786671044799522797523351303338587638988379404408208110536345116234470918047306927808198102051657497965820947207746020281525855053729705476851319771840504457579225949529875969590256830892684992304031249168231447574860164703630302510967189155225669236669244916964850797920744118436414720934516906864696606048885845327103611854271815852916750130473220317410508840908855044799311837661197471600526969238717487166512078911540619330975216777678768746521187705532080782547578823691400936430167896755837169688505731714575082616317493925388928283965795716589358020670075530298580943981564456174969076926671988279751963871271190852189840043460564438582649221510068319447659569693471054633438998647549092203244309741334559308713778165501500770388729892922472843024474836478542152196236662330591905317714549973966698836348178926258328140941096479239993596757736749079359501445372051564866733072752097347542263239578324478642733667037225108496035545934077006579220121499030235137067666584202405822527496969526912574823656264346686111688823121971332624313500652608574524680430497556927988348406426373301460739614344996997061362796197414638818071691479629068079327746749961407884855951227197108412361161769850739732605380894781676698912669353437946667849797247663785610436182570374867335058034908108505200186640822312344734736176569215294993803575919855412640384568168843957417890596083918093833238352743673174932386930667195004979459568045392907372219230861602881754939751233455586575038503359277397375800210609799508305523856780768941182501005035443038363925271209822630742660780623088542624685019767478527455630014599560912994003104138572240855341627465256174812592159625414508163753164928017905059375980668695801818406072087363662110870351649955350568607623442782980443138070903006421483491994066515177672045493005860639484997321203246451139634181178273748391522688481954855348279731780960011619233046934501456020179622018131611156500697794739609273436503379130516897854740268267964088227737229137455774449807984589405211708687524974954684558223379184839521786386450229780353893270132602333767591463191334661001536994381134941810825914886021872998750816711341579140675556740642148964750748657398333586360620544820986552175163993535062705490729071601442734134731398822514425404454084139134452680416592023959130719231768856005765415796999076560107919839834988138607487080905046950705719670428540942793353912014275648735282095210040348163792845575914107625159274753083262095277960381203717487735717624179306757038292361014045237560527208737038588904832337305884398233905751853880617412120772578667710001110245491461053355080971024947415842546298464372553354822600194099067681598059752439597051596736754190069272892896778818921900312789654468365710683882049678249553673722892537991034552034421126185449306549189187768903419298810470337282544057550510070814430981396727898784902997371445879211448792216928817108317118710069926927362247815703078704535420181806237759128211469796867542771570469702844298167705272070838205327335448411952821103595261214510855601294427434693604298732036703160019094437780488792129768910391452639494428636563952775351815566857209387443611764598149642691802785946491614315901991627195954849809987341591055016617466890893146069446803792699236424507045037414314338260190926463831364141085500227755343509861064902977587838126287081214473592126274169797319720532992690324280594200496044035656080428700457603008120741848297459934702154820782911178473031784227251925897587157141815900015502504692530479624208440864169959474399429376090902543971332536055108054278483879055541728814972394467216834573033502436676156576175520579582383800572681791477028265128859372367709661650909065410971280080047296778255601370965371991041435432337399305705922062745032961651152463902281448799635120689746493719518551090851266889512162487376535208198030776116728298280326291727879604894042284448754382774261347248626852263796280544296945763486628522693031130882341527397737714236404882545871108545820410534157008933915364926767862868000163248165573700158191949409909287382676730429222297967689237937519976323336597911363324077467220814125368532439433492247073521240362232229102132920109144317953379314514740019444098144495034940074961155295610028323751482568331018900345013505857809583420139230545635788961112525325858550702178141211994333315309039352546356572950678349445837015276924560562109273664768379960968648321684959956517107019688762609041149731226729580091335848090982382126911947458231875708134677836626311135018008894886810753655518071936708091445441681966581588148852960847704566681606667701055695728128703869270188825691724827568228712869040735988324302709363394499774867906258308950596145000319461759657898096772224252892096305595164524112999306417836075026803405646224121138478238850762311813205871499233090771184805805973016795899613092417686967600882308109630258899721932621578081960568048146459866283486405766957648614844402503853030856859308634361969835021506984206432459119093492378468897845415800273911244793127468899448580189220312706873073868644901230036505774762691660250318536484270038342485760196291646634199876322478125488330192926953279833337690516996565565866401662426453428439252087017124899000143466352688042529049774046111871981836656306853287820264298715173892420369687139135717631332883870569069405625490081867493712786124798319403870519367700960219488996225784059442092494245717703533570888936829380899854857014545852338921624526208699199361089345638987546165257594330889200640747024890747711283239113399268851064857589317706851377508603468281932821888696341834474023670890899877401820908392921740413356448121093711607473619942993330173442227931136636740107234906087549105352606864151305860156672474951776282119530775752671139315651620400971371335139680229910389348668960896849208652609227341255127174614663458344724253977207821799330827365637973911898914452905303602556884371062320742493000598853803142875404198331624315306878485075037179109470505622664390821192711820789525117148637417853518892312531710363466486163754820109689431777303486688458899008697474972175231398524058314145015480491904560535699944264833102222444965903350016297215804993352380855648085338858424174198842094106763153038592931299084136998515700707110524249961626515061439225863141644648108379199155927132007889691731653138641062477430196739447939334037489223096033621905810199329568981019083619972745644704778702797098141094798427537715061261102096271849675698683902324998032559515512888283389782432914049493661878944945116636597022672340910442096876629934521545661092192327437462984001447361530753690703100894797736597623667501029200489645281495939385901781145598917104603496894709454194733349669412721760709116111950319517363462902619448352157144433408974921429906536096508782601602684609701048990057429584511757414159711364940381141448630684810172962921726306439724336593751157523642347766302668153072160319435603441278135075189607285832095126635120848510314867266534033450859642200145535226973824506327026891481159380064450948672488747180153971286369239271077588121254694073503311947875404919703959241300422658877366807262510761653004455085908397725609390010054710396261810047437581079128137671343409622343427943636461588044445899364084194063406135493438365490786084497463904448436869346669362856426712011515134649985465340670403124294607924369354134120239099807405713170232338448258306634825862730044939290771665950692850359278976183206927484763355086532186302077471920192861600942607961332123622618643468456947496610744793493810156243382385896573415500665351531247755524213845918363985427828032731017488618330286192432208769962464568335795033935520348674986810874024076882866925823936097104810508420618945988135504288410397123586286850078555270897125032020572741451270339426878646330840235686932348502771085735184683174463247038279459869469200456183718642781770575974039524581214249724939080463256691255742211157904663610313536016221442413551942651724255235475324445298580489111766581289995984844899297170408122667377918510752517464454241809757276581792836410089741166161250553138025354941097460772084520567960469852676464196152853328583891363155877971442212158780620429556269020976953004560930569993026160059760744910400924529832380538357942163178751780296388445060933027731380866959507661481077417489169496948340461356591049481473393402717163701567824920814877607702492629624313851031996970470658485330805289774762494774347424641972411489099258547706986047112007981883255672098124184750027394710355519736301559720055273300284028138253623599594107310742410959498329418544159084519769119308654396432719856367865506161101855649473544251092037737439433292540495937439732232712515252579671843225112762866924206383158376359790562782249064185305348582428212108384602015719424711244167628061374874312712483260856781741164419620588301472241711725504741262798163295798534674576849997294761918350349083392809532917497012513072077486679859946453933396395975048854858617283277340980121027681227691581771048821840788821725412576272518173151852738716645117887946198752097950628697376519933085396606486278369143353214223278058353275072560747457237719581153024500534008466190526883333918631695221368854415638610641995104209854824299538380519913274642892831897868414049675991613297217026746538980606218890071283912729877557231527421897161920824447274179535240238218764022024753036189270640031809838809249964724203628833283543570684163870250133659463259839317042393055009515964294847265026854780974446217578797560572599199131174227204855862472112372788655808543284884438658356420438755876989401150877349908633532696411983075158035329874879323703926599131114391821513148784740567877905275940078378237628984864691677225933417660909701771808203008931788751278461062740830842551063499710590695771564364197604434677122342305773943351999549651174697372634378204488231723205776997207310631518567321769330484384482813764786103119755364150545519335677976258707996864499920824955657973197338519592966618597738947838714152236298724177543816791723238564996943851796306373589619071284454259627219248006455919057146784736036603659245601260429289624624296913120391968164774095485486705808229823449782343994672333013642798845842896149104999847687265210450225554820878145337724157442925102968526464940952466150483419621714228214838522871315118382086541458625856689047171464231992481663247532787940766966633244960221895134797927134692071587510697754724577034761860916042077400197274844795027418809889278885900182509771228308468979550308196445131374300904324697208392842134223091455289232186020675182528103040129777735361788400612295819236038965380173494579745395627256932108370733395370819939095708657488375883446991208745679688751175594761590439434117511905519980738438344281378106631777238350558725691743047358324759960753435409590510024903149383003428474089845265595448547738667441178758983341148511036362367051025356731498472209609155753223145248203821800220422847797519737978034845738339744753849467525801635861766814481135843478488769235323898736120904830900336573230912046634654710505335376760136644112829573425609789950229593996745734781690755837295765826485783126415823996741333355486312489399436282472291157983043385567763270567619536822307462314029451183791542127232296273934621043627617671071748696737446778443206069334794454744837895047239278560563788891485953345117296766346216863760969629709384980176565038111828708221759494968884496244072721078715243226558080230557948110196134566822600007268267872121459836472329567038197260360511776309771595253546152025459574456522701426386822682051215861051903154694849276722447469905762510965026154781940762903911851897088595889419032842361409954852158678791045613591508398270405417981863335445547434036805083832810971215743867564381412299056370794858879420983586162872196061721315942739087985641101639712087432304757148226541286675204600375153570676119869449876776717816784165940539600324140940273595380018308971529239962565835016342458679074759883679024970681810375571720472120213559611475789292879755313022366819143752188654941601369173202593617471963758337176580814009816914509006254564326905840338871316016455206095060755704307024157013036551415974687472532300010369562825745397251655511888262376274490501862941889384547803227951906363881011170132925201346443744564841869745165645048928234290034678649966435659797532941351907746221850182298416529530969563354247284137065352514292181990354736442444152667029783885214723953229977018594994494095803543384234677347117261348833200531541954548851681539871692937737247440782749259781596164149112469078304477889304513496544790629776612886498975962732810692338137311883629687372195843994599366247142327860635285870339687732259128249410088005723986511007826568260975489318689586314034665911071267464622156923415091657947557234231998543696129355858187059912968676365129027484169289802323281857080746153199236999668703501044499453810232976975014568863735031862783484612960276217447713672113077904295194619360242390376491453491104019667727565019967571560901159960481686883728519286960177776422430544489036951650083609850498775096268388731121178771456098623225277310355858634258551897316740790029675186662640587805276084267477718717976381279698745397607635434792155837408670984102261190221783025533238152134296101723084164299826152682019292115290299350426099651647187543854741812920604067962070944688585734719790152872363884010295830069906554593493180046113284056888376926425755862960634007157539321989653093681165531129861539377185942268252243507368369032352685174642024156247069245829755386500728585312956535768252591178106219862870443605944054254613518524695699420428788396579791952957833674648287958534074173567655832462700138757794784174413011872382199289109539951724631090544103627693293162033329417093123985662208354958090079160807840225423781013086394116495801157861352858770098093441092603002941663985679481803276121911172843012574052646183248322311569855125084152057191234545046738088198277646130221819506280574988211147321039798087488014888153711080821317852948707617336729000511263363196565483222985721444551913843418351873361958479301515368999175173810337961688145210107096417810895881331287946459863840486587250806842891246321429569705766604156703255041826255585819237661136340592952863443908745976885999986771671447800352554274676407931455092013305654796888817186822974133504490717815958318299885673893014221857331537926494460259207531440283178715822163918057784682672106351135055362372690072151620927142022035517495518443695670497827754876160542683391924054020932708392261228222079345175900320204040696274997807580342565931027043483766713581519692568618258169187986007360591659743586735665124568973454430400525979335568140772535107550419224950025558361331298117191036865724800943877606488918301622374717826003263716667062761124254987642768033784374263052043978502833108767899412744950204847693565123480015029630533952935783730618441592373218512955656783466849931279696970037781932222823062545447920932077464962596218014908499744891429928618243008537847167388415558517205874440391036524625186707676585928238518547884209417731088511883773123792776628326502555960586163250774594227130541750059625785583593427612430159082841168310163307242544562091157670021975977539020682780883178944471129960584286939152395500458528851310449299393416191679439281136327648605541247034244238129982453695471577412563802119653844918431745841322790196354784188921335121581262535222048919273079672482866849078188708928671062907097734414782975693783562737296108098786055382559854978739059714961590786919171468367329001140278367465503065723712453811866462808219063415173043449852604795834551328728239071026308363411032887739341891299074333786750773980375354636044014344160765720404360130871805294846375397016535882446337075868905778188157252158772902282946425791478106871031620099193140098240027774088272639421148061034663831797273571092721660073201510828188203665252659341635946191471671267751462033687012351844171651251135581836838392656724845503337735139342019513430367461763664389294942840819395289031082863758451529078042360169436124845489902844874099343868020091499860044765000456801790235763457464086418406080839686490753390171833121308500059957994146328251038905466287924783743677817714304077295911128538109609724783363434659495843468145687487760168952936717323233731171419083938530586220011337573925355660166866400237007620733832066366445953418607771159913181656754764947035515288564101817056745414574954368631065573817905075036337912769115215529846523207952695005813244667408866737228085958698576734558171290391813752985292539919197622457392473289688429536095001226213049924266434338467351088645466031528905606918158485276161257943713687532837706782580923458870564417818129106792857642043372895725185213214134620131166409089283818336835356298871140440650319376412664792417359552583984565057408770239841828484550840762945631507455985958631686811938836555988506484317208328321926325675091097262242016274971778153637433478402469392124599043245180568653801263484705311183769962663600062950050158513986898720929113973881489953244808089408009172802809067385104658874388397790302664621497727852084830237053906852460754401773603680402251299258504008068347006224378615533282547996031596819022547816479356675454863854816453960655892183825603767475224108095423562474319543142845907059912363014923463863455637355833646486158252814083545282813554376865219859784283021144815543339899329863166689511672126267569253992367822876860073101713656838699496284173700190812656064690113781872353951160925143924526745620036134403584831440215944849035557871444084244135071514011528210985798500950160062368631336416254719596570277349017000685078400611152083874932568769260774213057203917444455402803358896928695717608233450011057209862787844592330007266089080339735830623827804169544901846471621771293257098222801892403774092967166399653187133153574359077075048174884963571374458384808751921567288657702413404301424453192046181500729277930281326257137471705680501287614830333988287776072535488919005970275554323311349335142228327525904581622593742743712003010854903465636061343201098079741227248284339404702865498229928593544771459308908770800046724669366137312973037941876383780918789766649873612221710635634144473680019518236790463987664342524042633829364040042305440963500165204305586409799281496070671361592883536704290297717248898374376985870027081825985328649581653813891618945156646314192433557530401446725783101376556370506428077440808440619128099021394461444114987668688694691225983534020292228020482820048969555830706867896947034216048108788525072457367824332250069959320117395374742432990073262056943482460776755816533414394037874539394829713844305173596369025939197729359628528368665317349529015943382309129353982327622843439173941645517032767517615717152349067454553172535475829967021956720039988580288218078546537161248291064200962328600180599742559689566899198421401178500200959907375122425143475624302793540026675918922283506334148544854484410183119408483716849150556704561545115395478182568879839307040909768365285064076079058282463428814368193115560918699890513224637223925163878375233259831155018686501937163698587195360544771952862150670300568979444411501733223016043653076556320507750329968568300146215676593858161924324284802644545054005626791709453871886103573731712556063904075692881071925627662908943607321460444107171105990882656963822581144456005523248858873883121299770424520014675686148625518886284984420340313370796158173327445595952070361949515739680508235689764279152650807411168462806124234432456322373566194687606847886596815031058062974445899739681971530357294627273599475583964494956805929391999892004504433277627057297767597772195671198406640211314375416878470827320701016775357644892988440458458181476468523715553181962897473335518254327508909315013021330887912590613922247352979010361653045993558635604649917524610943206344899847145971421669368655328787700283960626880418556810999908437080296019068420101750599290325274346448416944150581700759327191266106306545992690482365222057872357442852043876752700633356719779341918676066243948651520060601040666469926767734215634971346239692048503938034072797960421289379540001210157054859796979146302934923794787617228448903520338725426956168219517903447954109671957968820337534499989189249308039618824021811645625326555789507769854524590025688148900593464497964241524253656436730518623061041076091983319134698518781216829499284631085006841264080694465014621634513595082679105367715788673427104567719751803349948337876117817998658139279761812675052073140234399789907125198778996614735606485420849811446826709138681256963614599748522524162168897822708768931804193949329168003050952675579785716880727337596389052521591671891166526751583005074320946737584951397710480007020969819710713319357864912049218225184247720540147243264306605211654257774806839887837900128506056266209773232193830182975154523385106305402875472791631781860793766045562576336948139497369028408220611821297978614203482983081201562516720957526564975204924811410668657371910308599061137507484763638899436965828597576762624201612304786443412444603128830764763694315268715368003519031514873079527588436882260913615484987164224421255816348262246924468200126563316393817982407404737664717904193939373048754045546446728402874557923714470320395998616287083326059352068567650770335200322653570406266820059057566379057495953497788001389979754455404217087182972411093300957791021795453281891836212282314597440651726753321760535037090345643977607110366988777349305998413019451535620366917469469210423790068670112084488824153853279790093007019503695670805136791694986652302169702238986595427458966142240404340778410066106150389955570468414630944912811877036077894248633305005027935802582538925155741468263695742052312805443489273645977745547388783451663325432563319780099732288601549505147892283284859501165239719629764214392264388734388510852582710833128562361486666188756940603151046780016380262895703316044161969874371593805212184979561972975372698150241098358809200591448033216024335604476361450481665485991646796767958008090867956371816930630460727450399075375830658205315419713731871412560315301464257625168529585108528505619404206250283894236872533063349690112588086438297512583188655004282940424374872277035699743434070307626677182321814337406398331062875691526753599673903103744529009862533880569663816461276844090556627501531442123838723650219700531507449616682594302660319544882286211788427434450611508269880538119637794293615813002390534788877519629380221867281032239856473510066778700951867053142966169023493813016406383420130638791549081784532969719378687569489757873600982288837696137097092811815744149025381450606936190513487801884145887201017260021702245990907103192734680399049441395613944330261388988626799574595001254532751539105830064412991608890682113345173709956991585785812092707620053158402093779097582896421174484685971428013173207202174079952126270063514106418350101110795416787219485475026785144135473109876596262875791730755905397799543105273194383085393155643534438941759122855063072357866668055692140725864078313085095483783411577563424157931646278319442982135610687805374647639833068028549269088835882410868656099125516842653615716879690404700582753514015224107965327178973214027038163064791568449313799628738321695324970161311872938068743807507167974031315887676155211982915800501474573029961899572563700430496223064706164450917657941605498787383739587075345944130555435695479256263457450135132759917296904847807878339329888785245757818355302255716043162826727546991113457728402183281571148435127979942872587248556584991556728809543563623942683165223340649571974086313863270421414725336389714832308528782044366823886472956391043623932833325661367979353383056799111554710488357338463627618282803411447525525096579456798972563655325644608765250439437301841318294794470376326120105881526936557361402321875837264567065456391917953216555884095848113508883913829404149178107960987978376687644678236945562625586485485726910128765095733353235987701705273750911788066268353096549254788125108551280860725187742376036727326268142340387194681592106126691318524101134998675725958331569133038814645972010214445536731187532487283246835857744159849240433918791368303413066675478105964765836397336629100069764717796775156952104815098239764651456873841109062590884148780649983062381952589909152483679713897715662081407360377190198797159555351582706545030052959870121955450423423629342542200129904195992388688842866220701883566235976448537466149815318315934973161546696587677598225499897024730259759174794094137960953629841044823069983254451587213471598192925931023375020040022358197553948671528928533896424263838990592394308858218835036020616727735361352694392490807160540695357540668186555877447621660979224300021923417349549350245227194949912914143199796813142117207709734426303728074040484689758163791762456510498330116616723996249471694593059669502771340977747534201354901293803306627852824509578088084437286866444103374632586701560068720209943798525803531809665049882567815580847234932337655509872887143069568970446416837479837922649162844842519935463382941497034374041316118397487499094211718850281178208870959469560014935488939287580597333114612691386258250398585317734269604461781414741139702903491764752874634290539307522090146040683866779184389662230883777343120023844825290478844333065316002140369811306212126305833277410302429467139864661713172630951327818738879750137572398498384409074773506612693542689775535861781351546777750785952527693003783711224346346326777820220956487501803730355393765169416982981949426761565802305273168549296679686886229715872409439279665503710382475339490008768070215212560781009376819052588366652902421719962781351382908740378045199063917226078339472035701898256009189960947403729021413443877618552146050231483952968711658578895619304789548023935304757054929903221446636531455467012470012069861362584187142778008814242642564739064540260767434331055657960698788175790732414358028133661045328917308581713993120680262741660001786575786085044945897843942616088880411698192654961435382183902690320761200382262136926232433698614399977039186755401385213770127835035047600632982000469716747365431571254760547665876240796161733142576598106454127826630775296320536739364094876213390344608145828571282227151956053682954843331469032804087340817922191573572894376827728525112441430427743704380312434816035529637614220036525872888106103526549143125077101789595880536498956812518603533703486989540453986833744531160790397400609272883702034970461864563159666358944266235556651421598667130881898609580758521293454186040345306795433461662275248568063610286351151383783007050120722159084500960920216870561331156046509317358035237892494495146263302419084826200264016738094728330639707581029897931750021456349674173510730218589323221715832285478280328522218811476431142556011108073920855643963832299469736906612388354964296909199683600754130272561098808235158068101950126740524540394807508992212023861710969158995839150570927217898397956618114512357199719306186429100215666244685552311648981929110964251895666955721755258616226027610738501524136812264466588105522058188437574282563151232732693905587432314329388524817932046209317888241983329898125017713039548143277160123525010495737551090752859297234363241764235914450709711509345472580182800502934260345370859874372182167215830965357614010322564964367669147557401925505008507129888088609762401249290107148292500924632292274687861249179390333633800018025487613137754632761949214967664896942952449185256063096611786810018311002293339800477234169168581134474107375453625205573091066535726240115780237028713923082617029641435344759682521817441075588005596622122150069773008158814784733034233303425250632190557487812257967314023937708833575951908653125856089431352486548588954374439105448143018533555819344978102009971974850393632995251716320814591455467981983991322276184180737606685619643431546888660110980764579747049546616630208817638947571476872933689544174646509465674400999740621592276066347783422391413946883285074636265972840418494666260265005030036570979990529367451712739098989564081413514760019221996147015376230938114247219406620783105354941865843182435791605106711524929932865151848765564088353739306697319269987829972522279695817133949078531839862534322681403551942801675593514242787256554071252784542229408190113072644409062005374036152888924962121537689720983990270334530321798454358526118501273441679153746106634166614665154090310438365407785037405670328250770933229008045250912133106162204056477125241915979957629147416876372396301694646953363780512528857109076146774409731041062273613396763419696819294372146989429450722974270278541856699288984298676117886097883823625982337931205028542699983991783572298407218223119701788251316476054560558437254583931908885561593895740261043412134272459232283003058721464723754452776171093159000537645642706997139613621969087866746227783562203794827714489149355828316323284861025773920365520750312214047317065394665214126170193318589173301043190407751000172273549144239198975832132519750774796567611035359177064958662936842987228509705197695757360706975702471334916935070510598196443952891379452478066818825238626700122002778548914434877685293655430835969403359049401269614117590362056164683680705896146349602491314418785924633238229468662169343150826871983619675948874868528885976279573241234818541013586203721751959026605771865511091168889928792958965634679240064771356894403412789597821669662053703974893302727757831965293932895531359972261820765706394458037604322330395339474121409865135903065812152545878173851605575768834254310577915581550189247547902378690709351423213401235061922161170996853499363980334594749831318760170083949302391992978663822523647468823463462048195633401833946461972778702031579145110177554821588481434689631785360967714548386535791417004204574241456728602763938020672455785773107944215916444959754092647590936488007664298187904840062899832511698052373563212059207306260707098941678037196747826481825763196143595206768880472767088045818770560218518689884030580498737150647608615273502047659871584262839006905215219556581894705091545972386434105549970703277424149930201410320519864199575377011975041402146249269516029465567798364768604983378001244877162572588685701423764804477128960507386495610564729217876480805199221274247698519862393148766338121307991381213647977311383419157494118539306299139003441827277017477594312499864905629264084247086561869795787326244314362160508026419352379100411209851318480481315311111077704582454290043760856786784228141349635812592745443310973440592227914052805857003991123906815789322103605856360711467417809976600202942192450926194840681706418598735580947222977485295659651393057317703349572192083973158121715673546791072732119847975500765860754572522214824389750698101118217110473866940748956397918210104709906314885328891262919731709983330381032695975031313479335842963650980242641219742839823954938223366674243983045359216255396251829965330314204054774241398975605862830663370466101733764042946485151112499756185698029705346556270643461636806210120964393960039347159947796336784661508636866948789401267392772160154933812498210143049672410070344245488200905442706408138027019968715278396713557540749753339119672818295078491052743146470842775395573178863639744564948042864091832847011459189174312192904476564497019657956649158348815441130069272429465522918977165561303571657431403076575556942575939877477574184929774181643399435599647007980902474634202760122730641977112830528711779937074510075659535920892498040097587939270272761728161723541462451338485395227069307929041179082859477958203084280909009852295386463702493262157506898063921274144127780963265489413960466507774420482071846203884768666400704590136833310018399461004647020899766640186364304403849720698805935105746403564232560242478575252572978011253727885940906334391328097068177263883411141070077209248224151798419954972983575265874008804329281282712896349397237433216261898343614009983060882029549251304311904896310044917907727909109505464711352129375250277159162317327373187643573029034860746923315065796268195208103349485868673831586070628927784890419975699527521152593637960957582920913616793761052193252958524480369885062661903173210622729045389837859418460190692083252930396824175564623024300201583618628284590515504849979315319580198944134506940827234519495292427997417773582115969708471455322646763752658732805490583359269301341783224678587705019559040424635030547626322397341436831746387550453903759933135123850413910884188616800949684327651886345687044342550560302108456088859218712853403218254739566227454234173647249185514888935807870840923142645017692864862771008434955668843396087017164591854872991847498901084069134133855157861849576035013978054673297911228196579808099803784662264065158893433287747463749548224446803657858715454463296437091793446250792267146382323502222363992195166774791876020849490056125804740844100957039438166262637751983604863359434643271364853184997465142218465755889890499310520810582146377153472804623312671086594118842443830268851581152493775226948094890981758316695073142095862387427455190795011580187050897729740193247223861056083758540749419249158569772442096175874840021062897035795397748521705415467749523176249530478816233046775061740161226562768067120268611883051095810600993648208405416657719140190015050539248624430832772276887076669263572005180201907124436355746513550078917177482534997940611580449222719459627520510935755279947391772546921465857749850723556905275063328491016890915969115943865230081256589900139199790049770762061393886572673894243952181496823371014063481493638426243026265574981111522423638519247440066731625008698862463956592772895089291161119922723975880317954779250120198773843164858365524168544427435440733485911138941038327684063404542915032486826537746739959266881394414986602598384592175823705159539312933507052236660282984831600646926418392649654128417394423761176328109017497000923160582098240246593615075123489884860351455208049845779254851674877567030117853027243561536377148009763500567201740139698223653714911464191529201352292837821004744897914242729810319250374074983411242539329510234834706794175762131614557681756673337349900276499159739198658616206530452825757627412047806502803962491361801370902470054842042134004116086184093890224830029664438276324588993236151941482563307641843567417838822795513922205718715102607855277990857513122198525841147586735276482507506685207885274923198032072276288766695589818440396866040522341002024877477400237093975781671566056179590077448167764972834631807250565217660270820209654351868876955740728321643973398418565858209570012122116274294318846174640174197538260293216814540214582441037204048415051087434294979467805506840635269704685132709424998456111462421840347560018491024727829807290268243888703896957528997005786078338071459736424411930411384230277590594075088694083840199858605562085656145647449557085780384122147879392313518610145299006302983595461068531639554213589991131607906122305230715827897051875231871001197536802557067318953173516757064095948293452408248636295199306725302392794521370092056553743989266936422375321962430475888711074397379409025781464037038767385217475416116984629288742986309598112189994222813477100819946165649553280589762371656270794480982585544266906431185053013613788450992957645214669333243460060772948374042346663211682095825092537860230748425403150049485818391192627763391591796700351782263227060143608836118325409683278273425012319441196839766214917099012634441641767220261294057276609175636381365607791575176238971503311276477758256702422035942642674671175483757892479944336293724260169898713706639455790039575837908554827361314027100864242161494938662944651824079659332676090727422930804093283090514304912663684739592231941892645469497486254411506610973032902520045797797751281059449400539587925502950605887262593920946535590505658606219773875231195518425288803479774797511242545865510770390157145834706713904918231315377807507521924790055012219453851019629651293296931450823800239705535132291523665737856416191114952974040993595811982235009874633988627572730872163609162307398232145129156682315638286495124424490885465205608921416403524559010427895316393146544991818863361685940005254897799794038958370049915606514507811993926625888090755621970863944423275718527198907880897748136281918508479884851409668751866385465811901936997322984143099690945575327699336995047940596646807"); invSqrtX = new Apfloat("0.56418958354775628694807945156077258584405062932899885684408572171064246844149341448674366020210736344302834790636170735168993149482616286636548952001776899329283763705959843976035246435021797257121158024577282022055450852717321662220846330811139951276345448602306823769091874515874661585130106639835777199937733416035779887616674407623303938021635060164362169623505045831253194687945665628832581552162443454886570318987743088177818294838947510850091845853422163178258933525183301202462256222372494727003389743126429965942635042830449036331580393769598560815933782922055738292378823157923310576196477746825309017156180805952222961763246535904008534429486250289473921641811927430977422556987879577904987481913693723969207286063342476796994860958876304363372645587875154308093441973848328849137917536189566350924134892530883039496540584105725414827482347517474200939698834167771488558916783373949859158165013768598868620439641290728692896380737732673111842867880211552486621897190889680753149512014745527175912981527212206323434675741526025618498227789498695253016694969685663862309220442486143313106110173970431655443536461630026681088930477205413027483214336586471029185494908383876924769637405875410315847331707621695314489049731739811213852526289496658188107247230501730560007305550738026907023920932512936518565440802730304560855889331865258630525883472098109161522555134016344809607734062906765209247774445791565993628691381065069739922116063501838120163482794525558804589719527990309229885611554562819744432231840948954822569892318934682036700320622921003243956292571852541904557883683133559630572888014867327142640415611826594705292148828210962155611587788457586937076931656897573303633060580804267765542888724683958653812819175444600411692598232070101487977598739665524120123102085597258077416323243651968705793718699568664131637070746016467456232664785276329361255603673045814750967583692588177510251617179158854351131944977951130206446574423546416984789804083750107470135275188047822622928469596822727604371352963566243917919851346226220302225583139481689744215628304289589197458305603292803761633107007468446807754335238804309325018209344327697175660458535814618929348300084752188356315613485030052563131751150240281525357348028103775587309687205804983911678544836782163830873961661473233861336858064369130362327022920120958420518454001622129760222492050209138562077926845204513809206519104822871344651158875977646633495516427975277152900630459262666213210247412162619267265257583174894539164002150602758312143432376221368865926588667722327005130728367784026758852702612626204623304827833773093459725104897520711061902252643126658529065705282455896450805541303573152502245105699347424513194027198482005017901051218365393350015086788334128533820394325989186458860182128103237819376135272641860975261957333921775530690182470880743194704770603952658525202275727673224405352835567656782748666180528568184389534014481806430664693634465400747291871772392106949945262293257821840527730356884864031512332566992523470311027574933252903059744296764363162772990464358844708667222896394685960201086760903071360480516376504524067957805736895016949964236950047089706313626078166185619663218284700774739942287908873053227130811032498300708800237075842354520605900314384741253294008552812549695965181921615707903796758028301539201532048375107908291922688326216758396417167461672753995583775081502517299603949425222840205899473612215419053715828613438487398090522305169387544617795294705631402716509359410261616481055491159842227135691346046233610415171336576112981414233406803319679212957118651203363736195534725979410919473813218791473267598462718552551887579755934932345210480461207507601887038050614639074252484284638619434643195046376565402559660603942734216659798731847716849162696760061385456542842668296423244647412313445991707051854082795130309956986576268273713346144038281470730274602574072210808368599748628671260265492020706920851787934904475915119844073759810215367044415466899659889272993409562370756870869893890621612882247232460148836787805411328346190808716586922092480838698726338506580003055790165732524446934710088181103809873111778766773278115075262361972407994788907458748710947494173554596600935718451739462183954924577707449183853086537527561392821260619897373724956375315765474397665361414676939685574844311545379091806015409735383982631685150412224687474671032170649428537066027921001175799220944018003376216676337577031769948843876962683788692992242719239154432214615739553487871275598873589396924354559840837624070484088807241062153876063344730857065896876916585669281509326281416842018881377099616128788119056941410266822150121199132709060730452207326511286976324647213722199843633641893155401207696743515391579486258659755045027734963665557776920242282226296664209761438270452632519817671957350102784482375908272297508510350647276203060623166558525608966580786840710316141399464391830066379930928702784472551007654723726806244302893128132180457443551641501321801547887667029097728511081095549334578653493623889661317856388711379758241048704133136039581329284885697528781569100784745220935753700794899256814191993816099536329043935814009657977297776647888080611452783168101341613935036512859286861680551295885587664116213501206060215913393041424193581433120163847397278261400943217309678227731657372659580538769950456194846016356587217452912510997741871165922842956461745260227733048992174609822499941336455055700400091079139094026619822123924323424723922428816383588858192984517844322657435952794136251683862184300384584714186309603848620313884223599144544790690239680790322856835049907159632422296292072556747456395004396306275410564563213492694072240005675845072296889636611092647085466761119828383002170505052961600922439930591366771883798456302407679951433863541650905825984501011010415586978798012490727195857669714028612616168309509346497428020399568547006756578680481857811049427709468077266460548959234783947674284597729947283724066842704096514497651208435546344586199241560190818160196901488584783200289028251761707365505269338610774112846690609234968183839179097327524324038431555384028723430635476619583023307727725427579741121155397140475122779065600658606347957997361668469650035281403385522084645026356575719131899873578716912512315486999597089433813921910212313899342074502805830929449871406692805292351731421992395545477344609761584906031639614048942972666301071328474048606817649872421181709716131240864262953287620272909860845406952454795283488518090436012445194196983881664892002107549708243826682648926296774119323280341328917027476296264117572639839456951947272977348793950106760922643774907118752078897549561400641000759898506470614273580237479767044447054471927497150909129511858371599719765968104244868344376282448128597664215097026213842802467700289360451691873431840519407443676963504016351717108772840719615761870302651891909033045578918380921822890511139111583863791934383436519314201168717314955454902257282053032985559851193595577154796380631798561406946303956263451132003060823529879699361648933264550451032214731154092208702505292267199740819150784721171925635477999964074784639855761962725580342635207932783171952495635799486707200343303157624935118217506754237437914812136080460611355415434656674931375476901144056955207809833467603903667011515719710830751834573112864828378201647492746338704304511161152004594782198832498817584966808755129613399252637064415108473363874672382723788891628471922444458232732427141042428583844509121453036018577066317263450710491170511967994260525806591645178275297657373106318072207940287682611533025171585623297772427241171219907894494265102830347867759540929734258948935688591148245660056279565684973679487620178198067092822374125164044546658422771090338989251192383919047911397751108629317181946147533284126721958545813500358355215286650621626130581019555017507732202038319117838330072924168815088585215881340380753988842024903102020848280555739997781673701451416182819651587634174209657682489608499576221032916793206764245211444429628179035688719130399272377682786098770108354856605057984957821407380783030713352876450241251052784051093673990966871281774215199117706363912149542121376398460995051909804994591654614963066777817770243521595140619307007899960358235490551929110041523071463730013448020763355664560328256117464395210748442548856278416153297890806102766040904743809965266423673534789599081948006610961800601632417298086692226979086904646734764226386570194265245360198206740364521330422644369039915643166603668270735411348526634638673965388476273159285507021432124419970148735056297184109713344535168116039850386577221262777258840267116599834084532857852784270894683958342422562254146067483616849288308024521564961703047678147893490899562763535675106967594266290035099060992625882196592453308411485613143891835429474753071213431922507493266488639823235551469584404098425929283762672361692485916515890464761931881378780249497682692410893269086230317484028762713487845488555083728422686493709605742856747355328821157580551559427894474536698984131636987495359677596118905155146659311839581585060618685667804675805538141233717003287568425461861343147202485100888443557069074093880630420745513950380294309663415827363183806062191374664329701042625983659711922253593103439571636159823786014038534161070663673931749878096349722760636886649120440890423589324937767423207434372192810169194197554227998757251546063095329588910012120996656426631237286583023288290921682002981970941837509195324919622931637593287161764533163958803732389823047734690441058247778739521371717374609775245714449555490149260025099685498803310968920655683666035871747040117499074747660397877557734996684229941633736797764185843325690787007798015633190952863350605471113019923352504652706697709888058858120872950766825543166125617763407792271374983894873709276480711674840537298502648022979016117433124471050702942068467773027534941037534231738164795692164197614856666316219792467656522201380743571758834455207793464593379420281774367250844069957532118611304295713123301776002317369219717324638898061914447646983454958982087564973979885533423036797189000448063041532743994679650060058360314537808419521394105004894071240811520325105795866412887873356195607385152055908213789074362804514146976082865241775290189873794807968987979373588825020615297497615878368171807934314104482657007812162906405417523594503538333251064848840092605094720755303138100964844409242356777638786792082952852903742207317667071493369604929047782333174264773751716413823536407670941523624861860035862948836123642849569247954484080790466836274995321737872968920425849576493619401731476056314342134128772629514188849954377616074076693448527304811195312666152190150679769478492171110802496477211681693033197420180499170627862122965321945563060290182212698319146513668824097101792025538350446204857481502513979093672932091328745137030764338029554104711609849553385682729392165812882652605117732287341111444209728648982149993974452775420452465587508308613362219649748260125191273639813605255744853952948461911731008093596738005974083489816770651222363514495952535312806725639674756955564241230715587856167414841295068560759643609723228843200387064519983259830016337432276626690230660069118991810575487237351869365729194168949741851077880514610813878701865837498986898602070328686821824369826731674516737658682423615648432731828242178668565426325614668227153283108869749496812258749518911306477301618810275610685578174035354040944236016043900298393454392244212043921676043370728826281786912809430354579552272975898544635883991638754284444621374362600265233439807556649186080927036987120303468311974951650757725815955409798807178246993021519805393830380525847960327266575099161403433799942014630649126505903999464185096193792892664390710874378682259188481710386626966948083034752291854717648753938558442348002899872242984767394792422156128974757501626566915174532623869751187418085507433380375363361292573780201691087729554271989396850241038389631320836754523983174671233498748124462815905862014322180217833935555264252786617321986382251704094837371407115697204044747931033060401767969603443126968144563972837638803892436087636692246313696584802936986998696361484086577887836604543627350717511789649939260036142903439729652964222595310903879081464560680365547502947208787024328379522049677185386434267445839671903517063438639476077545301326203322943744870207068967657671535129763287321430223871292467662716440261457967115089058993565384142608932125089536680325687922620580983380160057740171470664416150569856076837461854591493126597961785777431991966054145137117647621837463767319313956436276701134141893367220340254291589008957950026920146279537306911964325047278984266716200089602387627569229444077828040255487684753698226023508991825667664583680699741169752447423982061190381433152475494706602461670259118067212821341395578400486328521183527038443964541526369395695659064642412601556400375630215068802787793507503188268608174483048333008516072573440670139179836842348936400064331702420923429341560496926331278184396850093389779302445050710591790878670419538028616560517453082417587263252138573854878957645108906511711491196708530742990751175890078958279972753355606693215423682107002101495960404243275899158183827369585152580455995100737429426810781171027219708293234192616021628481539123093280495725903059882004175857489590266545831212063797270458365851331671607430403156316802305524428220674833586440481168288260999708136357660669176779393784377081337231785546526404303268433899539624989311632133188393754096133256249250361183234705268975824034041934772204256822657510107240068239403505522467048615570938324602114698715682028850876549009635440721319742489934130094302291525213680332010704718020079487010339566446289011048935796847993605916147837600664871575134195152199300786746877250762877137387576433007029374383529129726296212038326033039051643190889093934720271631076871240568387380118186767946685249008070005357025897507678834094395658461786251659180843838908128897190275116645566752868413180738822032340570642138104725685320501743217472547700289730083078618162168537205558198425919964495819276677450448023972633392192615984360944964131141454451121673195810542185058616527373615108805784066704092099130406678819123147531922858489626906993705606837993858621140633275171253969270124185791833372740881887678470543445639093119237369966766103720372935748348515501071359977132500810604360151519619045327774794484531140989795014963704293399917724245215858814413997579100261598683885190844221783028801746272388469054528748560228599822116670883270064317053149110055417365072997219489471394555839949355495721353019177721883556052081052663016871606006097529022687887650051378639043620337613518534696849789091676633160509029855981062336019250153839756684014378004043963025627547704340531854483668585853663573963884128995024476747833434544681295569906888105050635980140934679613427184633963364257821144090300975620979774939943565600913148232988493967596431551285246333883037925290546835948042946889566343576455727621844310228658339695273231439322173441706406027893784823054299173669618680064567912657880851687992857641913018762103083155310497668456724783602305544020201745341517851141812425501346879333953130941657534876571977101231668217209789495682749471507383760150982394307681007977167742344805070924963491141368341421059751843075275630555355973905658121413656252791394474746373886494032750401857481938376498671157664695343548669478278944223516567100332335718810268943218580234725547475460337109433909851542404514281976583871553526712083552133817324471065153668702058315349296827243179616072798564094729501476756758774694773946474773163729946110397646304415465288955699460409686815385039332149058548548533946589230193164537785843719667207220715799024089188790498951228526612678321792971146648955529360353075992896743183900464168025007307255525513334885759433456866942390941912984086508789075447890577149906689032831759822619963465575731337545762535798966416494022060810473614372537955827669230144962093483454316335451733074498509868630488787484865283874291914972130359201865590655000934083470353173766871685936431318728381996764888097708246030375619387241546365114179266082058593433531781815554697258454884210079218456167518591734209322097918415297015184123495780621056975931257663985605996992211602687344005196616783519016617564714084215178858611206652384090381645212315533415156210652763022487220268608150842562028980687055338239823518490161300633713777207277569639104230537845851419310867923123053682709373081356906591074047135430010853003440046606841906377406541903783177695131196794169753941492690897071593152474884615211358649705445910231625736423389999691173983000215621159878966095864842786974113389649867557903712028359236014304664587111233568332162153391596936724231482963812914058093742899912499751117119583395660793897107411834769799400489795923333513429198809889704910715424032899481801045978504546310563546858658788737311497729591022199583534762687520319143912514750446605827442021440806634293972826504461895478582430532863694151757279340558268489692568651820266099783573866995036060022647115502591545627141591773345948843127198110692967701909947201780927655115278079777845489761962555497989413403785235558131808751703391877864852538132481530419381237349192443588113118055720295823517916544504160744442254260585626111486242497236480524121126826801927659218641944773316160259890348092290459929256137071417944992513375451387278537657554529939217005598860089951757037912979960256501787029388712333369782396124355995651686368552792319309529384531004533759956488227454742612834748358560504949068977163454178181680237850208855568885078211178976568703721270885402965723481209879468538307007194285567666322940473227549795387459718352155346329930922781877406458718723512720783422577255690995216924971800695393568600497575581020740036008255157285709410654031527729306574350209495683762079509554575640414846822714053031575490745232886806180795802406265018967031866713865061463213414388662642854490092266679046238487257856800398820307239118469100135405146750825910759924344207147136964725042069590715109055775419542015459828625052625925106327684682287368362689577485611964457102117294970541980205367373760624130585186818123542107276433159268321437252310594519065030330277861943404583047658399731258240494161136315773859225598362056152280846430308277895525060137610331500768314060912636549086956626048727578439242616081621743301817316873004784407547620267652272235469814979008299677598257270261380642113256265809701523033979527486123230157851959075520482079187731679706021813899644608564202186500347804127108825845433999850607688488515680858473500375769612444211429650643716997619295529654966379416847591629504055169301647752706504672461836310059406961587540446499020937289377385335827720561840789413813531175545568519226050778045428932542058110909766202670907782405907689333625245121559149225027284627100803901302821670743586521988639632721895877119099794615730193532478094414640648946093154583483050973995291381089804133598999053401651324228186129999980665419025080235730995667967087425700625902055690593983268729213051075865997852518161113035191421704544774501622736901966674978305250175253719735947958514160296892633552886769863003371876663171326384379121920596720872792055031044673077906141463322557446270358409248727078342584489209988362673452399022501428572587016389349881612681878736610180141825279998284369305923218071148672446451461392048452952497907250327570721212098780448983545222512265972130313909180982987583256572096385838466364938394399136492065975602452446905990785604672532160335009060248829378928073103537410037940716915371372284799167144437570576864922988994498195526548134362473353142919941929902510707416998176980628481100871834249328381290757706383186306294353243879880271793853976240173240626266871122832749561177774679072636737877553146578089168244042814314903254275744032135024536230603243238622728530240965153874221687432187090472010599892635878029166214586357163028713200975362098924415828067255248973222565259747869964457126545033045062478306226071041992295571072201465413241752357796786796545046390154853122226506503213591548224729444303527048949121640051584801619979249550785493377923491911687014328396089014049020238803523411525711242330670213670710788069043953294512006902219248987245668155252471207225304879419117646136382265883918093243232715241022669795311391555173266264472813079522067825078432093897966786158897461720574776149194596986412047612931817397241039096151551580771707122829855714363107263263769207567656177427085211727391839965994695753975704893459684503568905189372386759093260248683088813952815638480889165381606844959179569760918419373780739642468615773153214566311625805576003529472378616258579510318340299247011724241070260173699716685481217990703423940432516548300602084634292033235730178599658447715117961918128755468455366028432826387159156202364015327436828964586721206255546954444889857213547463026892788555286688826247059820801626263307852434965408318060867525541429697467555598765686713383837245917097163413291202647218128121717906428623969522638790995176958706759844947346118114974685585042045475592032104896322633097939651776315866617643387882385869205486987222160165997009337492747922118643670059158984423539328793808276446970533226041739011403759720564096962437264233110695787355661479022682413710975468309723645790608219273437284680926599975143930764819663715615692560218307438471680345469933254076213729139488783857297633247637341237762984105503534049614682481564402163496422093603258110191110250674990967331594285501898991113222666865928364052768417211499114367581350769026784606942325440922487327659961082101721739778536447039295674609139260343144403301625490841567132733084888118046132130533471620063061924733983468760625230705263823701863436345006363419652218686481100456134661207470179606522358562730161734669663969799026572465838829741169910068813205049309819594139732418597922716355248819728328201989371082019372817660140758706049864824452112070702537874934134791449754025492740917573593471060392201353226961021567889249516894328587987644010418031046197996158979818962567968127218865462171663429024883296501500787051080330380927705746709258809151416449303408654568706713047633088300423630056642432964040375733170426341186574625023086538414236894534076412875694924729257452018578737237130283424485124923589249975967185949759455621348041364752798452194528803625858136368543546123360725878558579061099423435552095064006588196709240600849425038888121485985714251878960070326454427805433847642409050865464228648725070249705095872037043571719116100061877339269887135933673667859082287082442430954197699113096553135414003096449179113497399796850237666349826852015587803910207973507367369020353642578279876846626239251249993719267564412123666697141217968795560104143588048089081763990194998422785119971962923744252241099984929207692226790962915043918461001195434448045959023373551761152274959465869566114711721517139078245005951876971841756387730786218576851887255287387917099483191281300918624948118826306978851934638151644342687862802004288181801537557079329196656786486441748160862616034218688058713588471951913343894875926031672928848472543240150468672372117779614553121490048147219639094177073842457794189854061010200557476293488154978227856047675455628330948797216848484436670145639895737986566351543388644533833751647071563116225966020606631816742978849543067059869033967044941285519607546475414818941810334715274155964597831988906818340531287181211494057010015718416112249849724823531501076728369551688005636324195725032282819248690440508095436449288930523733708206388993132065454248190524213692229430860168805694937287323879464690305303711764561214360521165977010252146185279489206132965253386546945277891056285465401863556053060205014851139636984355648458653189318591013491891658950640205512644425899711169929301216722345334723011813834514206356350878279630088233076726062564619827826417590940099062045382002122389718900596796226238129814576671556495940814012804805548084773524480201407021459104801215699649229020306738643738332171936059379105328436864118816707750618717219945200192118844832934569273654091256566205574709842879173294284843601509334585582454531138858890223907013388617916184607613797535609828543846592357106188899734533395052765438452939195205298899268007875228989968070118707812626445771883569052226731992163164564544758381995163843389042232643568348822164918614379276586450183512210194370356157070713912837909724552115228106276742172217339796757381575830324675574147146167538280406991108758071229776539748274935582115563740211943742851360679246975027441095991239177230686649746883833355869919662091814123375578077046277935881816131505053913915261659068437286938804755406865617931677353693932004600822036676128722375097772101721660753560001861738121701024981991015815375546966794123296382119959959498650757275270952378914609833197712576803454868404649215447993306636011806302633185983908073777127065360684565178813461701916835105020570254470862219410242390356857120987465344209833272265511162826120243237180045500064657024489830288838424967628094970277048524696937777091866834978933904784157584118910481511377924727512134361917046371633138723656965467157301668771496685112793759023736116313650167181730218905192670216203407067492812489589294773375730604412221566363676297959168433396586933439676155008698957263457863870764337837814160931632327785139804064028252251194968347212639663310793352381503142154998878844015545951278942521763477136471352135756338176927124903500279523274738563889096115182110529072283343061034931876354944031786302381387781503102509068071554408077846800762798136663741600593007861610196710731949315813711250584864325032147355652348572550647280687600578696840101162428253742705304948378075475939789202880784076546884260096696780110346189758151969909735102521050451354995439636539955757066720816744534564945255937551653408852041743076230975991118003033405193316677893289425577144943228501930231649701860364950937399096381401905832934220881501578866870862104272384147204612801069223565729437398050833346636015232203702820767076329854890536765857882557113324453223906451079347934323227248010741617006052446486707613922170456232822423799348039716991911262749688740757188466944167802002970003291615850941585652168446400092051089110305171191331229081479969188237529808578243590929605050091148141164057703520348498526780227966041996838883144307526222307641364893767796485828212956949401737577223753076592091120194826525464498392064242535715873823006643626455079882413405336751630065487847944863766481902388865962024611571009959555677966390245823223367065440145922830291340375422506387339663464736659130343294464324482695854365860004867427047116620709352120780676509175430295805788421857322839708030045402042818904949374180784459729369832436304231492340134070165795410466801417395677736384366744492196620004143263030545361364953313318736302953875283376285497145380934283510605065403710362143612033170643448152127584386093394064273116557499244991868191843603859848086141174917761773467642614964713805438306644926551453847698465411559675433153543598308488251494647190040643318419763945530433136969744856330388497980065029662109147556968914026504272506299615042262185647037366442157098193196371675655169206529567978360854804610716919982566625767200363908558581103517769873851417867464282886954359485879013889544848631312924097024402160255155878121690390854243086100939673659308822252321367044940347087443305601751479177833134040125964006266287601044190078000958479663405032769159350019266290816735002443722477915494964468862740420286579584750506763938749694314789212345135729166854284450199227575007536060900420533072031274023309801518122302075336241186633754181608043706206836300030304353835473298873506616469554752703566476608268815275201711406565275877192488811829402653141223299025971245057070033866697190781791452487268475672323989924823897589138411165302055457519285324494552324215126116989555773252521272559957334304041259705596737204179342983503046654148990514430754204198053248680656394121888953544250158445606585360364862462814538281433200811443175819943535970093089742660860349361248456619270610612509233427406064737218459412761353215340931659772044081843401973837778406472401160553880643499729960692644287881209134299576418958454077245720430776492830389067981668904325958912838848283324755755093782122014435179519300781761159331065950981022275013416952005410462557894479522526889213879954950238447021357136627494438210386319653399932538792787623154016983634036020869802225862941655111958490769696820751189202210834250486921449395477127413279324455256313537452604540557959008456718999590443681558665049097728698922586805543821142284655648889958921848884091637154000752636806484347016173152136633972981973165504421768338727937988573352426468796880902084721016365461039241542116423898293553541492599545972399945668300130334209472440281416680018973351557520350730518245777176390197528307676061749336296430557634026579982251544769064862841861573407094719672153146456333343186691338195203484507835632564030510700999726345514480736823480698522279158580821217816671963689736331562189200618227404620929638299878546194845037130672879377659224991547350982501462640949473672497141913074747543519960144987857672307823791305279342623677722445067994162002585024283622548956809516797993695704610870620278407765055264490665443414245193944208228431460132605681057600342783644227269588741507965559132996467183143983286109974545255583548936245657444081454475810341724072157334915289158801864865232437234971310559679230769459240535594066868037534147397799978094935867816576314249141567570111266177941865607347594157096733173888821775829191609501837566301155402348489348586535117513470050574365177243885410387998425291899042838056077399362190375041890152117166707261222297125687723003282882409866758916377167064877898127548532828929449232801289129243042812045786249377383456876467690920805515789619915358826590621391030363769336915168973714928622568669081378390409990318211364608821942615261635542940836610167454888432111357590820833184944695774879557717285049231493286657924636909512037412238175083367879830724151600517843878700806808955881285792501851406614041792421636656804898827999291447513489623865532873078202491952235835407228719768512421934539781991336000458237326909455509057916657307558718961453717203571801033117689181066676042439900992422882190039700411853202791441464924562449567008287569659268844591289155753455180207513877986289776470994409934417784884010506977881148202460466702157057602867874589112325876988604761594962559775438048493130308029865952198079005876788540240077877103258070345233352943632634803380421525473739767142817901351285193180042797067389931666342135125523710581488293273345197531199043120406763931575313873624196110212044896645275100932050966928981592531149568457448565371803578485163917663482922279850550860690635355071885509495215371945507710410126931087569045411545451766132590325058839512304916137519097876065051894000382265571067628819898182254161799148586525297905635081339544041770897814755960402003890631647862429475570942575002021635407819684347687281772414813443359297644741230321895690234461596107170831526861263966666484836032779379224118913914122337571766765857524477968290341943875446104682371173874405645598643698138444482351732808832361741792206343111729080024085646360438014558636788095561876833879479541197057163517798024173352521141339098955635323390783508801823395369999451161031400442708953398431408938416860330544282939096576335931494237928560222492643287923183427062910310739531894007981749150363850607414275763764770976085965917501522817651994862717435111426895263197827991057818849478726836589199005115961181195993755121756911343039807346418142613184422739224859183876469700064714199087087135997879413172449220883565546233940421330506885631031055724922534429852856642208367820914000099264280494375723015117803496267107569253696418287757425194411247036736181075897352292112928316290543827438282791343625832020864921357428060965390399267010952331828355790661228793821536655147952135135554259838382541166467166120391514469371480913648643885605974022742568988237661718665990894676010257119500219839480524039094684178872646700931265352675991331754916754186016538675040431712026013004699878512006856916493041500562476179171753161324580190459161855963430941942854859412998565334299660959467956727977158854838716624177508590600666246210525203834239226568418579577423182050809706889609286013581032181800368200991375448713255161831163730561976193824297317312450354660186339843563866457309549721406045816419779333459374467081225774646262881685105916713563080462183970974314136264597143577855898367992789366715915095405824377728156136841728201202310517927312848694594460693278060508724662347333146500289729025473315314838787536423928512689975588166515992183736786829630889803656361009833164442902391281516602621581050707961177239097610790220406496090488875763270854745412544893325791165325448753930414604760971292922066668599764981726653664893563964505984262667229509152426024151071957183117632214134028028005214063746691752941540449052794286772751757383426500866527912616412349006847436212611835502711409169616793604374202293940270813048383629371718599030185529584917228778479550646778172300258013724498923508504116852166885218766709681422404864053316752139104335264594359987849581690097204549675629667753530709748294088541409101191564929941531822699737845598596791205139742871551421839343333451039015497895793642892726564140597350888148985270345031157238060035071163409808929095801945837024617191991916362600659412611218361301167316409612479824316935407256705750127782439797383539988375258102175306565714586927104906232268336277345221050136288791807017690450485590868657504119639099103122538089576305428421338847267161579377087185802268279839377048786256525759012396414616670897035498921253119385887729610585541065185884972490579775069450417370721505917845044297396610824993113405630726773093137861490740631007390280642646491734361115473167795838597679113726203270398258537656196891096956763138813494729269481972500207532852226162211794002037062775732585322821313236981056518929909641359707336186588155467733773192639157091144154125152275549819953232402428111413060062890082113943831901948377192018065274324068759101537593098906531180742229164003932589251149325392926026798784804369859765629216036874850509599643571759554929900123434861769053685716466939954687367821943481316199440136616601312916534361075793310940577967977611647831657577848350427377304628809301634398451780763075770418267762295823150309961401428734422152022504890759010378570440015855867749071557128246329182365211753708288466926215990360395139784847156787816020104974985752915248436429501295255625842955476903722249516714603343907402960195865664535908209552903460218951301749991444348841461283164695303624533733891661098139937784513263640741715661857209261220807360444784191058290587800666530799586869332094136148593831573040696364165675463748458159189966101775833012040868280679889763435694651529022035980500528306606396975109576885950832277740871164026444023683781744254107155861468098151299058055316859504364576721273439517750004641036764490363431652139504528575512285790679814483105718548921711021124476707367125158802692884394791260487921011196804575374216464101323545355210766966077240554737375275331181352073503892742550311621683414175225021118131266351018516293492689303559949171794211795320793999333795112555749329892557817314398571101596423018835545533975141027591064264000731629506803891441493499436780972099489506428211838813331172807643842966540366214143309342227809321040498306909937135203286341137383868981850575178369523507113432977570916327865562301348128399954148753386666280679774243544027448345995920155330745004025108891030319790677896896803475550386329215937987583413765345818848789458683062578127615402072055138301398760798133167921766536248632887863334409472052492438681732640358984530978250250337904040938525179023804823373713713772438199184295305874001449927842994151984956081568712325510232395191424424022549987066576098452437764820208200339401938225133842002254516419082874741188978322238216768587307497991593090301378484950591910451159723784222792429068305017162468046983966659787875730198968051714375422404197570920507302728609212497355339425267539665939538974928788990103234713347058318963072234201747659584858386904387189362909349033034056716667354886129020706762894855370309020121465650810719599319306374434799183614982688936025032810662026801783371829619330589471574636772192885714786857368030315198935926201635681689965783795569936347862083213878115592357185049621680965479174893925005842066383558887609535094364444137527940355993959374640755406659481560578349740621508046618209882138858601035547064316663393608475152924451336999140594053464556850438446478205862404894012378553858327664927622003510286392084108445509689818333725077859456425378863838699794105272587090645456094593905442616178871280079909651300751681762060820373173715722035073050311027766814505402288422146244459735951178067165830246585532910283667764975453653118379859124514681750171866404862984802238436805990150002587900733449092338716814664461570693578701358045010275408479972280661764092810471657337951376502622510415185255948652534379309646341907424926058463197685023299070892390210469355832008474302007656343732079067097996324161829671005834849478401911612443089355492507168226863009486733636558850561242462253709551922639268784382933538811699008311220169651849753688429943702695290854722277444268549413063162728115133641573070911911782993397295332910475705512402110447323438417187197737136722756745852396564876739482160481394327152677816386227659438521962238027898025740778498786940929861472375857184599019639472477325389062637607547821083968838627596491663128890620487519342719408198705949842723372319833251206242933273209964960675997491591948555490067067348606925620418619910377419920186981515191887059615892203354008993072887145913354141938271480145005180879372417970315546321541483793041229464188052283478111188747252670334574291968229559159776620722159679835580365902318411295086621215249841248714929435099758157784912410615552742259061635727755249956991096223181379026247534051447135737024416386393101335410056963346429098806714567233308813090504497097523116831801108742297531646162912567185485572165103273920263321444253651204336413057149402074174856024702367887184750909483175977873345761016374300249413902698072789058385338275345341067979233196511962398558651647180272883332117218010768802021043715341695965989129416123646380530914592664896376303765275539759716792072312287934531018863301310849719525759367267292434533641233906679363871919137669789467575934113856375737743160283596212959333394866238444725207557386543776635699073170255744935961292318399236975960356636307647876874425244501464175115553674460289792531291514796043448186831454481615865151164852958996755136070832110517491976352717944841667882260702411089184709437670086185930401122725133456955442896821995662358875638010207157962784813292205759941759656222237744661138459979006589544461690097691728242179566774838447900182230036857823947969270136908858257319898881258308082446414440738076296281919588470217283309846329466269766642857080867811611134378112390120153286644233282386903904276339427228301883666242774277752585502599629246833432424085728697064674894075523471504525207065829728983495647320208053471237455398678481422194063153342300414020788633969896977764474053639308060285657592124613859582053688062329678616374997567526252105153246187519757227186596078619513381165358983401320685181522435018200350486585149888380517468801566788809668258674374896086841865036886053076504713178713122666271872254999945140985916108397803350282525896941471967809799744488484976894985858740768559053750535637806602672838986188239865088233489317783631407301317078435468375735790540120692655800759160654151191575767738444970164618400862272370868690980512248273853922209296119892431490866832486792064327788306199487130160425062334508621633124083052147570343719828018762312197036276394157702803172635369638567666643194377947523746545254397178413711108598766834846320442809183109846707669331120546190913631804199071013108833525777155821929592649168607980572401999447691656873018239865999555589222154246054145397555816510996619367050773567183390560430314974162064969903974941942020884015383463609055890678404835069939757620519379009321383347412151710957907180335502659722535790618753430334686648042297463699885695891220097658210153652387457928821750219041338625776680437574082651740432496117797099029909567384800599825286640015660497457346077546457631221870125396189693782762183790932889090948449725045110707446342336564813878467717394044579168176642460533897973647496171363272228303770853359009702646163704855449493040896205332826761927558244377578112013983844960882996129070225541635660117587525951422135219282546369139990908928998427110839673990996709475389376370696416615133638934370457999148637850365820795081180932895330085811229445655662047945642322739487297564101669704669374578951168400710798922557463626082805112351376493034943637805512535283356247962285738419207818337458738886185339004954952774221684110059245259957129861532481425057119704149226450811212617737396318270318035486629210282417909090797453114682964205716395326903434704394644024072895798842288814616310595490559654241608928726321397558815045978249539247710220064361951967172685783202489405334625160046303289095372516262008325569567636769198289275540483106456381544912544900297034790527893516823527714895360064341969938349556567282266612878865820067947907905016552257156259378562393585660312404292549705646450249108979391314423723069240981231802732986301980166925076627033905481314205273084372564458242450400365980895738512000562712191774656225746491884214195277780179391606282817704703971505199283871784598761660928913585995220728437725553749627778265420177911145761851276825349090572238304310755260001596501633998050348681626910407450940865914919009775113069181431620300851370899091050662688302974401732231303625624050998460996835282293542499353795944717484210973667293249154510688714625703837833251085327061010734690187412533256567505051088681631032940214025400220401929590177649674891364576239032980991045119387594268253910489625557596450642712125131132659773487224235125502434179768706921724439574217325015106243871419949970477943793818740965986671578313715576463722628417041801438008463881917132175737477326208269896854827986155604451390841993043419729738139893368108536099623927401121472512317603299417266402791763991806033114846760298240274072197195713968046379504845197155185810631460486069556463509978221365742467948442296240778745428999651223650860178705277342092174930956399352047297904347082874622565237641847850947747018973970457538976013107422531354691627859435376293671420904117466731177378090584665768829707835522820016128291853207976902191922957638821128624576171797016267082732188232941507631287476697279784397291466751803945493483242196432284836152842964875731807917757474836675603874715420942939414665423007241073074348446719392981330390572291265165148167845682963478577396009518141982137315661750937806657478345527876530326637333212429014094447245128994010185817834905236656474841899769555373920228584893148856253942949260168774147861847595804348967712581573368778264298084356634974228596217570771122603438463712648413841575142006448402650048151948245113271420708270456730523105470373022892620718808012779411498828049677847661225624810513198978787582585437092316571865295688393270480581833433809662318587898259937262025214006572671066732153913809037089528006363788069885644598114612220220803546295202649297095627578750368909400276419318110813141573139281863258930437868586445758566800131953618360662872608199890115599081688065345837828435904255876445673604373882498293017892981675255539120252488641300966948166368872654133777557792187918710661168553464562746001766516006936837270595091757260691898243643032683027235524131627285811431883610073897637453399095715152016961322950033387576967543483474106566686585566267727296770901583810254543395105906569155626980328087757646583808379337990825536781426453355491948168844011581557664646904374154294286125344207431948618117047194233108429752062227100609306476963230362268948834549289551406678925942973651707809976276504326005887444530598484120131598581284622127775485515313524520949475206312360502362909718243489764519618711815901203996781195792208576369339970117158510060757514689835975738313931333525482213232885800978724021630286009378059454896971853760874199278360117890787223268735539244333250276696519676211597404909568550826085820790100553886828398557177685630668749485938954364037199829198959696556529031582099253407789261311750002305161209983784683802954002978171976840224277456358368977325267418268576880318063977616674248005394203768966266872972034708325083957501041416711456461731623241601840202407894200891752598165690532924663771836721189605654677212819969601210412338178021457968717201795329361356305233462324671310786788568824508792924972205435157632633620355606985779061246962592099137147898056101377178865088729983494671908568325998572423847507503466152358836940039081187169730459771000462425185839335400390512328985909580928544568832935476899972567743763734744478399119380158686604593738502476402136285252411316102736825864762758036385234640338274330206016809946997693818362801382388686946326937882564171843388938441468404128912322218589100923475211453953442992112726049028637605561316141508181083869727995031111789636940167987222700509054326459636456675505524471146636555429305034294436089650152979963889854381474099240069584052288639630057210875028655975684791449996620095598221840186045076728959446763280273606564669130296075011213002123518450405976992852124748335821704962445792179374123195470436820452133215201048776157603793388034014662581116696159735977336175540742727569993765893393954575145261458408126074723808876511281819631865523960494950459737073227291091406224569716322417125935502086296729446859183287675716063986159859101828219922609374841899990769466870444497366975070651597344813193965232216286975541341643182071935542869939242907453799854464071726555123374927134301912514148451367396450327345126417544786214763188646845879494345357696921446035381891171866543070176578755787449936155559457815468459581378274320618824091168366042379443266819205441009671281815069540316572248737483443664003137821294360814586881941452340139066155048675308311572658324402187503127983720227379890612386283827977840292805497256753188033696806443748702109142030596800276389037113484381634045031667010303464845362163245624390394532523033618951628257634017661258998708804157107355006491175725363557862355573362567026154252137966674357366746622895290682112292813296372176755333174599781232457309995661489865827016611609454563211089613354737503751376107815996529518304062277964699785906005958153392636875844676839015217145843971286214423962402949822546957749201615908515877944653806889628787945155073028186718255355034897842586077713270449598540163082843037757237796809206807967191941422255652257118877223167582954689676970543239953396348842872751905967640585666458503990989703281894088215578947037393970419325062332911776585342080156011776656942318397630087586384889853963199560947407805151856059929225948653760776868699112393245819580966350481976954864950343035294539781499003571548821633934817311504976767017867603543729422321588717731180440615608030468278822427246974195752782987085286934728817838459342041002134096673097425883604325692166582243888009022729968246423088462144178637219521299793495721966202301108457153623432772235095734390926124170582461037790488748130546479613612363764001568569016797281694500341996127091512245928820442247465758549390669004955694160527232934553262659352239591224811679250179393965131762285788608917840412302352013795578968793189830812565071294343442681040414323018114614877539159720317309391222206880324169207614957600883792832788002290969454938895659675662082014367948886769498981163998497407729809536056204924844979205004726125769529862213382057292567730634293263638762367788508812912141430829730545275226352453993499469392234324095544754353435569505157625042532991398705204739017753567989044577913740084198725670169209992614526687777227645763441568442854496824852860074354143319241556995686406984325090673172447760168694945453744944016710495212240946431956501133258649241938325736439016929196750797666245393316248682509499691892813466839117780245224760511382709024460283858255121841450380619808471325771144673093258681874270812660569364045085303728684797952271943774194848842024127297476147100215788503493026696817404678873300858113781159351407449492400904409486930108489662991244454686547463067788100450840819487534074076791483766923275275067061199754365166961471463906135865208552604365987312265644867183948023024810814962900878173053788479206362481141595770069317744250682340782987311807574896630124838003309621111261630822781282153001630634216845321602857164338793646457957328126688357843272528011597204929990914356697955645726975294370202965112194215648119634505508737525417997657488374870088477076227111237826796274427808084811023606907309680380975420595867284306504284075624964292546152706939357078704581131578517493128065078116968654499759110081956264855472668153543035148129671780637227896828883674570146631828063729227565220680273886310420447806993094465120661723638298979276426691433045140017985773632549338390380340396692086076003078307209964551532743296155764470390648416875838344876991429878332212389335501256146672808645328493800240125334916044183275525225993477167464519040624798633909800878074028151672590056335993290686297728531922667548195715707495768601196044973818096086236559328398842971889596087524600836404390366444484615998547444678565837064271690996411173862332256"); for (int prec = 25000; prec <= 50000; prec += 1000) { Apfloat tmpX = x.precision(prec), expectedInvX = invX.precision(prec), expectedInvSqrtX = invSqrtX.precision(prec), actualInvX = ApfloatMath.inverseRoot(tmpX, 1), actualInvSqrtX = ApfloatMath.inverseRoot(tmpX, 2); assertEquals("inv prec " + prec + " precision", prec, actualInvX.precision()); assertEquals("inv prec " + prec + " value", expectedInvX, actualInvX, new Apfloat("5e-" + prec)); assertEquals("invsqrt prec " + prec + " precision", prec, actualInvSqrtX.precision()); assertEquals("invsqrt prec " + prec + " value", expectedInvSqrtX, actualInvSqrtX, new Apfloat("5e-" + prec)); } assertEquals("inverseRoot(9.78675172784960122038e10773, 7912)", Apfloat.ONE.divide(new Apfloat(23, 21)), ApfloatMath.inverseRoot(new Apfloat("9.78675172784960122038e10773"), 7912), new Apfloat(1e-20)); assertEquals("1", new Apfloat(1), ApfloatMath.inverseRoot(Apfloat.ONE, 5)); assertEquals("sqrt(2)", new Apfloat(1.4142135623730950488016887242097), ApfloatMath.inverseRoot(new Apfloat(2.0), -2), new Apfloat(1e-15)); //assertEquals("inv 0x7FFFFFFFFFFFFFFFth root of 2", new Apfloat("0.999999999999999999924848832098"), ApfloatMath.inverseRoot(new Apfloat(2, 30), 0x7FFFFFFFFFFFFFFFL), new Apfloat(2e-29)); //assertEquals("inv 0x8000000000000000th root of 2", new Apfloat("1.0000000000000000000751511679"), ApfloatMath.inverseRoot(new Apfloat(2, 30), 0x8000000000000000L), new Apfloat(2e-29)); try { ApfloatMath.inverseRoot(x, 0); fail("inverse zeroth root accepted"); } catch (ArithmeticException ae) { // OK: inverse zeroth root } try { ApfloatMath.inverseRoot(new Apfloat(-2), 2); fail("inverse sqrt of -2 accepted"); } catch (ArithmeticException ae) { // OK: result would be imaginary } try { ApfloatMath.inverseRoot(new Apfloat(0), 2); fail("inverse sqrt of 0 accepted"); } catch (ArithmeticException ae) { // OK: result would be infinite } try { ApfloatMath.inverseRoot(new Apfloat(3), 2, 0); fail("precision 0 accepted"); } catch (IllegalArgumentException iae) { // OK: invalid input } try { ApfloatMath.inverseRoot(new Apfloat(3), 2); fail("infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK: can't have infinite memory } } public static void testRoot() { assertEquals("0", new Apfloat(0), ApfloatMath.root(Apfloat.ZERO, 3)); assertEquals("1", new Apfloat(1), ApfloatMath.root(Apfloat.ONE, 5)); assertEquals("1st root", new Apfloat(2), ApfloatMath.root(new Apfloat(2), 1)); assertEquals("root(2, 2)", new Apfloat(1.4142135623730950488016887242097), ApfloatMath.root(new Apfloat(2.0), 2), new Apfloat(1e-15)); assertEquals("root(2, -2)", new Apfloat(0.70710678118654752440084436210485), ApfloatMath.root(new Apfloat(2.0), -2), new Apfloat(5e-16)); //assertEquals("0x7FFFFFFFFFFFFFFFth root of 2", new Apfloat("1.0000000000000000000751511679015"), ApfloatMath.root(new Apfloat(2, 30), 0x7FFFFFFFFFFFFFFFL), new Apfloat(2e-29)); //assertEquals("0x8000000000000000th root of 2", new Apfloat("0.99999999999999999992484883209847"), ApfloatMath.root(new Apfloat(2, 30), 0x8000000000000000L), new Apfloat(2e-29)); assertEquals("sqrt(2)", new Apfloat(1.4142135623730950488016887242097), ApfloatMath.sqrt(new Apfloat(2.0)), new Apfloat(1e-15)); assertEquals("cbrt(2)", new Apfloat(1.2599210498948731647672106072782), ApfloatMath.cbrt(new Apfloat(2.0)), new Apfloat(1e-15)); assertEquals("root(2^1048576,1048576)", new Apfloat(2), ApfloatMath.root(ApfloatMath.pow(new Apfloat(2, 30), 1048576), 1048576), new Apfloat(1e-29)); assertEquals("root(2^100000000000,100000000000)", new Apfloat(2), ApfloatMath.root(ApfloatMath.pow(new Apfloat(2, 30), 100000000000L), 100000000000L), new Apfloat(1e-29)); //assertEquals("root(2^100000000000000000,100000000000000000)", new Apfloat(2), ApfloatMath.root(ApfloatMath.pow(new Apfloat(2, 30), 100000000000000000L), 100000000000000000L), new Apfloat(1e-29)); assertEquals("0 radix 12", 12, ApfloatMath.root(new Apint(0, 12), 3).radix()); try { ApfloatMath.root(new Apfloat(2), 0); fail("zeroth root accepted"); } catch (ArithmeticException ae) { // OK: zeroth root } try { ApfloatMath.root(new Apfloat(-2), 2); fail("sqrt of -2 accepted"); } catch (ArithmeticException ae) { // OK: result would be imaginary } try { ApfloatMath.root(new Apfloat(0), 0); fail("0th root of 0 accepted"); } catch (ArithmeticException ae) { // OK: result would be undefined } try { ApfloatMath.root(new Apfloat(3), 2); fail("infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK: can't have infinite memory } } public static void testAbs() { Apfloat x = new Apfloat(2); assertEquals("2", new Apfloat(2), ApfloatMath.abs(x)); x = new Apfloat(-2); assertEquals("-2", new Apfloat(2), ApfloatMath.abs(x)); x = new Apfloat(0); assertEquals("0", new Apfloat(0), ApfloatMath.abs(x)); } public static void testCopySign() { assertEquals("2, 1", new Apfloat(2), ApfloatMath.copySign(new Apfloat(2), new Apfloat(1))); assertEquals("2, -1", new Apfloat(-2), ApfloatMath.copySign(new Apfloat(2), new Apfloat(-1))); assertEquals("-2, 1", new Apfloat(2), ApfloatMath.copySign(new Apfloat(-2), new Apfloat(1))); assertEquals("-2, -1", new Apfloat(-2), ApfloatMath.copySign(new Apfloat(-2), new Apfloat(-1))); assertEquals("0, 0", new Apfloat(0), ApfloatMath.copySign(new Apfloat(0), new Apfloat(0))); assertEquals("0, 1", new Apfloat(0), ApfloatMath.copySign(new Apfloat(0), new Apfloat(1))); assertEquals("0, -1", new Apfloat(0), ApfloatMath.copySign(new Apfloat(0), new Apfloat(-1))); assertEquals("1, 0", new Apfloat(0), ApfloatMath.copySign(new Apfloat(1), new Apfloat(0))); assertEquals("-1, 0", new Apfloat(0), ApfloatMath.copySign(new Apfloat(-1), new Apfloat(0))); } public static void testFloor() { Apfloat x = new Apfloat("1.1"); assertEquals("1.1", new Apfloat(1), ApfloatMath.floor(x)); } public static void testCeil() { Apfloat x = new Apfloat("1.1"); assertEquals("1.1", new Apfloat(2), ApfloatMath.ceil(x)); } public static void testTruncate() { Apfloat x = new Apfloat("-1.1"); assertEquals("-1.1", new Apfloat(-1), ApfloatMath.truncate(x)); } public static void testFrac() { Apfloat x = new Apfloat("-1.1"); assertEquals("-1.1", new Apfloat("-0.1"), ApfloatMath.frac(x)); } @SuppressWarnings("deprecation") public static void testRound() { Apfloat[] inputs = { new Apfloat("5.5"), new Apfloat("2.5"), new Apfloat("1.6"), new Apfloat("1.1"), new Apfloat("1.0"), new Apfloat("-1.0"), new Apfloat("-1.1"), new Apfloat("-1.6"), new Apfloat("-2.5"), new Apfloat("-5.5") }; RoundingMode[] roundingModes = { UP, DOWN, CEILING, FLOOR, HALF_UP, HALF_DOWN, HALF_EVEN, UNNECESSARY }; Apfloat[][] expected = { { new Apint(6), new Apint(5), new Apint(6), new Apint(5), new Apint(6), new Apint(5), new Apint(6), null }, { new Apint(3), new Apint(2), new Apint(3), new Apint(2), new Apint(3), new Apint(2), new Apint(2), null }, { new Apint(2), new Apint(1), new Apint(2), new Apint(1), new Apint(2), new Apint(2), new Apint(2), null }, { new Apint(2), new Apint(1), new Apint(2), new Apint(1), new Apint(1), new Apint(1), new Apint(1), null }, { new Apint(1), new Apint(1), new Apint(1), new Apint(1), new Apint(1), new Apint(1), new Apint(1), new Apint(1) }, { new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1), new Apint(-1) }, { new Apint(-2), new Apint(-1), new Apint(-1), new Apint(-2), new Apint(-1), new Apint(-1), new Apint(-1), null }, { new Apint(-2), new Apint(-1), new Apint(-1), new Apint(-2), new Apint(-2), new Apint(-2), new Apint(-2), null }, { new Apint(-3), new Apint(-2), new Apint(-2), new Apint(-3), new Apint(-3), new Apint(-2), new Apint(-2), null }, { new Apint(-6), new Apint(-5), new Apint(-5), new Apint(-6), new Apint(-6), new Apint(-5), new Apint(-6), null } }; for (int i = 0; i < inputs.length; i++) { Apfloat input = inputs[i]; for (int j = 0; j < roundingModes.length; j++) { RoundingMode roundingMode = roundingModes[j]; Object result; try { result = ApfloatMath.round(input, 1, roundingMode); } catch (ArithmeticException ae) { result = null; } assertEquals(expected[i][j], result); } } assertEquals(new Apfloat("555.5600"), ApfloatMath.round(new Apfloat("555.5555"), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("555.5560"), ApfloatMath.round(new Apfloat("555.5555"), 6, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("555.5555"), ApfloatMath.round(new Apfloat("555.5555"), 7, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("555.5555"), ApfloatMath.round(new Apfloat("555.5555"), Apfloat.INFINITE, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("0.0005555600"), ApfloatMath.round(new Apfloat("0.0005555555"), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1010", Apfloat.DEFAULT, 2), ApfloatMath.round(new Apfloat("1.10101", Apfloat.DEFAULT, 2), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1100", Apfloat.DEFAULT, 2), ApfloatMath.round(new Apfloat("1.10111", Apfloat.DEFAULT, 2), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1111", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.11111", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1112", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.11112", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1112", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.11121", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1120", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.11122", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1111", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.1111111111111111111111111111", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1112", Apfloat.DEFAULT, 3), ApfloatMath.round(new Apfloat("1.1111111111111111111111111112", Apfloat.DEFAULT, 3), 5, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("2", Apfloat.DEFAULT, 28), ApfloatMath.round(new Apfloat("1.r", Apfloat.DEFAULT, 28), 1, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("2", Apfloat.DEFAULT, 36), ApfloatMath.round(new Apfloat("1.z", Apfloat.DEFAULT, 36), 1, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1e9223372036853775808"), ApfloatMath.round(new Apfloat("1.1e9223372036853775808"), 100000000000L, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat("1.1e-9223372036853775808"), ApfloatMath.round(new Apfloat("1.1e-9223372036853775808"), 100000000000L, RoundingMode.HALF_EVEN)); assertEquals(new Apfloat(0), ApfloatMath.round(new Apfloat(0), 1, RoundingMode.UNNECESSARY)); assertEquals(new Apfloat(0), ApfloatMath.round(new Apfloat(0), Apfloat.INFINITE, RoundingMode.UNNECESSARY)); Apfloat a = ApfloatMath.round(new Apfloat(1), Apfloat.INFINITE, RoundingMode.UNNECESSARY); assertEquals("1, infinite precision", Apfloat.INFINITE, a.precision()); assertEquals("1, infinite value", new Apfloat(1), a); a = ApfloatMath.round(new Apfloat(1), 1, RoundingMode.UNNECESSARY); assertEquals("1, 1 precision", 1, a.precision()); assertEquals("1, 1 value", new Apfloat(1), a); a = ApfloatMath.round(new Apfloat(12345, 4), 4, RoundingMode.UNNECESSARY); assertEquals("12345, 4 precision ", 4, a.precision()); assertEquals("12345, 4 value", new Apfloat(12340), a.precision(5)); a = ApfloatMath.round(new Apfloat(12345).precision(4), 4, RoundingMode.UNNECESSARY); assertEquals("12345, inifite/4 precision", 4, a.precision()); assertEquals("12345, inifite/4 value", new Apfloat(12340), a.precision(5)); a = ApfloatMath.round(new Apfloat(12345, 4), 5, RoundingMode.UNNECESSARY); assertEquals("12345, 5 precision", 5, a.precision()); assertEquals("12345, 5 value", new Apfloat(12340), a); a = ApfloatMath.round(new Apfloat(12345).precision(4), 5, RoundingMode.UNNECESSARY); assertEquals("12345, inifite/5 precision", 5, a.precision()); assertEquals("12345, inifite/5 value", new Apfloat(12340), a); try { ApfloatMath.round(new Apfloat(1000), 0, RoundingMode.HALF_EVEN); fail("precision 0 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.round(new Apfloat(1000), -1, RoundingMode.HALF_EVEN); fail("precision -1 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.round(new Apfloat(1000), Long.MIN_VALUE, RoundingMode.HALF_EVEN); fail("precision Long.MIN_VALUE accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } } public static void testRoundToPrecision() { Apfloat a = ApfloatMath.roundToPrecision(new Apfloat(4), 2, RoundingMode.UNNECESSARY); assertEquals("4, 2, infinite precision", 2, a.precision()); assertEquals("4, 2, infinite value", new Apfloat(4), a); a = ApfloatMath.roundToPrecision(new Apfloat("1.1e-1000000", Apfloat.INFINITE), Apfloat.INFINITE - 1, RoundingMode.UNNECESSARY); assertEquals("1.1e-1000000, infinite-1 precision", Apfloat.INFINITE - 1, a.precision()); assertEquals("1.1e-1000000, infinite-1 value", new Apfloat("1.1e-1000000"), a); } public static void testRoundToInteger() { Apint a = ApfloatMath.roundToInteger(new Apfloat(40), RoundingMode.UNNECESSARY); assertEquals("40", new Apfloat(40), a); a = ApfloatMath.roundToInteger(new Apfloat("4.1"), RoundingMode.UP); assertEquals("4.1 UP", new Apfloat(5), a); a = ApfloatMath.roundToInteger(new Apfloat("4.9"), RoundingMode.DOWN); assertEquals("4.9 DOWN", new Apfloat(4), a); a = ApfloatMath.roundToInteger(new Apfloat("-4.9"), RoundingMode.CEILING); assertEquals("-4.9 CEILING", new Apfloat(-4), a); a = ApfloatMath.roundToInteger(new Apfloat("-4.1"), RoundingMode.FLOOR); assertEquals("-4.1 FLOOR", new Apfloat(-5), a); a = ApfloatMath.roundToInteger(new Apfloat("5.4"), RoundingMode.HALF_UP); assertEquals("5.4 HALF_UP", new Apfloat(5), a); a = ApfloatMath.roundToInteger(new Apfloat("5.5"), RoundingMode.HALF_UP); assertEquals("5.5 HALF_UP", new Apfloat(6), a); a = ApfloatMath.roundToInteger(new Apfloat("5.6"), RoundingMode.HALF_UP); assertEquals("5.6 HALF_UP", new Apfloat(6), a); a = ApfloatMath.roundToInteger(new Apfloat("5.4"), RoundingMode.HALF_DOWN); assertEquals("5.4 HALF_DOWN", new Apfloat(5), a); a = ApfloatMath.roundToInteger(new Apfloat("5.5"), RoundingMode.HALF_DOWN); assertEquals("5.5 HALF_DOWN", new Apfloat(5), a); a = ApfloatMath.roundToInteger(new Apfloat("5.6"), RoundingMode.HALF_DOWN); assertEquals("5.6 HALF_DOWN", new Apfloat(6), a); a = ApfloatMath.roundToInteger(new Apfloat("-5.4"), RoundingMode.HALF_EVEN); assertEquals("-5.4 HALF_EVEN", new Apfloat(-5), a); a = ApfloatMath.roundToInteger(new Apfloat("-5.5"), RoundingMode.HALF_EVEN); assertEquals("-5.5 HALF_EVEN", new Apfloat(-6), a); a = ApfloatMath.roundToInteger(new Apfloat("-5.6"), RoundingMode.HALF_EVEN); assertEquals("-5.6 HALF_EVEN", new Apfloat(-6), a); a = ApfloatMath.roundToInteger(new Apfloat("1e-1000000000000000"), RoundingMode.UP); assertEquals("1e-1000000000000000 UP", new Apfloat(1), a); try { ApfloatMath.roundToInteger(new Apfloat("1.1"), RoundingMode.UNNECESSARY); fail("rounding accepted"); } catch (ArithmeticException ae) { // OK; rounding necessary } } public static void testRoundToPlaces() { Apfloat a = ApfloatMath.roundToPlaces(new Apfloat("1.2345", Apfloat.INFINITE), 4, RoundingMode.UNNECESSARY); assertEquals("1.2345, 4, infinite precision", Apfloat.INFINITE, a.precision()); assertEquals("1.2345, 4, infinite value", new Apfloat("1.2345"), a); a = ApfloatMath.roundToPlaces(new Apfloat(0), Long.MIN_VALUE, RoundingMode.UNNECESSARY); assertEquals("0, MIN_VALUE precision", Apfloat.INFINITE, a.precision()); assertEquals("0, MIN_VALUE value", new Apfloat(0), a); a = ApfloatMath.roundToPlaces(new Apfloat("1.2345"), 2, RoundingMode.DOWN); assertEquals("1.2345, 2, DOWN precision", Apfloat.INFINITE, a.precision()); assertEquals("1.2345, 2, DOWN value", new Apfloat("1.23"), a); a = ApfloatMath.roundToPlaces(new Apfloat("1.2345"), 2, RoundingMode.UP); assertEquals("1.2345, 2, UP precision", Apfloat.INFINITE, a.precision()); assertEquals("1.2345, 2, UP value", new Apfloat("1.24"), a); a = ApfloatMath.roundToPlaces(new Apfloat("123.45"), -2, RoundingMode.CEILING); assertEquals("123.45, -2, CEILING precision", Apfloat.INFINITE, a.precision()); assertEquals("123.45, -2, CEILING value", new Apfloat("200"), a); a = ApfloatMath.roundToPlaces(new Apfloat("-123.45"), -4, RoundingMode.FLOOR); assertEquals("-123.45, -4, FLOOR precision", Apfloat.INFINITE, a.precision()); assertEquals("-123.45, -4, FLOOR value", new Apfloat("-10000"), a); a = ApfloatMath.roundToPlaces(new Apfloat("-123.45"), 1, RoundingMode.HALF_UP); assertEquals("-123.45, 1, HALF_UP precision", Apfloat.INFINITE, a.precision()); assertEquals("-123.45, 1, HALF_UP value", new Apfloat("-123.5"), a); a = ApfloatMath.roundToPlaces(new Apfloat("-123.45"), 1, RoundingMode.HALF_DOWN); assertEquals("-123.45, 1, HALF_DOWN precision", Apfloat.INFINITE, a.precision()); assertEquals("-123.45, 1, HALF_DOWN value", new Apfloat("-123.4"), a); a = ApfloatMath.roundToPlaces(new Apfloat("123.45"), 1, RoundingMode.HALF_EVEN); assertEquals("123.45, 1, HALF_EVEN precision", Apfloat.INFINITE, a.precision()); assertEquals("123.45, 1, HALF_EVEN value", new Apfloat("123.4"), a); a = ApfloatMath.roundToPlaces(new Apfloat("123.45e1000000"), Long.MIN_VALUE, RoundingMode.DOWN); assertEquals("123.45e1000000, MIN_VALUE, UP precision", Apfloat.INFINITE, a.precision()); assertEquals("123.45e1000000, MIN_VALUE, UP value", new Apfloat(0), a); try { ApfloatMath.roundToPlaces(new Apfloat("1.1"), Long.MIN_VALUE, RoundingMode.DOWN); fail("Should underflow or overflow"); } catch (OverflowException oe) { // OK; underflow / overflow } try { ApfloatMath.roundToPlaces(new Apfloat("1.1"), Long.MIN_VALUE, RoundingMode.UP); fail("Should underflow or overflow"); } catch (OverflowException oe) { // OK; underflow / overflow } try { ApfloatMath.roundToPlaces(new Apfloat("1.2345"), 2, RoundingMode.UNNECESSARY); fail("rounding accepted"); } catch (ArithmeticException ae) { // OK; rounding necessary } } public static void testRoundToMultiple() { Apfloat a = ApfloatMath.roundToMultiple(new Apfloat(4), new Apfloat(2), RoundingMode.UNNECESSARY); assertEquals("4, 2, infinite precision", Apfloat.INFINITE, a.precision()); assertEquals("4, 2, infinite value", new Apfloat(4), a); a = ApfloatMath.roundToMultiple(new Apfloat("1.3"), new Apfloat("0.3"), RoundingMode.UP); assertEquals("1.3, 0.3, UP precision", 1, a.precision()); assertEquals("1.3, 0.3, UP value", new Apfloat("1.5", 1), a); // Highly questionable if this is meaningful at all a = ApfloatMath.roundToMultiple(new Apfloat("1.3"), new Apfloat("0.30"), RoundingMode.UP); assertEquals("1.3, 0.30, UP precision", 2, a.precision()); assertEquals("1.3, 0.30, UP value", new Apfloat("1.5"), a); a = ApfloatMath.roundToMultiple(new Apfloat("2.3"), new Apfloat("1.1"), RoundingMode.DOWN); assertEquals("2.3, 1.1, DOWN precision", 2, a.precision()); assertEquals("2.3, 1.1, DOWN value", new Apfloat("2.2"), a); a = ApfloatMath.roundToMultiple(new Apfloat("2.2"), new Apfloat("1.1"), RoundingMode.UNNECESSARY); assertEquals("2.2, 1.1, UNNECESSARY precision", 2, a.precision()); assertEquals("2.2, 1.1, UNNECESSARY value", new Apfloat("2.2"), a); a = ApfloatMath.roundToMultiple(new Apfloat("3.3"), new Apfloat("2.2"), RoundingMode.HALF_DOWN); assertEquals("3.3, 2.2, HALF_DOWN precision", 2, a.precision()); assertEquals("3.3, 2.2, HALF_DOWN value", new Apfloat("2.2"), a); a = ApfloatMath.roundToMultiple(new Apfloat("3.3"), new Apfloat("2.2"), RoundingMode.HALF_UP); assertEquals("3.3, 2.2, HALF_UP precision", 2, a.precision()); assertEquals("3.3, 2.2, HALF_UP value", new Apfloat("4.4"), a); a = ApfloatMath.roundToMultiple(new Apfloat("5.5"), new Apfloat("2.2"), RoundingMode.HALF_EVEN); assertEquals("5.5, 2.2, HALF_EVEN precision", 2, a.precision()); assertEquals("5.5, 2.2, HALF_EVEN value", new Apfloat("4.4"), a); a = ApfloatMath.roundToMultiple(new Apfloat("-2.9"), new Apfloat("1.1"), RoundingMode.CEILING); assertEquals("-2.9, 1.1, CEILING precision", 2, a.precision()); assertEquals("-2.9, 1.1, CEILING value", new Apfloat("-2.2"), a); a = ApfloatMath.roundToMultiple(new Apfloat("-2.3"), new Apfloat("1.1"), RoundingMode.FLOOR); assertEquals("-2.3, 1.1, FLOOR precision", 2, a.precision()); assertEquals("-2.3, 1.1, FLOOR value", new Apfloat("-3.3"), a); a = ApfloatMath.roundToMultiple(new Apfloat("123456.7"), new Apfloat("0.3"), RoundingMode.UP); assertEquals("123456.7, 0.3, UP precision", 1, a.precision()); assertEquals("123456.7, 0.3, UP value", new Apfloat("123456.9", 1), a); // Highly questionable if this is meaningful at all a = ApfloatMath.roundToMultiple(new Apfloat("0.3"), new Apfloat("123456.7"), RoundingMode.UP); assertEquals("0.3, 123456.7, UP precision", 7, a.precision()); assertEquals("0.3, 123456.7, UP value", new Apfloat("123456.7"), a); a = ApfloatMath.roundToMultiple(new Apfloat("0"), new Apfloat("123456.7"), RoundingMode.UP); assertEquals("0, 123456.7, UP precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 123456.7, UP value", new Apfloat(0), a); try { ApfloatMath.roundToMultiple(new Apfloat("1.2345"), new Apfloat(0), RoundingMode.UP); fail("Non-zero as multiple of zero"); } catch (ArithmeticException ae) { // OK; impossible } try { ApfloatMath.roundToMultiple(new Apfloat("2.3e8999999999999999999"), new Apfloat("1.1e-8999999999999999999"), RoundingMode.UP); fail("Too big scale difference"); } catch (OverflowException oe) { // OK; too big scale difference } } @SuppressWarnings("deprecation") public static void testNegate() { Apfloat x = new Apfloat(2); assertEquals("2", new Apfloat(-2), ApfloatMath.negate(x)); x = new Apfloat(-2); assertEquals("-2", new Apfloat(2), ApfloatMath.negate(x)); x = new Apfloat(0); assertEquals("0", new Apfloat(0), ApfloatMath.negate(x)); } public static void testModf() { Apfloat[] f = ApfloatMath.modf(new Apfloat(2)); assertEquals("2 i", new Apfloat(2), f[0]); assertEquals("2 f", new Apfloat(0), f[1]); f = ApfloatMath.modf(new Apfloat("1.5")); assertEquals("1.5 i", new Apfloat(1), f[0]); assertEquals("1.5 f", new Apfloat("0.5"), f[1]); assertEquals("1.5 f precision", 1, f[1].precision()); f = ApfloatMath.modf(new Apfloat("-1.5", 3)); assertEquals("-1.5 i", new Apfloat(-2), f[0]); assertEquals("-1.5 f", new Apfloat("0.5"), f[1]); assertEquals("-1.5 f precision", 2, f[1].precision()); } public static void testFmod() { assertEquals("0, 1", new Apfloat(0), ApfloatMath.fmod(new Apfloat(0), Apfloat.ONE)); assertEquals("1, 0", new Apfloat(0), ApfloatMath.fmod(new Apfloat(1), Apfloat.ZERO)); assertEquals("2, 3", new Apfloat(2), ApfloatMath.fmod(new Apfloat(2), new Apfloat(3))); assertEquals("2, -3", new Apfloat(2), ApfloatMath.fmod(new Apfloat(2), new Apfloat(-3))); assertEquals("-2, 3", new Apfloat(-2), ApfloatMath.fmod(new Apfloat(-2), new Apfloat(3))); assertEquals("-2, -3", new Apfloat(-2), ApfloatMath.fmod(new Apfloat(-2), new Apfloat(-3))); assertEquals("200, 3 no precision", new Apfloat(0), ApfloatMath.fmod(new Apfloat(200, 1), new Apfloat(3))); assertEquals("20, 3 no precision", new Apfloat(0), ApfloatMath.fmod(new Apfloat(20, 1), new Apfloat(3))); assertEquals("20, 3 no precision radix", 12, ApfloatMath.fmod(new Apfloat(20, 1, 12), new Apfloat(3, Apfloat.DEFAULT, 12)).radix()); assertEquals("20, 2", new Apfloat(0), ApfloatMath.fmod(new Apfloat(20, 2), new Apfloat(2))); Apfloat a = ApfloatMath.fmod(new Apfloat(20, 2), new Apfloat(3)); assertEquals("20, 3 precision 1, precision", 1, a.precision()); assertEquals("20, 3 precision 1, value", new Apfloat(2), a); a = ApfloatMath.fmod(new Apfloat("11257801564015978614078912465097"), new Apfloat("12590784789234078934789457778")); assertEquals("11257801564015978614078912465097, 12590784789234078934789457778, precision", 28, a.precision()); assertEquals("11257801564015978614078912465097, 12590784789234078934789457778, value", new Apfloat("1639962440712046377137211565"), a); a = ApfloatMath.fmod(new Apfloat("11257801564015978614078912465097"), new Apfloat(13)); assertEquals("11257801564015978614078912465097, 13, precision", 1, a.precision()); assertEquals("11257801564015978614078912465097, 13, value", new Apfloat(4), a); a = ApfloatMath.fmod(new Apfloat("11257801564015978614078912465097"), new Apfloat(19)); assertEquals("11257801564015978614078912465097, 19, precision", 2, a.precision()); assertEquals("11257801564015978614078912465097, 19, value", new Apfloat(18), a); a = ApfloatMath.fmod(new Apfloat("123"), new Apfloat("13")); assertEquals("123, 13, precision", 1, a.precision()); assertEquals("123, 13, value", new Apfloat(6), a); a = ApfloatMath.fmod(new Apfloat("123"), new Apfloat("14")); assertEquals("123, 14, precision", 2, a.precision()); assertEquals("123, 14, value", new Apfloat(11), a); a = ApfloatMath.fmod(new Apfloat("123"), new Apfloat("61")); assertEquals("123, 61, precision", 1, a.precision()); assertEquals("123, 61, value", new Apfloat(1), a); a = ApfloatMath.fmod(new Apfloat("123"), new Apfloat("99")); assertEquals("123, 99, precision", 2, a.precision()); assertEquals("123, 99, value", new Apfloat(24), a); for (int i = 5; i <= 150; i++) { StringBuilder buffer = new StringBuilder(); for (int j = 0; j < i; j++) { buffer.append((char) ('1' - (j & 1))); } String value = buffer.toString(); Apfloat x = new Apfloat(value, Apfloat.DEFAULT, 9), y = new Apfloat(value, Apfloat.DEFAULT, 9), one = new Apfloat(1, Apfloat.DEFAULT, 9); assertEquals(x + ", " + y, new Apfloat(0), ApfloatMath.fmod(x, y)); assertEquals("-" + x + ", " + y, new Apfloat(0), ApfloatMath.fmod(x.negate(), y)); assertEquals(x + "+1, " + y, new Apfloat(1, Apfloat.DEFAULT, 9), ApfloatMath.fmod(x.add(one), y)); assertEquals("-1-" + x + ", " + y, new Apfloat(-1, Apfloat.DEFAULT, 9), ApfloatMath.fmod(one.add(x).negate(), y)); } assertEquals("very long, very long", new Apfloat("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApfloatMath.fmod(new Apfloat("610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apfloat("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); assertEquals("very long, -very long", new Apfloat("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApfloatMath.fmod(new Apfloat("610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apfloat("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); assertEquals("-very long, very long", new Apfloat("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApfloatMath.fmod(new Apfloat("-610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apfloat("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); assertEquals("-very long, -very long", new Apfloat("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApfloatMath.fmod(new Apfloat("-610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apfloat("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); a = ApfloatMath.fmod(new Apfloat("2.3e9000000000000000000"), new Apfloat("1.1e-9000000000000000000")); assertEquals("1.1e9000000000000000000, 1.1e-9000000000000000000, precision", Apfloat.INFINITE, a.precision()); assertEquals("1.1e9000000000000000000, 1.1e-9000000000000000000, value", new Apfloat(0), a); } public static void testMultiplyAdd() { Apfloat a = ApfloatMath.multiplyAdd(new Apfloat("2"), new Apfloat("3"), new Apfloat("4"), new Apfloat("5")); assertEquals("2 * 3 + 4 * 5 precision", 1, a.precision()); assertEquals("2 * 3 + 4 * 5 value", new Apfloat(26), a.precision(2)); a = ApfloatMath.multiplyAdd(new Apfloat("2", 2), new Apfloat("3", 2), new Apfloat("4", 2), new Apfloat("5", 2)); assertEquals("2 * 3 + 4 * 5, prec 2, precision", 2, a.precision()); assertEquals("2 * 3 + 4 * 5, prec 2, value", new Apfloat(26), a); a = ApfloatMath.multiplyAdd(new Apfloat(20, 1, 12), new Apfloat(30, 1, 12), new Apfloat("4", 1, 12), new Apfloat("5", 1, 12)); assertEquals("20 * 30 + 4 * 5, prec 1, precision", 1, a.precision()); assertEquals("20 * 30 + 4 * 5, prec 1, value", new Apfloat(600, 1, 12), a); a = ApfloatMath.multiplyAdd(new Apfloat(200, 2), new Apfloat(300, 2), new Apfloat(4), new Apfloat(5)); assertEquals("200 * 300 + 4 * 5, prec 2, precision", 2, a.precision()); assertEquals("200 * 300 + 4 * 5, prec 2, value", new Apfloat(60000), a.precision(Apfloat.INFINITE)); a = ApfloatMath.multiplyAdd(new Apfloat("4", 1, 12), new Apfloat("5", 1, 12), new Apfloat(20, 1, 12), new Apfloat(30, 1, 12)); assertEquals("4 * 5 + 20 * 30, prec 1, precision", 1, a.precision()); assertEquals("4 * 5 + 20 * 30, prec 1, value", new Apfloat(600, 1, 12), a); a = ApfloatMath.multiplyAdd(new Apfloat(4), new Apfloat(5), new Apfloat(200, 2), new Apfloat(300, 2)); assertEquals("4 * 5 + 200 * 300, prec 2, precision", 2, a.precision()); assertEquals("4 * 5 + 200 * 300, prec 2, value", new Apfloat(60000), a.precision(Apfloat.INFINITE)); // xxxxx000 * xxxxx + xxx00000 * xxx0 = // xxxxxx0000000 + xxxx00000000 = // xxxxx00000000 + xxxx00000000 = // xxxx000000000 / xxxx00000000 a = ApfloatMath.multiplyAdd(new Apfloat(12345678, 8), new Apfloat(12345, 5), new Apfloat(12345678, 5), new Apfloat(1234, 3)); assertEquals("5-4-4 precision", 4, a.precision()); assertEquals("5-4-4 value", new Apfloat(167641961562L), a, new Apfloat(100000000)); } public static void testMultiplySubtract() { Apfloat a = ApfloatMath.multiplySubtract(new Apfloat(2), new Apfloat(3), new Apfloat(4), new Apfloat(5)); assertEquals("2 * 3 - 4 * 5 precision", Apfloat.INFINITE, a.precision()); assertEquals("2 * 3 - 4 * 5 value", new Apfloat(-14), a.precision(2)); } public static void testAgm() { Apfloat a = ApfloatMath.agm(new Apfloat(1, 100), new Apfloat(2, 100)); assertEquals("1, 2 precision", 100, a.precision()); assertEquals("1, 2 value", new Apfloat("1.4567910310469068691864323832650819749738639432213055907941723832679264545802509002574737128184484443281894"), a, new Apfloat("5e-99")); a = ApfloatMath.agm(new Apfloat(1, 1), new Apfloat(2, 1)); assertEquals("1, 2, prec 1, precision", 1, a.precision()); assertEquals("1, 2, prec 1, value", new Apfloat(1), a, new Apfloat(1)); a = ApfloatMath.agm(new Apfloat(1, 10), new Apfloat(2, 20)); assertEquals("1, 2, prec 10-20, precision", 10, a.precision()); assertEquals("1, 2, prec 10-20, value", new Apfloat("1.456791031"), a, new Apfloat("5e-9")); a = ApfloatMath.agm(new Apfloat(-1, 20), new Apfloat(-2, 10)); assertEquals("-1, -2, prec 10-20, precision", 10, a.precision()); assertEquals("-1, -2, prec 10-20, value", new Apfloat("-1.456791031"), a, new Apfloat("5e-9")); a = ApfloatMath.agm(new Apfloat("1.000000000e10"), new Apfloat("1.000000000e-10")); assertEquals("1e10, 1e-10, precision 10", 10, a.precision()); assertEquals("1e10, 1e-10, value, precision 10", new Apfloat("331126196.7"), a, new Apfloat("0.5")); a = ApfloatMath.agm(new Apfloat("1.0000000000000000000e10"), new Apfloat("1.000000000e-10")); assertEquals("1e10, 1e-10, precision 10-20", 10, a.precision()); assertEquals("1e10, 1e-10, value, precision 10-20", new Apfloat("331126196.7"), a, new Apfloat("0.5")); a = ApfloatMath.agm(new Apfloat(1, 10), new Apfloat(1, 20)); assertEquals("1, 1, prec 10-20, precision", 10, a.precision()); assertEquals("1, 1, prec 10-20, value", new Apfloat(1), a); a = ApfloatMath.agm(new Apfloat(1, 20), new Apfloat(1, 10)); assertEquals("1, 1, prec 20-10, precision", 10, a.precision()); assertEquals("1, 1, prec 20-10, value", new Apfloat(1), a); a = ApfloatMath.agm(new Apfloat(0), new Apfloat(1)); assertEquals("0, 1", new Apfloat(0), a); a = ApfloatMath.agm(Apfloat.ONE, Apfloat.ZERO); assertEquals("1, 0", new Apfloat(0), a); a = ApfloatMath.agm(new Apfloat(-1), new Apfloat(1)); assertEquals("-1, 1", new Apfloat(0), a); a = ApfloatMath.agm(new Apint(1, 12), new Apint(0, 12)); assertEquals("1, 0 radix", 12, a.radix()); a = ApfloatMath.agm(new Apint(1, 12), new Apint(-1, 12)); assertEquals("1, -1 radix", 12, a.radix()); a = new Apfloat("1.456791031046906869186432383265081974973863943221305590794172383267926454580250900257473712818448444328189401816036799935576243074340124511691213249952279376897021197672689372826666678270743290207238456460096313336749441664951640082693223908626337673838241025488726264513659066040887588510046672813094743978935512911720175447186956416035641113070606125170400972745374521370401420144157682323238964502909132239229201863020459196677536211529560998432049400961861338863911084030381488628159073170114235547302303533626208986835613080075985703121250813571733533606272496417145565136129415437696905495272776402217189832840401938243495416339663411171247074920049399475823655320274233156954218768925951056191034134712504572955839404827707329984173302332020201906541083764475690954512308594220997449412380273230046465841574004772512701790771147617828666064344158947341035545499540170260305012929701470776236465507485850428931202947542598396287345703761265310456809232764193204759624931172723676784849010063883831645335627155765372880260543270126668904548807658246837332956745606320439206000827315925297924120517572792956898069837182018081118012502131089972469511003170367875430017874462279301921060156857761490839367431915105478717272782446538831715921363968336746689231345994523668360452657260101103397053499527132362563007397454373813873045156390854348724120700844774879469375150443446048584280930172395926036732129188875719856402864926298810995160417385214470404976503137921156910217010840121652176385776278443131535045190731074843750437867090838446698767945050890489992429995490314062282068159093045161404523458248697227150619981888378435664415174711160595006902423143459075966810454416997061373268370421830924936517791683419258027937814913005585514983905421612991836639607353242591728408919130405601743611335886762255281130983568838120661186537684120574342592819568100284858774281240119689820354838043041113162808407169939503577633814675423251711145297625856010709698328986771681300270753462124431438249079287242299178307352064301908595916689642113630953871478324579363224590054821977720752752434856153962211487647114809252498114236281605836155826301649837304049554058938232508056924063922852025132566569884400145216494747221972532532860069992021237959974546155685028445119102475386567214984215767810803373267199219113161724471869212162578104306058776030926578404910389652192404389117677295835067825022753770320621321736011850304863716204309012040569800028743530750682957857187725797496332806514717356341562788595136219969639265644529365016344351116338283641806458971781098774751480098405354570139783225722233163294120124683588116225556912157809787231837370485212940457115577099959109605532398430813959714213851721154337178339537086640233608391562229893503493649411031401362724533210284028590050377655433375682840029673698157498020943869571637004045326975420227362140674697142027390581797343320575190963092149403833594112151706423118043310372943975783109168287709984495991399458167906285118753395839483377129729549566614285242117269351913253207745257819406658932664711556189413"); for (int prec = 500; prec <= 3000; prec += 100) { Apfloat agm = ApfloatMath.agm(new Apfloat(1, prec), new Apfloat(2, prec)); assertEquals("agm prec " + prec + " precision", prec, agm.precision()); assertEquals("agm prec " + prec + " value", a.precision(prec), agm, new Apfloat("5e-" + prec)); } for (int prec = 901; prec < 1000; prec++) { Apfloat agm = ApfloatMath.agm(new Apfloat(1, prec), new Apfloat(2, prec)); assertEquals("agm prec " + prec + " precision", prec, agm.precision()); assertEquals("agm prec " + prec + " value", a.precision(prec), agm, new Apfloat("5e-" + prec)); } try { ApfloatMath.agm(new Apfloat(1.0), new Apfloat(-2.0)); fail("AGM with complex result accepted"); } catch (ArithmeticException ae) { // OK; non-real result } try { ApfloatMath.agm(new Apfloat(1), new Apfloat(2)); fail("AGM to infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; can't calculate this to infinite precision } } public static void testFactorial() { Apfloat result = ApfloatMath.factorial(100, 10); assertEquals("value", new Apfloat(9.332621544e157), result, new Apfloat("5e148")); assertEquals("precision", 10, result.precision()); result = ApfloatMath.factorial(10, Apfloat.INFINITE, 16); assertEquals("value 16", new Apfloat(0x375F00, Apfloat.DEFAULT, 16), result); assertEquals("precision 16", Apfloat.INFINITE, result.precision()); try { ApfloatMath.factorial(7, 10, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testDoubleFactorial() { Apfloat result = ApfloatMath.doubleFactorial(99, 10); assertEquals("value", new Apfloat(2.725392140e78), result, new Apfloat("5e69")); assertEquals("precision", 10, result.precision()); result = ApfloatMath.doubleFactorial(11, Apfloat.INFINITE, 16); assertEquals("value 16", new Apfloat(0x289B, Apfloat.DEFAULT, 16), result); assertEquals("precision 16", Apfloat.INFINITE, result.precision()); try { ApfloatMath.doubleFactorial(7, 10, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testPi() { Apfloat pi10 = new Apfloat("3.14159265358979323846264338327950288419716939937510582097494459230781640628620899862803482534211706798214808651328230664709384460955058223172535940812848111745028410270193852110555964462294895493038196442881097566593344612847564823378678316527120190914564856692346034861045432664821339360726024914127372458700660631558817488152092096282925409171536436789259036001133053054882046652138414695194151160943305727036575959195309218611738193261179310511854807446237996274956735188575272489122793818301194912983367336244065664308602139494639522473719070217986094370277053921717629317675238467481846766940513200056812714526356082778577134275778960917363717872146844090122495343014654958537105079227968925892354201995611212902196086403441815981362977477130996051870721134999999837297804995105973173281609631859502445945534690830264252230825334468503526193118817101000313783875288658753320838142061717766914730359825349042875546873115956286388235378759375195778185778053217122680661300192787661119590921642019893809525720106548586327886593615338182796823030195203530185296899577362259941389124972177528347913151"); assertEquals("prec 100", pi10.precision(100), ApfloatMath.pi(100), new Apfloat(5e-98)); assertEquals("prec 1000", pi10, ApfloatMath.pi(1000), new Apfloat("5e-998")); assertEquals("prec 500 precision", 500, ApfloatMath.pi(500).precision()); assertEquals("prec 500 value", pi10.precision(500), ApfloatMath.pi(500)); assertEquals("prec 50 precision", 50, ApfloatMath.pi(50).precision()); assertEquals("prec 50 value", pi10.precision(50), ApfloatMath.pi(50)); assertEquals("base 16", new Apfloat("3.243F6A8885A308D313198A2E03707344A4093822299F31D00", Apfloat.DEFAULT, 16), ApfloatMath.pi(50, 16), new Apfloat(5e-100, 1, 16)); for (int prec = 1000; prec <= 1100; prec++) { Apfloat pi = ApfloatMath.pi(prec); assertEquals("pi prec " + prec + " precision", prec, pi.precision()); assertEquals("pi prec " + prec + " value", pi10.precision(prec), pi, new Apfloat("5e-" + (prec - 2))); } try { ApfloatMath.pi(0); fail("Precision 0 accepted"); } catch (IllegalArgumentException e) { // OK; invalid precision } try { ApfloatMath.pi(Apfloat.INFINITE); fail("Infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; invalid precision } try { ApfloatMath.pi(50, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testLog() { Apfloat a = ApfloatMath.log(new Apfloat(2, 100)); assertEquals("2, 100 precision", 100, a.precision()); assertEquals("2, 100 value", new Apfloat("0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687"), a, new Apfloat("5e-99")); a = ApfloatMath.log(new Apfloat(3, 150, 16)); assertEquals("3, 150 precision", 150, a.precision()); assertEquals("3, 150 value", new Apfloat("1.193ea7aad030a976a4198d55053b7cb5be1442d9b7e08df03d97eeea5149358caa9782d20cc698505071f733039a8ed5625c15071ea7bca1cf37d8f11024c66486d094e21e74d0a547df6", Apfloat.DEFAULT, 16), a, ApfloatMath.scale(new Apfloat(5, 1, 16), -148)); a = ApfloatMath.log(new Apfloat(1, 1, 12)); assertEquals("1", new Apfloat(0), a); assertEquals("1 radix", 12, a.radix()); a = ApfloatMath.log(new Apfloat("2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852516642")); assertEquals("e, 99, precision", 99, a.precision()); assertEquals("e, 99, value", new Apfloat(1), a, new Apfloat("5e-97")); a = ApfloatMath.log(new Apfloat("2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427")); assertEquals("e, 100, precision", 100, a.precision()); assertEquals("e, 100, value", new Apfloat(1), a, new Apfloat("5e-98")); a = ApfloatMath.log(new Apfloat("7.38905609893065022723042746057500781318031557055184732408712782252257379607905776338431248507912179")); assertEquals("e^2, 99, precision", 99, a.precision()); assertEquals("e^2, 99, value", new Apfloat(2), a, new Apfloat("5e-98")); a = ApfloatMath.log(new Apfloat("7.389056098930650227230427460575007813180315570551847324087127822522573796079057763384312485079121794")); assertEquals("e^2, 100, precision", 100, a.precision()); assertEquals("e^2, 100, value", new Apfloat(2), a, new Apfloat("5e-98")); a = ApfloatMath.log(new Apfloat("1.1")); assertEquals("1.1, precision", 1, a.precision()); a = ApfloatMath.log(new Apfloat("1.01")); assertEquals("1.01, precision", 1, a.precision()); a = ApfloatMath.log(new Apfloat("1.1", 3)); assertEquals("1.1, 3, precision", 2, a.precision()); a = ApfloatMath.log(new Apfloat("2.567534329783818000500533029709932117494558299117260796421579784603311989535237879614227625064708170e2171472", 100)); assertEquals("e^5000000, 100 precision", 106, a.precision()); assertEquals("e^5000000, 100 value", new Apfloat(5000000), a, new Apfloat("5e-99")); a = ApfloatMath.log(new Apfloat("3.894787261069254290252471079176073765185215930321023940272302235080330044710873765250549604329029361e-2171473", 100)); assertEquals("-e^5000000, 100 precision", 100, a.precision()); assertEquals("-e^5000000, 100 value", new Apfloat(-5000000), a, new Apfloat("5e-92")); Apfloat x = new Apfloat("0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687542001481020570685733685520235758130557032670751635075961930727570828371435190307038623891673471123350115364497955239120475172681574932065155524734139525882950453007095326366642654104239157814952043740430385500801944170641671518644712839968171784546957026271631064546150257207402481637773389638550695260668341137273873722928956493547025762652098859693201965058554764703306793654432547632744951250406069438147104689946506220167720424524529612687946546193165174681392672504103802546259656869144192871608293803172714367782654877566485085674077648451464439940461422603193096735402574446070308096085047486638523138181676751438667476647890881437141985494231519973548803751658612753529166100071053558249879414729509293113897155998205654392871700072180857610252368892132449713893203784393530887748259701715591070882368362758984258918535302436342143670611892367891923723146723217205340164925687274778234453534"); a = new Apfloat("-0.3665129205816643270124391582326694694542634478371052630536777136705616153193527385494558228566989083583025230453648347655663425171940646634814655030562792138730255618922699717672286041800832613019942189532855463393890461583132806371040809369384417114396747846899170526422674184027391035004631190422189323680484095772276875435803559664871149188455813202333163965976808249936452933584668462357426343756525369861095695215917735720106501342222449994153507078142297833029637774311970293974350362633156244687655088608994135490709908943039494582566844946811522717063194325489044697564936223469819270466722804100902961886880218201749101992361055490535324877585339998097074377916278218193441996319021050429330124241505927926809754056140292099176158224802342090188412736812269321284034933052507728909167575791393588626671908786468115956639594429979580206395481395923027937867469315592027193309322415124007731716247058993690703827533513739231800701041955722130456332586628947326070184882339110039410732806653401"); for (int prec = 500; prec <= 800; prec += 100) { Apfloat log = ApfloatMath.log(x.precision(prec)); assertEquals("log(log2) prec " + prec + " precision", prec, log.precision()); assertEquals("log(log2) prec " + prec + " value", a.precision(prec), log, new Apfloat("5e-" + prec)); } for (int prec = 900; prec <= 1000; prec++) { Apfloat log = ApfloatMath.log(x.precision(prec)); // NOTE: EXTRA ALLOWED ERROR NEEDED FOR CASE prec=1000 assertEquals("log(log2) prec " + prec + " precision", prec, log.precision()); assertEquals("log(log2) prec " + prec + " value", a.precision(prec), log, new Apfloat("11e-" + prec)); } a = new Apfloat("0.6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875420014810205706857336855202357581305570326707516350759619307275708283714351903070386238916734711233501153644979552391204751726815749320651555247341395258829504530070953263666426541042391578149520437404303855008019441706416715186447128399681717845469570262716310645461502572074024816377733896385506952606683411372738737229289564935470257626520988596932019650585547647033067936544325476327449512504060694381471046899465062201677204245245296126879465461931651746813926725041038025462596568691441928716082938031727143677826548775664850856740776484514644399404614226031930967354025744460703080960850474866385231381816767514386674766478908814371419854942315199735488037516586127535291661000710535582498794147295092931138971559982056543928717000721808576102523688921324497138932037843935308877482597017155910708823683627589842589185353024363421436706118923678919237231467232172053401649256872747782344535347648114941864238677677440606956265737960086707625719918473402265146283790488306203306114463007371949"); for (int prec = 1000; prec <= 1100; prec++) { Apfloat log = ApfloatMath.log(new Apfloat(2, prec)); assertEquals("log(2) prec " + prec + " precision", prec, log.precision()); assertEquals("log(2) prec " + prec + " value", a.precision(prec), log, new Apfloat("5e-" + prec)); } try { ApfloatMath.log(new Apfloat(0)); fail("log of zero accepted"); } catch (ArithmeticException ae) { // OK; result would be -infinite } try { ApfloatMath.log(new Apfloat(-1)); fail("log of -1 accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } try { ApfloatMath.log(new Apfloat(2)); fail("log to infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; can't calculate this to infinite precision } } public static void testLogBase() { Apfloat a = ApfloatMath.log(new Apfloat(4, 100), new Apfloat(2, 100)); assertEquals("4 base 2, precision 100", 100, a.precision()); assertEquals("4 base 2, value", new Apfloat(2), a, new Apfloat("5e-99")); a = ApfloatMath.log(new Apfloat(8, 400), new Apfloat(2, 200)); assertEquals("4 base 2, precision 200", 200, a.precision()); assertEquals("4 base 2, value", new Apfloat(3), a, new Apfloat("5e-199")); a = ApfloatMath.log(new Apfloat(16, 300), new Apfloat(2, 600)); assertEquals("4 base 2, precision 300", 300, a.precision()); assertEquals("4 base 2, value", new Apfloat(4), a, new Apfloat("5e-299")); a = ApfloatMath.log(new Apfloat(16, 400), new Apfloat(2)); assertEquals("4 base 2, precision 400", 400, a.precision()); assertEquals("4 base 2, value", new Apfloat(4), a, new Apfloat("5e-399")); a = ApfloatMath.log(new Apfloat(16), new Apfloat(2, 500)); assertEquals("4 base 2, precision 500", 500, a.precision()); assertEquals("4 base 2, value", new Apfloat(4), a, new Apfloat("5e-499")); a = ApfloatMath.log(new Apfloat(2, 5), new Apfloat("1.01", 7)); assertEquals("2 base 1.01, precision", 5, a.precision()); assertEquals("2 base 1.01, value", new Apfloat("69.661"), a, new Apfloat("5e-3")); a = ApfloatMath.log(new Apfloat("1.01", 7), new Apfloat(2, 5)); assertEquals("1.01 base 2, precision", 5, a.precision()); assertEquals("1.01 base 2, value", new Apfloat("0.014355"), a, new Apfloat("5e-6")); } public static void testExp() { Apfloat a = ApfloatMath.exp(new Apfloat(2, 100)); assertEquals("2, 100 precision", 100, a.precision()); assertEquals("2, 100 value", new Apfloat("7.389056098930650227230427460575007813180315570551847324087127822522573796079057763384312485079121794"), a, new Apfloat("5e-98")); a = ApfloatMath.exp(new Apfloat(3, 150, 16)); assertEquals("3, 150 precision", 150, a.precision()); assertEquals("3, 150 value", new Apfloat("14.15E5BF6FB105F2D4BDFC53744C3A390585839728AA90A12389790C837E6FF2A68ABFE2D58DAFA5273C74EB175B9D0BD5584DFC81BE96F62CE66F428A2A50FFCBDF4083E8EE811BE42F", Apfloat.DEFAULT, 16), a, ApfloatMath.scale(new Apfloat(5, 1, 16), -147)); a = ApfloatMath.exp(new Apfloat(0, 1, 17)); assertEquals("1 radix", 17, a.radix()); assertEquals("1 prec", Apfloat.INFINITE, a.precision()); assertEquals("1 value", new Apfloat(1), a); a = ApfloatMath.exp(new Apfloat("0.1")); assertEquals("0.1, precision", 2, a.precision()); a = ApfloatMath.exp(new Apfloat("0.01")); assertEquals("0.01, precision", 3, a.precision()); a = ApfloatMath.exp(new Apfloat("0.1", 2)); assertEquals("0.1, 2, precision", 3, a.precision()); a = ApfloatMath.exp(new Apfloat("1e-10", 32)); assertEquals("1e-10", new Apfloat("1.0000000001000000000050000000002"), a, new Apfloat("5e-31")); //a = ApfloatMath.exp(new Apfloat("1e" + Long.MIN_VALUE / 3 * 2)); //assertEquals("1e-2/3MIN", new Apfloat(1), a); a = ApfloatMath.exp(new Apfloat(5000000, 21)); assertEquals("5000000, 15 precision", 15, a.precision()); assertEquals("5000000, 15 value", new Apfloat("2.56753432978382e2171472"), a, new Apfloat("5e2171458")); a = ApfloatMath.exp(new Apfloat(5000000, 106)); assertEquals("5000000, 100 precision", 100, a.precision()); assertEquals("5000000, 100 value", new Apfloat("2.567534329783818000500533029709932117494558299117260796421579784603311989535237879614227625064708170e2171472"), a, new Apfloat("5e2171373")); a = ApfloatMath.exp(new Apfloat(-5000000, 106)); assertEquals("-5000000, 100 precision", 100, a.precision()); assertEquals("-5000000, 100 value", new Apfloat("3.894787261069254290252471079176073765185215930321023940272302235080330044710873765250549604329029361e-2171473"), a, new Apfloat("5e-2171572")); a = ApfloatMath.exp(new Apfloat("-1e25", 50)); assertEquals("-1e25, 50 value", new Apfloat(0), a); a = ApfloatMath.exp(new Apfloat("-1e25")); assertEquals("-1e25, 1 value", new Apfloat(0), a); a = ApfloatMath.exp(new Apfloat("-1e25", Apfloat.INFINITE)); assertEquals("-1e25, infinite value", new Apfloat(0), a); a = ApfloatMath.exp(new Apfloat("-21237598959199934509.830775042768")); assertEquals("-21237598959199934509.830775042768 value", new Apfloat(0), a); // How to compute this with some other tool: // exp(-2.123759895919992e19) = exp(-21237598959199920000) = exp(-2737330 * 2304964 * 3366000) // = (exp(-2737330) ^ 2304964) ^ 3366000 // = ((4.8512289541615048587 * 10 ^ -1188808) ^ 2304964) ^ 3366000 // = (4.8512289541615048587 ^ 2304964 * 10 ^ (-1188808 * 2304964)) ^ 3366000 // = (4.3958838520520181922 * 10 ^ 1580863 * 10 ^ (-1188808 * 2304964)) ^ 3366000 // = (4.3958838520520181922 * 10 ^ (1580863 + (-1188808 * 2304964)) ^ 3366000 // = 4.3958838520520181922 ^ 3366000 * 10 ^ ((1580863 + (-1188808 * 2304964)) * 3366000) // = 3.4628920318050121308 * 10 ^ 2164493 * 10 ^ ((1580863 + (-1188808 * 2304964)) * 3366000) // = 3.4628920318050121308 * 10 ^ (2164493 + (1580863 + (-1188808 * 2304964)) * 3366000) // = 3.4628920318050121308 * 10 ^ -9223372036854769507 a = ApfloatMath.exp(new Apfloat("-2.1237598959199920000000000000000000e19")); assertEquals("-2.123759895919992e19 precision", 16, a.precision()); assertEquals("-2.123759895919992e19 value", new Apfloat("3.462892031805012e-9223372036854769507"), a, new Apfloat("5e-9223372036854769491")); a = ApfloatMath.exp(new Apfloat("-100000000000000000000", 30, 17)); assertEquals("underflow radix", 17, a.radix()); assertEquals("underflow prec", Apfloat.INFINITE, a.precision()); assertEquals("underflow value", new Apfloat(0), a); a = new Apfloat("2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427427466391932003059921817413596629043572900334295260595630738132328627943490763233829880753195251019011573834187930702154089149934884167509244761460668082264800168477411853742345442437107539077744992069551702761838606261331384583000752044933826560297606737113200709328709127443747047230696977209310141692836819025515108657463772111252389784425056953696770785449969967946864454905987931636889230098793127736178215424999229576351482208269895193668033182528869398496465105820939239829488793320362509443117301238197068416140397019837679320683282376464804295311802328782509819455815301756717361332069811250996181881593041690351598888519345807273866738589422879228499892086805825749279610484198444363463244968487560233624827041978623209002160990235304369941849146314093431738143640546253152096183690888707016768396424378140592714563549061303107208510383750510115747704171898610687396965521267154688957035035"); for (int prec = 500; prec <= 800; prec += 100) { Apfloat exp = ApfloatMath.exp(new Apfloat(1, prec)); assertEquals("exp prec " + prec + " precision", prec, exp.precision()); assertEquals("exp prec " + prec + " value", a.precision(prec), exp, new Apfloat("5e-" + (prec - 1))); } for (int prec = 900; prec <= 1000; prec++) { Apfloat exp = ApfloatMath.exp(new Apfloat(1, prec)); assertEquals("exp prec " + prec + " precision", prec, exp.precision()); assertEquals("exp prec " + prec + " value", a.precision(prec), exp, new Apfloat("5e-" + (prec - 1))); } try { ApfloatMath.exp(new Apfloat("50000000000000000000", 500000000)); fail("Overflow should have occurred"); } catch (OverflowException oe) { // OK; result would overflow } try { ApfloatMath.exp(new Apfloat(2)); fail("exp to infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; can't calculate this to infinite precision } } public static void testPow() { Apfloat a = ApfloatMath.pow(new Apfloat(2, 100), new Apfloat("0.5", 100)); assertEquals("2, 100 precision", 100, a.precision(), 1); assertEquals("2, 100 value", new Apfloat("1.414213562373095048801688724209698078569671875376948073176679737990732478462107038850387534327641573"), a, new Apfloat("5e-98")); a = new Apfloat("1.193EA7AAD030A976A4198D55053B7CB5BE1442D9B7E08DF03D97EEEA5149358CAA9782D20CC698505071F733039A8ED5625C15071EA7BCA1CF37D8F11024C66486D094E21E74D0A547DF6", 150, 16); a = ApfloatMath.pow(a, a); assertEquals("3, 150 precision", 150, a.precision(), 1); assertEquals("3, 150 value", new Apfloat("1.1BDD7EF9BE61C2CAB36ED12BED65238AFAC02791331A39420E85923B550F899BC353D7408E2B07B374E294888A03E98DCBF9B55433D064C6D28E005F42ED02FAD35AC14C5E4A2E1F30AD8", Apfloat.DEFAULT, 16), a, ApfloatMath.scale(new Apfloat(5, 1, 16), -148)); a = ApfloatMath.pow(new Apfloat(2), new Apfloat(0)); assertEquals("2^0", new Apfloat(1), a); a = ApfloatMath.pow(new Apfloat(2), new Apfloat(1)); assertEquals("2^1", new Apfloat(2), a); a = ApfloatMath.pow(new Apfloat(0), new Apfloat(2)); assertEquals("0^2", new Apfloat(0), a); a = ApfloatMath.pow(new Apfloat(0), new Apfloat("0.1")); assertEquals("0^0.1", new Apfloat(0), a); a = ApfloatMath.pow(new Apfloat(1), new Apfloat(2)); assertEquals("1^2", new Apfloat(1), a); a = ApfloatMath.pow(new Apfloat("-3.21000"), new Apfloat("-2.00000")); assertEquals("-3.21^-2.00 precision", 6, a.precision()); assertEquals("-3.21^-2.00 value", new Apfloat("0.0970487"), a, new Apfloat("5e-7")); a = ApfloatMath.pow(new Apfloat("-1.000000000000000000000000000010000000000"), new Apfloat("1.000000000000000000000000000000000000000e20")); assertEquals("-1.00000000000000000000000000001^1e20 precision", 20, a.precision()); assertEquals("-1.00000000000000000000000000001^1e20 value", new Apfloat("1.0000000010000000000"), a, new Apfloat("5e-19")); try { ApfloatMath.pow(new Apfloat("1.2"), new Apfloat("57")); } catch (LossOfPrecisionException lope) { // OK } a = ApfloatMath.pow(new Apfloat("1.02"), new Apfloat("57")); assertEquals("1.02^57, precision", 1, a.precision()); a = ApfloatMath.pow(new Apfloat("1.2"), new Apfloat("1.0")); assertEquals("1.2^1.0, precision", 2, a.precision()); a = ApfloatMath.pow(new Apfloat("1.2"), new Apfloat("1")); assertEquals("1.2^1, precision", 1, a.precision()); a = ApfloatMath.pow(new Apfloat("1.02"), new Apfloat("1.00")); assertEquals("1.02^1.00, precision", 3, a.precision()); a = ApfloatMath.pow(new Apfloat("1.02"), new Apfloat("1")); assertEquals("1.02^1, precision", 1, a.precision()); a = ApfloatMath.pow(new Apfloat("1.2"), new Apfloat("0.01")); assertEquals("1.2^0.01, precision", 4, a.precision()); a = ApfloatMath.pow(new Apfloat("1.02"), new Apfloat("0.01")); assertEquals("1.02^0.01, precision", 5, a.precision()); a = ApfloatMath.pow(new Apfloat("12312312342343245234234.4554123", 100), new Apfloat("432.243245234", 100)); assertEquals("12312312342343245234234.4554123^432.243245234, precision", 96, a.precision()); assertEquals("12312312342343245234234.4554123^432.243245234, value", new Apfloat("2.51239266531220414856835532497217396556903456254971203012293241477748612273092084132746823767646e9548"), a, new Apfloat("5e9453")); Apfloat x = new Apfloat("0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687542001481020570685733685520235758130557032670751635075961930727570828371435190307038623891673471123350115364497955239120475172681574932065155524734139525882950453007095326366642654104239157814952043740430385500801944170641671518644712839968171784546957026271631064546150257207402481637773389638550695260668341137273873722928956493547025762652098859693201965058554764703306793654432547632744951250406069438147104689946506220167720424524529612687946546193165174681392672504103802546259656869144192871608293803172714367782654877566485085674077648451464439940461422603193096735402574446070308096085047486638523138181676751438667476647890881437141985494231519973548803751658612753529166100071053558249879414729509293113897155998205654392871700072180857610252368892132449713893203784393530887748259701715591070882368362758984258918535302436342143670611892367891923723146723217205340164925687274778234453534"), y = new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930381964428810975665933446128475648233786783165271201909145648566923460348610454326648213393607260249141273724587006606315588174881520920962829254091715364367892590360011330530548820466521384146951941511609433057270365759591953092186117381932611793105118548074462379962749567351885752724891227938183011949129833673362440656643086021394946395224737190702179860943702770539217176293176752384674818467669405132000568127145263560827785771342757789609173637178721468440901224953430146549585371050792279689258923542019956112129021960864034418159813629774771309960518707211349999998372978049951059731732816096318595024459455346908302642522308253344685035261931188171010003137838752886587533208381420617177669147303598253490428755468731159562863882353787593751957781857780532171226806613001927876611195909216420198"); a = new Apfloat("0.316182943197044690614169268497792885452164361693051710732667324268823185192218337501840769380849175934963329367241486177119992719972036535656516370698214957622438377784029981033223873271141421939813138295037738564766790036552697116686100077566696580000839312315156298008831180831582540185037993133224966864508908869785121857911552089207739673945009998248291357701939332415732827372723670347306280056437522519983428006474751126018076658937443328965140553449786853150070311258642464494464377283951772289329403314138401969945114622833848835745934222479165579350121531744358768058822541639234759395945505389376644705555314322615751906758924387381898831546019383916458560077972932084527603542042873539826316621369800590919207282064653521206479549258209266902697520830020862834814623634525867254396928645227883965555367571830849867301421792625669502862980792359748616959118702882311710152741878652879534809041570410154075983958637237380877034358236840420087080482174290845507248144579739353309032206160873"); for (int prec = 500; prec <= 800; prec += 100) { Apfloat pow = ApfloatMath.pow(x.precision(prec), y.precision(prec)); assertEquals("pow prec " + prec + " precision", prec, pow.precision()); assertEquals("pow prec " + prec + " value", a.precision(prec), pow, new Apfloat("5e-" + prec)); } for (int prec = 900; prec <= 1000; prec++) { Apfloat pow = ApfloatMath.pow(x.precision(prec), y.precision(prec)); // NOTE: EXTRA ALLOWED ERROR NEEDED FOR CASE prec=1000 assertEquals("pow prec " + prec + " precision", prec, pow.precision()); assertEquals("pow prec " + prec + " value", a.precision(prec), pow, new Apfloat("10e-" + prec)); } try { ApfloatMath.pow(new Apfloat(0), new Apfloat(0)); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { ApfloatMath.pow(new Apfloat(0), new Apfloat("-1.0")); fail("0^-1 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { ApfloatMath.pow(new Apfloat(0), new Apfloat("-1.5")); fail("0^-1.5 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { ApfloatMath.pow(new Apfloat(0), new Apfloat("-2.0")); fail("0^-2 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { ApfloatMath.pow(new Apfloat(100, 100), new Apfloat(5000000000000000000L, 100)); fail("Overflow should have occurred"); } catch (OverflowException oe) { // OK; result would overflow } try { ApfloatMath.pow(new Apfloat(-2), new Apfloat("1.3")); fail("pow of negative number accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } try { ApfloatMath.pow(new Apfloat(3), new Apfloat(-1)); fail("pow to infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; can't calculate this to infinite precision } } public static void testAcosh() { Apfloat a = ApfloatMath.acosh(new Apfloat(2, 100)); assertEquals("2, 100 precision", 100, a.precision(), 1); assertEquals("2, 100 value", new Apfloat("1.316957896924816708625046347307968444026981971467516479768472256920460185416443976074219013450101783"), a, new Apfloat("5e-98")); a = ApfloatMath.acosh(new Apfloat("1e5000000", 94)); assertEquals("1e5000000, 100 precision", 100, a.precision(), 1); assertEquals("1e5000000, 100 value", new Apfloat("11512926.158117408980035266690653942496182075518643999240421893625517872541780384370874701631311318488"), a, new Apfloat("5e-91")); a = ApfloatMath.acosh(new Apfloat(1, 100)); assertEquals("1, 100 value", new Apfloat(0), a); try { ApfloatMath.acosh(new Apfloat("0.9")); fail("acosh(0.9) accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } try { ApfloatMath.acosh(new Apfloat("-0.5")); fail("acosh(-0.5) accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } } public static void testAsinh() { Apfloat a = ApfloatMath.asinh(new Apfloat(2, 100)); assertEquals("2, 100 precision", 100, a.precision(), 1); assertEquals("2, 100 value", new Apfloat("1.443635475178810342493276740273105269405553003156981558983054506520491602824665323236028287368170425"), a, new Apfloat("5e-98")); a = ApfloatMath.asinh(new Apfloat(-2, 100)); assertEquals("-2, 100 precision", 100, a.precision(), 1); assertEquals("-2, 100 value", new Apfloat("-1.443635475178810342493276740273105269405553003156981558983054506520491602824665323236028287368170425"), a, new Apfloat("5e-98")); a = ApfloatMath.asinh(new Apfloat("1e5000000", 94)); assertEquals("1e5000000, 100 precision", 100, a.precision(), 1); assertEquals("1e5000000, 100 value", new Apfloat("11512926.158117408980035266690653942496182075518643999240421893625517872541780384370874701631311318488"), a, new Apfloat("5e-91")); a = ApfloatMath.asinh(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(0), a); } public static void testAtanh() { Apfloat a = ApfloatMath.atanh(new Apfloat("0.5", 100)); assertEquals("0.5, 100 precision", 100, a.precision(), 1); assertEquals("0.5, 100 value", new Apfloat("0.5493061443340548456976226184612628523237452789113747258673471668187471466093044834368078774068660444"), a, new Apfloat("5e-99")); a = ApfloatMath.atanh(new Apfloat("-0.5", 100)); assertEquals("-0.5, 100 precision", 100, a.precision(), 1); assertEquals("-0.5, 100 value", new Apfloat("-0.5493061443340548456976226184612628523237452789113747258673471668187471466093044834368078774068660444"), a, new Apfloat("5e-99")); a = ApfloatMath.atanh(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(0), a); try { ApfloatMath.atanh(new Apfloat("1")); fail("atanh(1) accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } try { ApfloatMath.atanh(new Apfloat("-1")); fail("atanh(-1) accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } public static void testCosh() { Apfloat a = ApfloatMath.cosh(new Apfloat(2, 100)); assertEquals("2, 100 precision", 100, a.precision(), 1); assertEquals("2, 100 value", new Apfloat("3.7621956910836314595622134777737461082939735582307116027776433475883235850902727266607053037848894217"), a, new Apfloat("5e-98")); a = ApfloatMath.cosh(new Apfloat(-2, 100)); assertEquals("-2, 100 precision", 100, a.precision(), 1); assertEquals("-2, 100 value", new Apfloat("3.7621956910836314595622134777737461082939735582307116027776433475883235850902727266607053037848894217"), a, new Apfloat("5e-98")); a = ApfloatMath.cosh(new Apfloat(5000000, 106)); assertEquals("5000000, 100 precision", 100, a.precision(), 1); assertEquals("5000000, 100 value", new Apfloat("1.283767164891909000250266514854966058747279149558630398210789892301655994767618939807113812532354085e2171472"), a, new Apfloat("5e2171372")); a = ApfloatMath.cosh(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(1), a); } public static void testSinh() { Apfloat a = ApfloatMath.sinh(new Apfloat(2, 100)); assertEquals("2, 100 precision", 100, a.precision(), 1); assertEquals("2, 100 value", new Apfloat("3.626860407847018767668213982801261704886342012321135721309484474934250210988785036723607181294232373"), a, new Apfloat("5e-98")); a = ApfloatMath.sinh(new Apfloat(-2, 100)); assertEquals("-2, 100 precision", 100, a.precision(), 1); assertEquals("-2, 100 value", new Apfloat("-3.626860407847018767668213982801261704886342012321135721309484474934250210988785036723607181294232373"), a, new Apfloat("5e-98")); a = ApfloatMath.sinh(new Apfloat(5000000, 106)); assertEquals("5000000, 100 precision", 100, a.precision(), 1); assertEquals("5000000, 100 value", new Apfloat("1.283767164891909000250266514854966058747279149558630398210789892301655994767618939807113812532354085e2171472"), a, new Apfloat("5e2171372")); a = ApfloatMath.sinh(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(0), a); } public static void testTanh() { Apfloat a = ApfloatMath.tanh(new Apfloat(2, 100)); assertEquals("2, 100 precision", 100, a.precision(), 1); assertEquals("2, 100 value", new Apfloat("0.96402758007581688394641372410092315025502997624093477604826321741310794631761020255947485004520768915"), a, new Apfloat("5e-99")); a = ApfloatMath.tanh(new Apfloat(-2, 100)); assertEquals("-2, 100 precision", 100, a.precision(), 1); assertEquals("-2, 100 value", new Apfloat("-0.96402758007581688394641372410092315025502997624093477604826321741310794631761020255947485004520768915"), a, new Apfloat("5e-99")); a = ApfloatMath.tanh(new Apfloat(5000000, 100)); assertEquals("5000000, 100 precision", 4343037, a.precision(), 1); assertEquals("5000000, 100 value", new Apfloat(1).subtract(new Apfloat("3.03387356179746871517892756452203249280217116298171287391802587502345779082540217305405121824e-4342945")), a, new Apfloat("5e-4343037")); a = ApfloatMath.tanh(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(0), a); } public static void testAcos() { Apfloat a = ApfloatMath.acos(new Apfloat("0.5", 100)); assertEquals("0.5, 100 precision", 100, a.precision(), 1); assertEquals("0.5, 100 value", new Apfloat("1.04719755119659774615421446109316762806572313312503527365831486410260546876206966620934494178070569"), a, new Apfloat("5e-98")); a = ApfloatMath.acos(new Apfloat("-0.5", 100)); assertEquals("-0.5, 100 precision", 100, a.precision(), 1); assertEquals("-0.5, 100 value", new Apfloat("2.09439510239319549230842892218633525613144626625007054731662972820521093752413933241868988356141138"), a, new Apfloat("5e-98")); a = ApfloatMath.acos(new Apfloat("1e-100")); assertEquals("0, 100 precision", 100, a.precision(), 1); assertEquals("0, 100 value", new Apfloat("1.57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105853"), a, new Apfloat("5e-98")); a = ApfloatMath.acos(new Apfloat(1, 100)); assertEquals("1, 100 value", new Apfloat(0), a); try { ApfloatMath.acos(new Apfloat(0)); fail("acos(0) accepted"); } catch (InfiniteExpansionException iee) { // OK; result would have infinite precision } try { ApfloatMath.acos(new Apfloat("1.1")); fail("acos(1.1) accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } } public static void testAsin() { Apfloat a = ApfloatMath.asin(new Apfloat("0.5", 100)); assertEquals("0.5, 100 precision", 100, a.precision(), 1); assertEquals("0.5, 100 value", new Apfloat("0.5235987755982988730771072305465838140328615665625176368291574320513027343810348331046724708903528447"), a, new Apfloat("5e-99")); a = ApfloatMath.asin(new Apfloat("-0.5", 100)); assertEquals("-0.5, 100 precision", 100, a.precision(), 1); assertEquals("-0.5, 100 value", new Apfloat("-0.5235987755982988730771072305465838140328615665625176368291574320513027343810348331046724708903528447"), a, new Apfloat("5e-99")); a = ApfloatMath.asin(new Apfloat("0.00001", 100)); assertEquals("0.00001, 100 precision", 100, a.precision(), 1); assertEquals("0.00001, 100 value", new Apfloat("0.00001000000000016666666667416666666711309523812562003968477689844894697641769350752329383472276925426623"), a, new Apfloat("5e-103")); a = ApfloatMath.asin(new Apfloat(1, 100)); assertEquals("1, 100 precision", 100, a.precision(), 1); assertEquals("1, 100 value", new Apfloat("1.57079632679489661923132169163975144209858469968755291048747229615390820314310449931401741267105853"), a, new Apfloat("5e-98")); a = ApfloatMath.asin(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(0), a); try { ApfloatMath.asin(new Apfloat("1.1")); fail("asin(1.1) accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } } public static void testAtan() { Apfloat a = ApfloatMath.atan(new Apfloat("0.5", 100)); assertEquals("0.5, 100 precision", 100, a.precision(), 1); assertEquals("0.5, 100 value", new Apfloat("0.4636476090008061162142562314612144020285370542861202638109330887201978641657417053006002839848878926"), a, new Apfloat("5e-99")); a = ApfloatMath.atan(new Apfloat("-0.5", 100)); assertEquals("-0.5, 100 precision", 100, a.precision(), 1); assertEquals("-0.5, 100 value", new Apfloat("-0.4636476090008061162142562314612144020285370542861202638109330887201978641657417053006002839848878926"), a, new Apfloat("5e-99")); a = ApfloatMath.atan(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(0), a); } public static void testAtan2() { Apfloat a = ApfloatMath.atan2(new Apfloat(0), new Apfloat(2, 20)); assertEquals("0,2 value", new Apfloat(0), a); a = ApfloatMath.atan2(new Apfloat(2, 20), new Apfloat(2, 20)); assertEquals("2,2 precision", 20, a.precision(), 1); assertEquals("2,2 value", new Apfloat("0.78539816339744830962"), a, new Apfloat("5e-20")); a = ApfloatMath.atan2(new Apfloat(2, 20), new Apfloat(0)); assertEquals("2,0 precision", 20, a.precision()); assertEquals("2,0 value", new Apfloat("1.5707963267948966192"), a, new Apfloat("5e-19")); a = ApfloatMath.atan2(new Apfloat(2, 20), new Apfloat(-2, 20)); assertEquals("2,-2 precision", 20, a.precision(), 1); assertEquals("2,-2 value", new Apfloat("2.3561944901923449288"), a, new Apfloat("5e-19")); a = ApfloatMath.atan2(new Apfloat(0), new Apfloat(-2, 20)); assertEquals("0,-2 precision", 20, a.precision()); assertEquals("0,-2 value", new Apfloat("3.1415926535897932385"), a, new Apfloat("5e-19")); a = ApfloatMath.atan2(new Apfloat(-2, 20), new Apfloat(2, 20)); assertEquals("-2,2 precision", 20, a.precision(), 1); assertEquals("-2,2 value", new Apfloat("-0.78539816339744830962"), a, new Apfloat("5e-20")); a = ApfloatMath.atan2(new Apfloat(-2, 20), new Apfloat(0)); assertEquals("-2,0 precision", 20, a.precision(), 1); assertEquals("-2,0 value", new Apfloat("-1.5707963267948966192"), a, new Apfloat("5e-19")); a = ApfloatMath.atan2(new Apfloat(-2, 20), new Apfloat(-2, 20)); assertEquals("-2,-2 precision", 20, a.precision(), 1); assertEquals("-2,-2 value", new Apfloat("-2.3561944901923449288"), a, new Apfloat("5e-19")); a = ApfloatMath.atan2(new Apfloat(2, 20), new Apfloat(3, 20)); assertEquals("2,3 precision", 20, a.precision(), 1); assertEquals("2,3 value", new Apfloat("0.58800260354756755125"), a, new Apfloat("5e-20")); a = ApfloatMath.atan2(new Apfloat("6.618533197939224e-13"), new Apfloat("0.9999999966650702")); assertEquals("6.618533197939224e-13,0.9999999966650702 precision", 16, a.precision(), 1); assertEquals("6.618533197939224e-13,0.9999999966650702 value", new Apfloat("6.61853322001157e-13"), a, new Apfloat("5e-27")); a = ApfloatMath.atan2(new Apfloat("-6.618533197939224e-13"), new Apfloat("0.9999999966650702")); assertEquals("-6.618533197939224e-13,0.9999999966650702 precision", 16, a.precision(), 1); assertEquals("-6.618533197939224e-13,0.9999999966650702 value", new Apfloat("-6.61853322001157e-13"), a, new Apfloat("5e-27")); a = ApfloatMath.atan2(new Apfloat(0, 1, 12), new Apfloat(2, 20, 12)); assertEquals("0,2 radix", 12, a.radix()); try { ApfloatMath.atan2(new Apfloat(0), new Apfloat(0)); fail("atan2(0,0) accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { ApfloatMath.atan2(new Apfloat(2), new Apfloat(3)); fail("atan2 to infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; result would have infinite precision } } public static void testCos() { Apfloat a = ApfloatMath.cos(new Apfloat(1, 100)); assertEquals("1, 100 precision", 100, a.precision(), 1); assertEquals("1, 100 value", new Apfloat("0.5403023058681397174009366074429766037323104206179222276700972553811003947744717645179518560871830893"), a, new Apfloat("5e-99")); a = ApfloatMath.cos(new Apfloat(-1, 100)); assertEquals("-1, 100 precision", 100, a.precision(), 1); assertEquals("-1, 100 value", new Apfloat("0.5403023058681397174009366074429766037323104206179222276700972553811003947744717645179518560871830893"), a, new Apfloat("5e-99")); a = ApfloatMath.cos(new Apfloat("3141592653589793239.462643383")); assertEquals("1e18pi + 1 precision", 10, a.precision(), 1); assertEquals("1e18pi + 1 value", new Apfloat("0.5403023058"), a, new Apfloat("5e-10")); a = ApfloatMath.cos(new Apfloat("1e-10", 32)); assertEquals("1e-10 prec 32 value", new Apfloat("0.99999999999999999999500000000000"), a, new Apfloat("5e-32")); a = ApfloatMath.cos(new Apfloat("1e-10", 3)); assertEquals("1e-10 prec 3 value", new Apfloat("0.99999999999999999999500"), a, new Apfloat("5e-23")); a = ApfloatMath.cos(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(1), a); try { ApfloatMath.cos(new Apfloat(1000, 3)); fail("cos(1000 prec 3) accepted"); } catch (LossOfPrecisionException lope) { // OK; loss of precision } } public static void testSin() { Apfloat a = ApfloatMath.sin(new Apfloat(1, 100)); assertEquals("1, 100 precision", 100, a.precision(), 1); assertEquals("1, 100 value", new Apfloat("0.8414709848078965066525023216302989996225630607983710656727517099919104043912396689486397435430526959"), a, new Apfloat("5e-99")); a = ApfloatMath.sin(new Apfloat(-1, 100)); assertEquals("-1, 100 precision", 100, a.precision(), 1); assertEquals("-1, 100 value", new Apfloat("-0.8414709848078965066525023216302989996225630607983710656727517099919104043912396689486397435430526959"), a, new Apfloat("5e-99")); a = ApfloatMath.sin(new Apfloat("3141592653589793239.462643383")); assertEquals("1e18pi + 1 precision", 10, a.precision(), 1); assertEquals("1e18pi + 1 value", new Apfloat("0.8414709848"), a, new Apfloat("5e-10")); a = ApfloatMath.sin(new Apfloat("1e-10", 32)); assertEquals("1e-10 prec 32 value", new Apfloat("0.99999999999999999999833333333333e-10"), a, new Apfloat("5e-42")); a = ApfloatMath.sin(new Apfloat("1e-10", 3)); assertEquals("1e-10 prec 3 value", new Apfloat("0.99999999999999999999833e-10"), a, new Apfloat("5e-33")); a = ApfloatMath.sin(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(0), a); try { ApfloatMath.sin(new Apfloat(1000, 3)); fail("sin(1000 prec 3) accepted"); } catch (LossOfPrecisionException lope) { // OK; loss of precision } } public static void testTan() { Apfloat a = ApfloatMath.tan(new Apfloat(1, 100)); assertEquals("1, 100 precision", 100, a.precision(), 1); assertEquals("1, 100 value", new Apfloat("1.55740772465490223050697480745836017308725077238152003838394660569886139715172728955509996520224298"), a, new Apfloat("5e-98")); a = ApfloatMath.tan(new Apfloat(-1, 100)); assertEquals("-1, 100 precision", 100, a.precision(), 1); assertEquals("-1, 100 value", new Apfloat("-1.55740772465490223050697480745836017308725077238152003838394660569886139715172728955509996520224298"), a, new Apfloat("5e-98")); a = ApfloatMath.tan(new Apfloat(0)); assertEquals("0, 100 value", new Apfloat(0), a); try { ApfloatMath.tan(new Apfloat(1000, 3)); fail("tan(1000 prec 3) accepted"); } catch (LossOfPrecisionException lope) { // OK; loss of precision } } public static void testSinc() { Apfloat a = ApfloatMath.sinc(new Apfloat(4, 20)); assertEquals("4 precision", 20, a.precision()); assertEquals("4 value", new Apfloat("-0.18920062382698206284"), a, new Apfloat("5e-20")); a = ApfloatMath.sinc(new Apfloat("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apint(1), a); a = ApfloatMath.sinc(new Apint(0, 2)); assertEquals("0 radix 2 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 radix 2 radix", 2, a.radix()); assertEquals("0 radix 2 value", new Apint(1, 2), a); } public static void testW() { Apfloat a = new Apfloat(3, 55, 7); Apfloat w = ApfloatMath.w(a); assertEquals("value", new Apfloat("1.023055505635040031000066002051603260046346014422202623", 55, 7), w, new Apfloat("5e-54", 1, 7)); assertEquals("radix", 7, w.radix()); assertEquals("precision", 55, w.precision()); } public static void testToRadians() { Apfloat a = ApfloatMath.toRadians(new Apfloat(180, 100)); assertEquals("180 precision", 100, a.precision()); assertEquals("180 value", new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068"), a, new Apfloat("5e-99")); a = ApfloatMath.toRadians(new Apfloat(90, 50, 16)); assertEquals("90 precision", 50, a.precision()); assertEquals("90 value", new Apfloat("1.921fb54442d18469898cc51701b839a252049c1114cf98e80", 50, 16), a, new Apfloat(8, 1, 16).scale(-49)); a = ApfloatMath.toRadians(new Apfloat(0)); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apfloat(0), a); } public static void testToDegrees() { Apfloat a = ApfloatMath.toDegrees(ApfloatMath.pi(100, 10)); assertEquals("180 precision", 100, a.precision()); assertEquals("180 value", new Apfloat(180), a, new Apfloat("5e-97")); a = ApfloatMath.toDegrees(ApfloatMath.pi(50, 16).divide(new Apfloat(2, 50, 16))); assertEquals("90 precision", 50, a.precision()); assertEquals("90 value", new Apfloat(90, 50, 16), a, new Apfloat(8, 1, 16).scale(-48)); a = ApfloatMath.toDegrees(new Apfloat(0)); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apfloat(0), a); } public static void testProduct() { Apfloat a = ApfloatMath.product(new Apfloat(2, 5), new Apfloat(3, 2)); assertEquals("5-2 precision", 2, a.precision()); assertEquals("5-2 value", new Apfloat(6), a); a = ApfloatMath.product(new Apfloat(2), new Apfloat(3, 5), new Apfloat(4, 8)); assertEquals("MAX-5-8 precision", 5, a.precision()); assertEquals("MAX-5-8 value", new Apfloat(24), a); a = ApfloatMath.product(Apfloat.ZERO, new Apfloat(12345)); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apfloat(0), a); a = ApfloatMath.product(new Apfloat(0, 1, 12)); assertEquals("0 radix", 12, a.radix()); a = ApfloatMath.product(new Apfloat("1"), new Apfloat("2.50000000000000000000000000000000000000000000000000000000000000000000001"), new Apfloat("2.0000000000000000000000000000000000001"), new Apfloat(2)); assertEquals("Many precision", 1, a.precision()); assertEquals("Many value", new Apfloat(10), a); Apfloat[] x = new Apfloat[] { new Apfloat(1000000000000L), new Apfloat(1) }; ApfloatMath.product(x); assertEquals("Array product 1 [0]", new Apfloat(1000000000000L), x[0]); assertEquals("Array product 1 [1]", new Apfloat(1), x[1]); x = new Apfloat[] { new Apfloat(1), new Apfloat(1000000000000L) }; ApfloatMath.product(x); assertEquals("Array product 2 [0]", new Apfloat(1), x[0]); assertEquals("Array product 2 [1]", new Apfloat(1000000000000L), x[1]); assertEquals("Empty product", new Apfloat("1"), ApfloatMath.product()); Apfloat[] numbers = new Apfloat[100000]; for (int i = 0; i < numbers.length; i++) { numbers[i] = new Apfloat(i + 1); } Apfloat factorial = ApintMath.factorial(numbers.length); assertEquals("Factorial", factorial, ApfloatMath.product(numbers)); numbers[0] = factorial; assertEquals("Factorial squared", factorial.multiply(factorial), ApfloatMath.product(numbers)); } public static void testSum() { Apfloat a = ApfloatMath.sum(new Apfloat(12345000, 5), new Apfloat(12345, 5)); assertEquals("5-2 precision", 5, a.precision()); assertEquals("5-2 value", new Apfloat(12357000), a); a = ApfloatMath.sum(new Apfloat(12345678, 10), new Apfloat(12345, 5)); assertEquals("8-5 precision", 8, a.precision()); assertEquals("8-5 value", new Apfloat(12358023), a); a = ApfloatMath.sum(new Apfloat(0), new Apfloat(12345, 5)); assertEquals("0-0 precision", 5, a.precision()); assertEquals("0-0 value", new Apfloat(12345), a); a = ApfloatMath.sum(new Apfloat(12345678, 6), new Apfloat(12, 2)); assertEquals("6-0 precision", 6, a.precision()); assertEquals("6-0 value", new Apfloat(12345600), a); a = ApfloatMath.sum(new Apfloat(12345678, 5), new Apfloat(12, 2)); assertEquals("5-0 precision", 5, a.precision()); assertEquals("5-0 value", new Apfloat(12345000), a); a = ApfloatMath.sum(new Apfloat(10), new Apfloat(100, 2)); assertEquals("10, 100 2 precision", 2, a.precision()); assertEquals("10, 100 2 value", new Apfloat(110), a); a = ApfloatMath.sum(new Apfloat(10), new Apfloat(100, 3)); assertEquals("10, 100 3 precision", 3, a.precision()); assertEquals("10, 100 3 value", new Apfloat(110), a); a = ApfloatMath.sum(new Apfloat(100, 2), new Apfloat(10)); assertEquals("100, 10 2 precision", 2, a.precision()); assertEquals("100, 10 2 value", new Apfloat(110), a); a = ApfloatMath.sum(new Apfloat(10), new Apfloat(1, 2)); assertEquals("10, 1 2 precision", 3, a.precision()); assertEquals("10, 1 2 value", new Apfloat(11), a); a = ApfloatMath.sum(new Apfloat(10), new Apfloat(1, 3)); assertEquals("10, 1 3 precision", 4, a.precision()); assertEquals("10, 1 3 value", new Apfloat(11), a); a = ApfloatMath.sum(new Apfloat(1, 2), new Apfloat(10)); assertEquals("1, 10 2 precision", 3, a.precision()); assertEquals("1, 10 2 value", new Apfloat(11), a); a = ApfloatMath.sum(new Apfloat(10), new Apfloat(10)); assertEquals("10, 10 MAX precision", Apfloat.INFINITE, a.precision()); assertEquals("10, 10 MAX value", new Apfloat(20), a); a = ApfloatMath.sum(new Apfloat(10), new Apfloat(100)); assertEquals("10, 100 MAX precision", Apfloat.INFINITE, a.precision()); assertEquals("10, 100 MAX value", new Apfloat(110), a); a = ApfloatMath.sum(new Apfloat(50, 2), new Apfloat(50, 2)); assertEquals("50, 50 2 precision", 3, a.precision()); assertEquals("50, 50 2 value", new Apfloat(100), a); a = ApfloatMath.sum(new Apfloat("2")); assertEquals("2 precision", 1, a.precision()); assertEquals("2 value", new Apfloat(2), a); a = ApfloatMath.sum(new Apfloat("1"), new Apfloat("3333333.33"), new Apfloat("2.2"), new Apfloat("444444444400000000000000000000000000"), new Apfloat("6666.6"), new Apfloat("555"), new Apfloat(7)); assertEquals("Many precision", 36, a.precision()); assertEquals("Many value", new Apfloat("444444444400000000000000000003340564"), a); Apfloat[] x = new Apfloat[] { new Apfloat(1000000000000L), new Apfloat(1) }; ApfloatMath.sum(x); assertEquals("Array sum 1 [0]", new Apfloat(1000000000000L), x[0]); assertEquals("Array sum 1 [1]", new Apfloat(1), x[1]); x = new Apfloat[] { new Apfloat(1), new Apfloat(1000000000000L) }; ApfloatMath.sum(x); assertEquals("Array sum 2 [0]", new Apfloat(1), x[0]); assertEquals("Array sum 2 [1]", new Apfloat(1000000000000L), x[1]); assertEquals("Empty sum", new Apcomplex("0"), ApfloatMath.sum()); Apfloat[] numbers = new Apfloat[100000]; for (int i = 0; i < numbers.length; i++) { numbers[i] = new Apfloat(i + 1); } assertEquals("Big sum", new Apfloat(5000050000L), ApfloatMath.sum(numbers)); numbers[0] = numbers[0].add(new Apfloat("1e10000000", Apfloat.INFINITE)); assertEquals("Big number big sum", new Apfloat(5000050000L).add(new Apfloat("1e10000000", Apfloat.INFINITE)), ApfloatMath.sum(numbers)); } public static void testE() { Apfloat a = ApfloatMath.e(10); assertEquals("10 radix", 10, a.radix()); assertEquals("10 precision", 10, a.precision()); assertEquals("10 value", new Apfloat("2.718281828"), a, new Apfloat("5e-9")); a = ApfloatMath.e(50); assertEquals("50 radix", 10, a.radix()); assertEquals("50 precision", 50, a.precision()); assertEquals("50 value", new Apfloat("2.7182818284590452353602874713526624977572470937000"), a, new Apfloat("5e-49")); a = ApfloatMath.e(20, 16); assertEquals("20 radix", 16, a.radix()); assertEquals("20 precision", 20, a.precision()); assertEquals("20 value", new Apfloat("2.b7e151628aed2a6abf7", 20, 16), a, new Apfloat("0.0000000000000000008", 1, 16)); try { ApfloatMath.e(0); fail("Precision 0 accepted"); } catch (IllegalArgumentException e) { // OK; invalid precision } try { ApfloatMath.e(Apfloat.INFINITE); fail("Infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; invalid precision } try { ApfloatMath.e(50, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testEuler() { Apfloat a = ApfloatMath.euler(10); assertEquals("10 radix", 10, a.radix()); assertEquals("10 precision", 10, a.precision()); assertEquals("10 value", new Apfloat("0.5772156649"), a, new Apfloat("5e-10")); a = ApfloatMath.euler(50); assertEquals("50 radix", 10, a.radix()); assertEquals("50 precision", 50, a.precision()); assertEquals("50 value", new Apfloat("0.57721566490153286060651209008240243104215933593992"), a, new Apfloat("5e-50")); a = ApfloatMath.euler(20, 16); assertEquals("20 radix", 16, a.radix()); assertEquals("20 precision", 20, a.precision()); assertEquals("20 value", new Apfloat("0.93c467e37db0c7a4d1be", 20, 16), a, new Apfloat("0.00000000000000000008", 1, 16)); a = ApfloatMath.eulerSmall(2000, 10); assertEquals("long and short match", EulerHelper.euler(2000, 10), a); a = ApfloatMath.euler(2500, 10); assertEquals("short and long match", ApfloatMath.eulerSmall(2500, 10), a); for (int radix = 2; radix <= 36; radix++) { a = ApfloatMath.eulerSmall(20, radix); assertEquals("long and short match radix " + radix + " precision 20", EulerHelper.euler(20, radix), a); a = ApfloatMath.eulerSmall(200, radix); assertEquals("long and short match radix " + radix + " precision 200", EulerHelper.euler(200, radix), a); } try { ApfloatMath.euler(0); fail("Precision 0 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.euler(-1); fail("Precision -1 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.euler(Apfloat.INFINITE); fail("Infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; invalid precision } try { ApfloatMath.euler(50, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testCatalan() { Apfloat a = ApfloatMath.catalan(10); assertEquals("10 radix", 10, a.radix()); assertEquals("10 precision", 10, a.precision()); assertEquals("10 value", new Apfloat("0.9159655942"), a, new Apfloat("5e-10")); a = ApfloatMath.catalan(50); assertEquals("50 radix", 10, a.radix()); assertEquals("50 precision", 50, a.precision()); assertEquals("50 value", new Apfloat("0.91596559417721901505460351493238411077414937428167"), a, new Apfloat("5e-50")); a = ApfloatMath.catalan(20, 16); assertEquals("20 radix", 16, a.radix()); assertEquals("20 precision", 20, a.precision()); assertEquals("20 value", new Apfloat("0.ea7cb89f409ae8452158", 20, 16), a, new Apfloat("0.00000000000000000008", 1, 16)); try { ApfloatMath.catalan(0); fail("Precision 0 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.catalan(-1); fail("Precision -1 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.catalan(Apfloat.INFINITE); fail("Infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; invalid precision } try { ApfloatMath.catalan(50, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testGlaisher() { Apfloat a = ApfloatMath.glaisher(10); assertEquals("10 radix", 10, a.radix()); assertEquals("10 precision", 10, a.precision()); assertEquals("10 value", new Apfloat("1.282427129"), a, new Apfloat("5e-9")); a = ApfloatMath.glaisher(50); assertEquals("50 radix", 10, a.radix()); assertEquals("50 precision", 50, a.precision()); assertEquals("50 value", new Apfloat("1.2824271291006226368753425688697917277676889273250"), a, new Apfloat("5e-49")); a = ApfloatMath.glaisher(20, 16); assertEquals("20 radix", 16, a.radix()); assertEquals("20 precision", 20, a.precision()); assertEquals("20 value", new Apfloat("1.484d24f2fd8731313ed", 20, 16), a, new Apfloat("0.0000000000000000008", 1, 16)); try { ApfloatMath.glaisher(0); fail("Precision 0 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.glaisher(-1); fail("Precision -1 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.glaisher(Apfloat.INFINITE); fail("Infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; invalid precision } try { ApfloatMath.glaisher(50, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testKhinchin() { Apfloat a = ApfloatMath.khinchin(10); assertEquals("10 radix", 10, a.radix()); assertEquals("10 precision", 10, a.precision()); assertEquals("10 value", new Apfloat("2.685452001"), a, new Apfloat("5e-9")); a = ApfloatMath.khinchin(50); assertEquals("50 radix", 10, a.radix()); assertEquals("50 precision", 50, a.precision()); assertEquals("50 value", new Apfloat("2.6854520010653064453097148354817956938203822939945"), a, new Apfloat("5e-49")); a = ApfloatMath.khinchin(20, 16); assertEquals("20 radix", 16, a.radix()); assertEquals("20 precision", 20, a.precision()); assertEquals("20 value", new Apfloat("2.af79c8478da1aef2fdf", 20, 16), a, new Apfloat("0.0000000000000000008", 1, 16)); try { ApfloatMath.khinchin(0); fail("Precision 0 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.khinchin(-1); fail("Precision -1 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { ApfloatMath.khinchin(Apfloat.INFINITE); fail("Infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; invalid precision } try { ApfloatMath.khinchin(50, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testGamma() { Apfloat a = ApfloatMath.gamma(new Apfloat("0.50000000")); assertEquals("0.5 precision", 8, a.precision()); assertEquals("0.5 value", new Apfloat("1.7724539"), a, new Apfloat("5e-7")); a = ApfloatMath.gamma(new Apfloat("-0.50000000")); assertEquals("-0.5 precision", 8, a.precision()); assertEquals("-0.5 value", new Apfloat("-3.5449077"), a, new Apfloat("5e-7")); a = ApfloatMath.gamma(new Apfloat(1, 8, 5)); assertEquals("1 precision", 8, a.precision()); assertEquals("1 radix", 5, a.radix()); assertEquals("1 value", new Apfloat("1"), a); a = ApfloatMath.gamma(new Apfloat(2, 100, 15)); assertEquals("2 precision", 100, a.precision()); assertEquals("2 radix", 15, a.radix()); assertEquals("2 value", new Apfloat("1"), a); a = ApfloatMath.gamma(new Apfloat("3.0000")); assertEquals("3 precision", 5, a.precision()); assertEquals("3 value", new Apfloat("2"), a); a = ApfloatMath.gamma(new Apfloat(4)); assertEquals("4 precision", Apfloat.INFINITE, a.precision()); assertEquals("4 value", new Apfloat(6), a); a = ApfloatMath.gamma(new Apfloat("1.6", 50, 12)); assertEquals("1.5 precision", 50, a.precision()); assertEquals("1.5 radix", 12, a.radix()); assertEquals("1.5 value", new Apfloat("0.a77497505445a57663a7a6a27293557aa7636b52055b106267", 50, 12), a, new Apfloat("6e-50", 1, 12)); a = ApfloatMath.gamma(new Apfloat("100.1", 200)); assertEquals("100.1 precision", 198, a.precision()); assertEquals("100.1 radix", 10, a.radix()); assertEquals("100.1 value", new Apfloat("1.47845449465151367987473964370058459815616330531263071222863411464877072133812707322505189203455965790627278052589675722784367103797434916544534856714784021130076746063941341581673323445817944799010e156"), a, new Apfloat("5e-41")); a = ApfloatMath.gamma(new Apfloat("1000000000000.1", 200)); assertEquals("1000000000000.1 precision", 187, a.precision()); assertEquals("1000000000000.1 radix", 10, a.radix()); assertEquals("1000000000000.1 value", new Apfloat("2.224653017598333183967851025493808141494831993379408189875623062445371016679508334427856798243992091090588534116479723793172610167211719300756575577203942719906409747242019348186775610123e11565705518092"), a, new Apfloat("5e11565705517906")); a = ApfloatMath.gamma(new Apfloat("1000000000000.1", 40)); assertEquals("1000000000000.1 precision", 27, a.precision()); assertEquals("1000000000000.1 radix", 10, a.radix()); assertEquals("1000000000000.1 value", new Apfloat("2.22465301759833318396785103e11565705518092"), a, new Apfloat("5e11565705518066")); a = ApfloatMath.gamma(new Apfloat("1.110100011010100101001010001000000000000000110011001100110011001100110011001100110011001100110011001100110011001100110011001100110011e39", 133, 2)); assertEquals("1000000000000.1 radix 2 precision", 88, a.precision()); assertEquals("1000000000000.1 radix 2 radix", 2, a.radix()); assertEquals("1000000000000.1 radix 2 value", new Apfloat("1.101100110001111000000001111011100111100110011010110000111001101101000111111101101001101e38420442097744", Apfloat.DEFAULT, 2), a, new Apfloat("1e38420442097657", 1, 2)); a = ApfloatMath.gamma(new Apfloat("cre66i9s.3lllllllllllllllm", 25, 36)); assertEquals("1000000000000.1 radix 36 precision", 17, a.precision()); assertEquals("1000000000000.1 radix 36 radix", 36, a.radix()); assertEquals("1000000000000.1 radix 36 value", ApfloatMath.scale(new Apfloat("3.nbkxpiq7zeevaryz", Apfloat.DEFAULT, 36), 7431527940352L), a, ApfloatMath.scale(new Apfloat("h", 1, 36), 7431527940336L)); a = ApfloatMath.gamma(new Apfloat("100000000000000000.1", 100)); assertEquals("100000000000000000.1 precision", 82, a.precision()); assertEquals("100000000000000000.1 radix", 10, a.radix()); assertEquals("100000000000000000.1 value", new Apfloat("6.823026252477337409854801263715027688793307758143854258250527972341074891269582940e1656570551809674810"), a, new Apfloat("5e1656570551809674729")); try { ApfloatMath.gamma(new Apfloat("0")); fail("Gamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.gamma(new Apfloat("-1")); fail("Gamma of -1"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.gamma(new Apfloat("1e100", 100)); fail("Gamma overflow"); } catch (OverflowException are) { // OK } try { ApfloatMath.gamma(new Apfloat("4.5", Apfloat.INFINITE)); fail("Gamma infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testGammaIncomplete() { Apfloat a = ApfloatMath.gamma(new Apfloat("2.0000000"), new Apfloat("1.0000000")); assertEquals("2,1 precision", 8, a.precision()); assertEquals("2,1 value", new Apfloat("0.73575888"), a, new Apfloat("5e-8")); a = ApfloatMath.gamma(new Apfloat("4.0000000"), new Apfloat("6.0000000")); assertEquals("4,6 precision", 8, a.precision()); assertEquals("4,6 value", new Apfloat("0.90722330"), a, new Apfloat("5e-8")); a = ApfloatMath.gamma(new Apfloat("4.50000"), new Apfloat("6.50000")); assertEquals("4.5,6.5 precision", 6, a.precision()); assertEquals("4.5,6.5 value", new Apfloat("1.89139"), a, new Apfloat("5e-5")); a = ApfloatMath.gamma(new Apfloat("-0.500000"), new Apfloat("0.500000")); assertEquals("-0.5,0.5 precision", 6, a.precision()); assertEquals("-0.5,0.5 value", new Apfloat("0.590691"), a, new Apfloat("5e-6")); a = ApfloatMath.gamma(new Apfloat(1, 10), new Apfloat(-1, 10)); assertEquals("1,-1 precision", 10, a.precision()); assertEquals("1,-1 value", new Apfloat("2.718281828"), a, new Apfloat("5e-9")); a = ApfloatMath.gamma(new Apfloat(100, 10), new Apfloat(1, 10)); assertEquals("100,1 precision", 10, a.precision()); assertEquals("100,1 value", new Apfloat("9.332621544e155"), a, new Apfloat("5e-146")); a = ApfloatMath.gamma(new Apfloat("-100.5", 12), new Apfloat(1, 12)); assertEquals("-100.5,1 precision", 12, a.precision()); assertEquals("-100.5,1 value", new Apfloat("0.00362407278773"), a, new Apfloat("5e-14")); a = ApfloatMath.gamma(new Apfloat(-1, 10), new Apfloat(1, 10)); assertEquals("-1,1 precision", 10, a.precision()); assertEquals("-1,1 value", new Apfloat("0.1484955068"), a, new Apfloat("5e-10")); a = ApfloatMath.gamma(new Apfloat(-1, 10), new Apfloat(10, 10)); assertEquals("-1,10 precision", 9, a.precision()); assertEquals("-1,10 value", new Apfloat("3.830240466e-7"), a, new Apfloat("5e-16")); a = ApfloatMath.gamma(new Apfloat(-10, 10), new Apfloat(1, 10)); assertEquals("-10,1 precision", 10, a.precision()); assertEquals("-10,1 value", new Apfloat("0.03314854471"), a, new Apfloat("5e-11")); a = ApfloatMath.gamma(new Apfloat(-10, 10), new Apfloat(10, 10)); assertEquals("-10,10 precision", 9, a.precision()); assertEquals("-10,10 value", new Apfloat("2.214690319e-16"), a, new Apfloat("5e-24")); a = ApfloatMath.gamma(new Apfloat(4, 10), new Apfloat("0.1", 10)); assertEquals("4,0.1 precision", 10, a.precision()); assertEquals("4,0.1 value", new Apfloat("5.999976919"), a, new Apfloat("5e-9")); a = ApfloatMath.gamma(new Apfloat(4, 10), new Apfloat("-0.1", 10)); assertEquals("4,-0.1 precision", 10, a.precision()); assertEquals("4,-0.1 value", new Apfloat("5.999972914"), a, new Apfloat("5e-9")); a = ApfloatMath.gamma(new Apfloat("-1.000e-50"), new Apfloat("100.0")); assertEquals("-1e-50,100 precision", 2, a.precision()); assertEquals("-1e-50,100 value", new Apfloat("3.7e-46"), a, new Apfloat("5e-47")); a = ApfloatMath.gamma(new Apfloat("4.5000000"), Apfloat.ZERO); assertEquals("4.5,0 precision", 8, a.precision()); assertEquals("4.5,0 value", new Apfloat("11.631728"), a, new Apfloat("5e-6")); a = ApfloatMath.gamma(new Apfloat("1234567890.0000000000"), new Apfloat("0.12345678900000000")); assertEquals("1234567890,0.123456789 precision", 10, a.precision()); assertEquals("1234567890,0.123456789", new Apfloat("9.091929131e10687926435"), a, new Apfloat("5e10687926426")); a = ApfloatMath.gamma(new Apfloat("0.12345678900000000"), new Apfloat("1234567890.000000000")); assertEquals("0.123456789,1234567890 precision", 10, a.precision()); assertEquals("0.123456789,1234567890", new Apfloat("7.395260483e-536166031"), a, new Apfloat("5e-536166022")); a = ApfloatMath.gamma(new Apfloat("4.0000000", Apfloat.DEFAULT, 11), new Apfloat("0.60000000", Apfloat.DEFAULT, 11)); assertEquals("4,0.6 precision radix 11", 8, a.precision()); assertEquals("4,0.6 value radix 11", new Apfloat("5.a929793", Apfloat.DEFAULT, 11), a, new Apfloat("5e-7", Apfloat.DEFAULT, 11)); a = ApfloatMath.gamma(new Apfloat("4.0000000", Apfloat.DEFAULT, 11), new Apfloat("-0.60000000", Apfloat.DEFAULT, 11)); assertEquals("4,-0.6 precision radix 11", 8, a.precision()); assertEquals("4,-0.6 value radix 11", new Apfloat("5.a6928aa", Apfloat.DEFAULT, 11), a, new Apfloat("5e-7", Apfloat.DEFAULT, 11)); a = ApfloatMath.gamma(new Apfloat("4.0000000", Apfloat.DEFAULT, 11), new Apfloat("6.0000000", Apfloat.DEFAULT, 11)); assertEquals("4,6 precision radix 11", 8, a.precision()); assertEquals("4,6 value radix 11", new Apfloat("0.9a857246", Apfloat.DEFAULT, 11), a, new Apfloat("5e-8", Apfloat.DEFAULT, 11)); a = ApfloatMath.gamma(new Apfloat("-4.0000000", Apfloat.DEFAULT, 11), new Apfloat("6.0000000", Apfloat.DEFAULT, 11)); assertEquals("-4,6 precision radix 11", 8, a.precision()); assertEquals("-4,6 value radix 11", new Apfloat("3.57a6772e-7", Apfloat.DEFAULT, 11), a, new Apfloat("5e-14", Apfloat.DEFAULT, 11)); try { ApfloatMath.gamma(Apfloat.ZERO, Apfloat.ZERO); fail("Gamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.gamma(new Apfloat("-0.500000"), new Apfloat("-0.500000")); fail("Non-real result"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.gamma(new Apfloat(-1, 10), new Apfloat(-2, 10)); fail("Non-real result"); } catch (ArithmeticException ae) { // OK non-real result } try { ApfloatMath.gamma(new Apfloat(0, 10), new Apfloat(-1, 10)); fail("Non-real result"); } catch (ArithmeticException ae) { // OK non-real result } try { ApfloatMath.gamma(new Apfloat("1e100", 100), new Apfloat("1.000e102")); fail("Overflow"); } catch (OverflowException are) { // OK } try { ApfloatMath.gamma(new Apfloat(4), new Apfloat(5)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testGammaIncompleteGeneralized() { Apfloat a = ApfloatMath.gamma(new Apfloat("2.0000000"), Apfloat.ZERO, new Apfloat("1.0000000")); assertEquals("2,0,1 precision", 7, a.precision()); assertEquals("2,0,1 value", new Apfloat("0.26424112"), a, new Apfloat("5e-8")); a = ApfloatMath.gamma(new Apfloat("1.0000000"), Apfloat.ZERO, new Apfloat("2.0000000")); assertEquals("1,0,2 precision", 7, a.precision()); assertEquals("1,0,2 value", new Apfloat("0.86466472"), a, new Apfloat("5e-8")); a = ApfloatMath.gamma(new Apfloat("4.0000000"), Apfloat.ZERO, new Apfloat("1.0000000")); assertEquals("4,0,1 precision", 7, a.precision()); assertEquals("4,0,1 value", new Apfloat("0.11392894"), a, new Apfloat("5e-8")); a = ApfloatMath.gamma(new Apfloat("4.0000000"), Apfloat.ZERO, new Apfloat("6.0000000")); assertEquals("4,0,6 precision", 8, a.precision()); assertEquals("4,0,6 value", new Apfloat("5.0927767"), a, new Apfloat("5e-7")); a = ApfloatMath.gamma(new Apfloat("1.0000000"), Apfloat.ZERO, new Apfloat("100.0000000")); assertEquals("1,0,100 precision", 8, a.precision()); assertEquals("1,0,100 value", new Apfloat(1), a, new Apfloat("5e-7")); a = ApfloatMath.gamma(new Apfloat(1, 10), Apfloat.ZERO, new Apfloat(-1, 10)); assertEquals("1,0,-1 precision", 10, a.precision()); assertEquals("1,0,-1 value", new Apfloat("-1.718281828"), a, new Apfloat("5e-9")); a = ApfloatMath.gamma(new Apfloat(2, 10), Apfloat.ZERO, new Apfloat("-0.2", 10)); assertEquals("2,0,-0.2 precision", 10, a.precision()); assertEquals("2,0,-0.2 value", new Apfloat("0.02287779347"), a, new Apfloat("5e-11")); a = ApfloatMath.gamma(new Apfloat(1000, 10), Apfloat.ZERO, new Apfloat(1, 10)); assertEquals("1000,0,1 precision", 10, a.precision()); assertEquals("1000,0,1 value", new Apfloat("0.0003682473202"), a, new Apfloat("5e-13")); a = ApfloatMath.gamma(new Apfloat(4.0), new Apfloat(0.01), new Apfloat(10000.0)); assertEquals("4,0.01,10000 precision", 16, a.precision()); assertEquals("4,0.01,10000 value", new Apfloat("5.999999997519917"), a, new Apfloat("5e-15")); a = ApfloatMath.gamma(new Apfloat(4.0), new Apfloat(10000.0), new Apfloat(0.01)); assertEquals("4,10000,0.01 precision", 16, a.precision()); assertEquals("4,10000,0.01 value", new Apfloat("-5.999999997519917"), a, new Apfloat("5e-15")); a = ApfloatMath.gamma(new Apfloat(4.0), new Apfloat(0.01), new Apfloat(0.02)); assertEquals("4,0.01,0.02 precision", 15, a.precision()); assertEquals("4,0.01,0.02 value", new Apfloat("3.68852198942455e-8"), a, new Apfloat("5e-22")); a = ApfloatMath.gamma(new Apfloat(4.0), new Apfloat(10000.0), new Apfloat(20000.0)); assertEquals("4,10000.0,20000.0 precision", 12, a.precision()); assertEquals("4,10000.0,20000.0 value", new Apfloat("1.13582457861018e-4331"), a, new Apfloat("5e-4342")); a = ApfloatMath.gamma(new Apfloat("4.0000000"), new Apfloat("1.0000000"), Apfloat.ZERO); assertEquals("4,1,0 precision", 7, a.precision()); assertEquals("4,1,0 value", new Apfloat("-0.11392894"), a, new Apfloat("5e-8")); a = ApfloatMath.gamma(new Apfloat(-4), new Apfloat(10000.0), new Apfloat(0.01)); assertEquals("-4,10000,0.01 precision", 16, a.precision()); assertEquals("-4,10000,0.01 value", new Apfloat("-24669150.2547202578891267"), a, new Apfloat("5e-8")); a = ApfloatMath.gamma(Apfloat.ZERO, new Apfloat(1.0), new Apfloat(2.0)); assertEquals("0,1,2 precision", 16, a.precision()); assertEquals("0,1,2 value", new Apfloat("0.1704834236874592"), a, new Apfloat("5e-16")); a = ApfloatMath.gamma(new Apint(1, 12), new Apint(1, 12), new Apint(1, 12)); assertEquals("1,1,1 value", new Apfloat(0), a); assertEquals("1,1,1 radix", 12, a.radix()); try { ApfloatMath.gamma(Apfloat.ZERO, Apfloat.ZERO, Apfloat.ZERO); fail("Gamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.gamma(new Apfloat(-1, 10), Apfloat.ZERO, new Apfloat(1, 10)); fail("Lower gamma of non-positive integer"); } catch (ArithmeticException ae) { // OK a is non-positive integer } try { ApfloatMath.gamma(Apfloat.ZERO, new Apfloat(-1, 10), Apfloat.ZERO); fail("Lower gamma of non-positive integer"); } catch (ArithmeticException ae) { // OK a is non-positive integer } try { ApfloatMath.gamma(Apfloat.ZERO, Apfloat.ZERO, new Apfloat(-1, 10)); fail("Lower gamma of non-positive integer"); } catch (ArithmeticException ae) { // OK a is non-positive integer } try { ApfloatMath.gamma(new Apfloat("1e100", 100), new Apfloat("1.000e102"), new Apfloat("1.000e103")); fail("Overflow"); } catch (OverflowException are) { // OK } try { ApfloatMath.gamma(new Apfloat(4), Apfloat.ZERO, new Apfloat(5)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testLogGamma() { Apfloat a = ApfloatMath.logGamma(new Apfloat(6, 30, 10)); assertEquals("6 precision", 29, a.precision()); assertEquals("6 value", new Apfloat("4.7874917427820459942477009345232"), a, new Apfloat("5e-28")); a = ApfloatMath.logGamma(new Apfloat("4.20000")); assertEquals("4.2 precision", 6, a.precision()); assertEquals("4.2 value", new Apfloat("2.04856"), a, new Apfloat("5e-5")); a = ApfloatMath.logGamma(new Apfloat("1.50000")); assertEquals("1.5 precision", 5, a.precision()); assertEquals("1.5 value", new Apfloat("-0.120782"), a, new Apfloat("5e-5")); try { ApfloatMath.logGamma(new Apfloat("-0.1")); fail("Log gamma of non-positive value"); } catch (ArithmeticException ae) { // OK a is negative } try { ApfloatMath.logGamma(Apfloat.ZERO); fail("Lower gamma of zero"); } catch (ArithmeticException ae) { // OK a is zero } } public static void testDigamma() { Apfloat a = ApfloatMath.digamma(new Apfloat(6, 30, 10)); assertEquals("6 precision", 30, a.precision(), 1); assertEquals("6 value", new Apfloat("1.70611766843180047272682124325"), a, new Apfloat("5e-29")); a = ApfloatMath.digamma(new Apfloat("-6.5", 30, 10)); assertEquals("-6.5 precision", 30, a.precision(), 1); assertEquals("-6.5 value", new Apfloat("1.94675748424608678806929117727"), a, new Apfloat("5e-29")); a = ApfloatMath.digamma(new Apfloat("1e100", 30, 10)); assertEquals("1e100 precision", 33, a.precision(), 1); assertEquals("1e100 value", new Apfloat("230.258509299404568401799145468436"), a, new Apfloat("5e-29")); a = ApfloatMath.digamma(new Apfloat("-10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.1")); assertEquals("-1e100-1 precision", 4, a.precision()); assertEquals("-1e100-1 value", new Apfloat("239.927337"), a, new Apfloat("5e-1")); a = ApfloatMath.digamma(new Apfloat("1e1000000", 30, 10)); assertEquals("1e1000000 precision", 36, a.precision(), 1); assertEquals("1e1000000 value", new Apfloat("2302585.09299404568401799145468436421"), a, new Apfloat("5e-26")); a = ApfloatMath.digamma(new Apfloat(1, 1)); assertEquals("1 precision", 1, a.precision()); assertEquals("1 value", new Apfloat("-0.6"), a, new Apfloat("5e-1")); try { ApfloatMath.digamma(new Apfloat(0)); fail("Digamma of zero"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.digamma(new Apfloat(-6)); fail("Digamma of -6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.digamma(new Apfloat(3)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testPolygamma() { Apfloat a = ApfloatMath.polygamma(3, new Apfloat(6, 30, 10)); assertEquals("3, 6 precision", 30, a.precision(), 1); assertEquals("3, 6 value", new Apfloat("0.0118278281927550750219481051729"), a, new Apfloat("5e-31")); } public static void testBeta() { Apfloat a = ApfloatMath.beta(new Apfloat(5, 6), new Apfloat(6, 6)); assertEquals("5, 6 precision", 6, a.precision(), 1); assertEquals("5, 6 value", new Apfloat("0.000793651"), a, new Apfloat("5e-9")); } public static void testBetaIncomplete() { Apfloat a = ApfloatMath.beta(new Apfloat(4, 6), new Apfloat(5, 6), new Apfloat(6, 6)); assertEquals("4, 5, 6 precision", 6, a.precision(), 1); assertEquals("4, 5, 6 value", new Apfloat("-20944.9"), a, new Apfloat("5e-1")); a = ApfloatMath.beta(new Apfloat(0), new Apfloat("1.00000"), new Apfloat("6.00000")); assertEquals("0, 1, 6 precision", Apfloat.INFINITE, a.precision(), 1); assertEquals("0, 1, 6 value", new Apfloat(0), a); a = ApfloatMath.beta(new Apfloat("-0.100000"), new Apfloat("1.00000"), new Apfloat("6.00000")); assertEquals("-0.1, 1, 6 precision", 6, a.precision(), 1); assertEquals("-0.1, 1, 6 value", new Apfloat("-0.128594"), a, new Apfloat("5e-6")); a = ApfloatMath.beta(new Apfloat("1", 40, 2), new Apfloat("10", 40, 2), new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2)); assertEquals("1, 10, 0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("0.1000000000000000000000000000000000000000", 40, 2), a, new Apfloat("1e-40", 1, 2)); assertEquals("1, 10, 0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision()); try { ApfloatMath.beta(new Apfloat("0.1"), new Apfloat(0), new Apfloat("1")); fail("Beta of 0.1, 0, 1"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("4"), new Apfloat(0), new Apfloat("6")); fail("Beta of 4, 0, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("0"), new Apfloat("-0.1"), new Apfloat("6")); fail("Beta of 0, -0.1, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("0"), new Apfloat("-1"), new Apfloat("6")); fail("Beta of 0, -1, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("-0.1"), new Apfloat("0.1"), new Apfloat("6")); fail("Beta of -0.1, 0.1, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("1.50000"), new Apfloat("-1.50000"), new Apfloat("2.50000")); fail("Beta of 1.5, -1.5, 2.5"); } catch (ArithmeticException ae) { // OK } } public static void testBetaIncompleteGeneralized() { Apfloat a = ApfloatMath.beta(new Apfloat(3, 6), new Apfloat(4, 6), new Apfloat(5, 6), new Apfloat(6, 6)); assertEquals("3, 4, 5, 6 precision", 6, a.precision(), 1); assertEquals("3, 4, 5, 6 value", new Apfloat("-20339.1"), a, new Apfloat("5e-1")); a = ApfloatMath.beta(new Apfloat(0), new Apfloat("1.00000"), new Apfloat("2.00000"), new Apfloat("6.00000")); assertEquals("0, 1, 2, 6 precision", 6, a.precision(), 1); assertEquals("0, 1, 2, 6 value", new Apfloat("0.0238095"), a, new Apfloat("5e-7")); a = ApfloatMath.beta(new Apfloat("1.00000"), new Apfloat(0), new Apfloat("2.00000"), new Apfloat("6.00000")); assertEquals("1, 0, 2, 6 precision", 6, a.precision(), 1); assertEquals("1, 0, 2, 6 value", new Apfloat("-0.0238095"), a, new Apfloat("5e-7")); a = ApfloatMath.beta(new Apfloat("-0.100000"), new Apfloat("1.00000"), new Apfloat("2.00000"), new Apfloat("6.00000")); assertEquals("-0.1, 1, 2, 6 precision", 6, a.precision(), 1); assertEquals("-0.1, 1, 2, 6 value", new Apfloat("0.0168720"), a, new Apfloat("5e-7")); a = ApfloatMath.beta(new Apfloat("1.00000"), new Apfloat("-0.100000"), new Apfloat("2.00000"), new Apfloat("6.00000")); assertEquals("1, -0.1, 2, 6 precision", 6, a.precision(), 1); assertEquals("1, -0.1, 2, 6 value", new Apfloat("-0.0168720"), a, new Apfloat("5e-7")); a = ApfloatMath.beta(new Apfloat("0.1", 40, 2), new Apfloat("1", 40, 2), new Apfloat("10", 40, 2), new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2)); assertEquals("0.1, 1, 10, 0.1111111111111111111111111111111111111111, 2 radix 2 value", new Apfloat("0.01100000000000000000000000000000000000001", 39, 2), a, new Apfloat("1e-40", 1, 2)); assertEquals("0.1, 1, 10,, 0.1111111111111111111111111111111111111111, 2 radix 2 precision", 39, a.precision()); try { ApfloatMath.beta(new Apfloat("0.1"), new Apfloat("0.2"), new Apfloat(0), new Apfloat("1")); fail("Beta of 0.1, 0.2, 0, 1"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("3"), new Apfloat("4"), new Apfloat(0), new Apfloat("6")); fail("Beta of 3, 4, 0, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("0"), new Apfloat("1"), new Apfloat("-0.1"), new Apfloat("6")); fail("Beta of 0, 1, -0.1, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("1"), new Apfloat("0"), new Apfloat("-0.1"), new Apfloat("6")); fail("Beta of 1, 0, -0.1, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("0"), new Apfloat("1"), new Apfloat("-1"), new Apfloat("6")); fail("Beta of 0, 1, -1, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("1"), new Apfloat("0"), new Apfloat("-1"), new Apfloat("6")); fail("Beta of 1, 0, -1, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("-0.1"), new Apfloat("1"), new Apfloat("0.1"), new Apfloat("6")); fail("Beta of -0.1, 1, 0.1, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("1"), new Apfloat("-0.1"), new Apfloat("0.1"), new Apfloat("6")); fail("Beta of 1, -0.1, 0.1, 6"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("1.50000"), new Apfloat("0.500000"), new Apfloat("-1.50000"), new Apfloat("2.50000")); fail("Beta of 1.5, 0.5, -1.5, 2.5"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.beta(new Apfloat("0.500000"), new Apfloat("1.50000"), new Apfloat("-1.50000"), new Apfloat("2.50000")); fail("Beta of 0.5, 1.5, -1.5, 2.5"); } catch (ArithmeticException ae) { // OK } } public static void testPochhammer() { Apfloat a = ApfloatMath.pochhammer(new Apfloat("3.10000"), new Apfloat("2.40000")); assertEquals("3.1, 2.4 precision", 6, a.precision(), 1); assertEquals("3.1, 2.4 value", new Apfloat("23.8179"), a, new Apfloat("5e-4")); a = ApfloatMath.pochhammer(new Apfloat("-3.00000"), new Apfloat("2.40000")); assertEquals("-3, 2.4 precision", Apfloat.INFINITE, a.precision(), 1); assertEquals("-3, 2.4 value", new Apfloat(0), a); a = ApfloatMath.pochhammer(new Apfloat("-3.00000"), new Apfloat("-2.00000")); assertEquals("-3, -2 precision", 6, a.precision(), 1); assertEquals("-3, -2 value", new Apfloat("0.0500000"), a, new Apfloat("5e-7")); try { ApfloatMath.pochhammer(new Apfloat("-3.50000"), new Apfloat("-2.50000")); fail("Infinite allowed"); } catch (ArithmeticException ae) { // OK } } public static void testBinomial() { Apfloat a = ApfloatMath.binomial(new Apfloat("9.000000000"), new Apfloat("4.000000000")); assertEquals("9,4 precision", 10, a.precision()); assertEquals("9,4 value", new Apfloat("126.0000000"), a, new Apfloat("5e-7")); a = ApfloatMath.binomial(new Apfloat("9.300000"), new Apfloat("4.200000")); assertEquals("9.3,4.2 precision", 6, a.precision()); assertEquals("9.3,4.2 value", new Apfloat("154.376"), a, new Apfloat("5e-3")); a = ApfloatMath.binomial(new Apfloat("-9.30000"), new Apfloat("-4.20000")); assertEquals("-9.3,-4.2 precision", 6, a.precision(), 1); assertEquals("-9.3,-4.2 value", new Apfloat("0.000200991"), a, new Apfloat("5e-9")); a = ApfloatMath.binomial(new Apfloat(0), new Apfloat(0)); assertEquals("0,0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0,0 value", new Apfloat(1), a); a = ApfloatMath.binomial(new Apfloat(1), new Apfloat(0)); assertEquals("1,0 precision", Apfloat.INFINITE, a.precision()); assertEquals("1,0 value", new Apfloat(1), a); a = ApfloatMath.binomial(new Apfloat("3.20000"), new Apfloat("4.00000")); assertEquals("3.2,4 precision", 6, a.precision()); assertEquals("3.2,4 value", new Apfloat("0.0704000"), a, new Apfloat("5e-7")); a = ApfloatMath.binomial(new Apfloat("7.20000"), new Apfloat("4.20000")); assertEquals("7.2,4.2 precision", 6, a.precision()); assertEquals("7.2,4.2 value", new Apfloat("38.6880"), a, new Apfloat("5e-4")); a = ApfloatMath.binomial(new Apfloat("3.20000"), new Apfloat("4.20000")); assertEquals("3.2,4.2 precision", Apfloat.INFINITE, a.precision()); assertEquals("3.2,4.2 value", new Apfloat(0), a); a = ApfloatMath.binomial(new Apfloat("3.20000"), new Apfloat("-4.00000")); assertEquals("3.2,-4 precision", Apfloat.INFINITE, a.precision()); assertEquals("3.2,-4 value", new Apfloat(0), a); try { ApfloatMath.binomial(new Apfloat("-3.0"), new Apfloat("4.2")); fail("Binomial of -3,4.2"); } catch (ArithmeticException ae) { // OK; result is infinite } } public static void testZeta() { Apfloat a = ApfloatMath.zeta(new Apfloat("3.00000")); assertEquals("3 precision", 6, a.precision()); assertEquals("3 value", new Apfloat("1.20206"), a, new Apfloat("5e-5")); a = ApfloatMath.zeta(new Apfloat("-101.000")); assertEquals("-101 precision", 4, a.precision()); assertEquals("-101 value", new Apfloat("-7.261e78"), a, new Apfloat("5e75")); a = ApfloatMath.zeta(new Apfloat("-1001.000")); assertEquals("-1001 precision", 4, a.precision()); assertEquals("-1001 value", new Apfloat("-1.349e1771"), a, new Apfloat("5e1768")); a = ApfloatMath.zeta(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("0.00833333"), a, new Apfloat("5e-8")); a = ApfloatMath.zeta(new Apfloat("-5.00000")); assertEquals("-5 precision", 6, a.precision()); assertEquals("-5 value", new Apfloat("-0.00396825"), a, new Apfloat("5e-8")); a = ApfloatMath.zeta(new Apfloat("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apfloat("-0.5"), a); a = ApfloatMath.zeta(new Apint(0, 11)); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Aprational(new Apint(-1, 11), new Apint(2, 11)), a); try { ApfloatMath.zeta(new Apint(1, 11)); fail("Zeta of one"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.zeta(new Apfloat(2)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testZetaHurwitz() { Apfloat a = ApfloatMath.zeta(new Apfloat("3.00000"), new Apfloat("4.00000")); assertEquals("3,4 precision", 6, a.precision()); assertEquals("3,4 value", new Apfloat("0.0400199"), a, new Apfloat("5e-7")); a = ApfloatMath.zeta(new Apfloat("3.00000"), new Apfloat("-4.20000")); assertEquals("3,4.2 precision", 6, a.precision()); assertEquals("3,4.2 value", new Apfloat("-123.502"), a, new Apfloat("5e-3")); a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("-4.20000")); assertEquals("-3,4.2 precision", 6, a.precision()); assertEquals("-3,4.2 value", new Apfloat("-119.2381"), a, new Apfloat("5e-3")); a = ApfloatMath.zeta(new Apfloat("3.00000"), new Apfloat("4.20000")); assertEquals("3,4.2 precision", 6, a.precision()); assertEquals("3,4.2 value", new Apfloat("0.0358824"), a, new Apfloat("5e-7")); a = ApfloatMath.zeta(new Apfloat("3.20000"), new Apfloat("4.00000")); assertEquals("-3,4.2 precision", 6, a.precision()); assertEquals("-3,4.2 value", new Apfloat("0.0282234"), a, new Apfloat("5e-7")); a = ApfloatMath.zeta(new Apfloat("3.20000"), new Apfloat("4.20000")); assertEquals("-3,4.2 precision", 6, a.precision()); assertEquals("-3,4.2 value", new Apfloat("0.0250343"), a, new Apfloat("5e-7")); a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("-3.00000")); assertEquals("-3,-3 precision", 6, a.precision()); assertEquals("-3,-3 value", new Apfloat("-35.9917"), a, new Apfloat("5e-4")); a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("-1.00000")); assertEquals("-3,-1 precision", 6, a.precision()); assertEquals("-3,-1 value", new Apfloat("-0.991667"), a, new Apfloat("5e-6")); a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("0")); assertEquals("-3,0 precision", 6, a.precision()); assertEquals("-3,0 value", new Apfloat("0.00833333"), a, new Apfloat("5e-8")); a = ApfloatMath.zeta(new Apfloat("-33.0000"), new Apfloat("0")); assertEquals("-33,0 precision", 6, a.precision()); assertEquals("-33,0 value", new Apfloat("-1.26357e10"), a, new Apfloat("5e5")); a = ApfloatMath.zeta(new Apfloat("-333.000"), new Apfloat("0")); assertEquals("-333,0 precision", 6, a.precision()); assertEquals("-333,0 value", new Apfloat("-5.2873977e430"), a, new Apfloat("5e425")); a = ApfloatMath.zeta(new Apfloat("-3.00000"), new Apfloat("1.00000")); assertEquals("-3,1 precision", 6, a.precision()); assertEquals("-3,1 value", new Apfloat("0.00833333"), a, new Apfloat("5e-8")); a = ApfloatMath.zeta(new Apfloat("0"), new Apfloat("0")); assertEquals("0,0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0,0 value", new Apfloat("0.5"), a); try { ApfloatMath.zeta(new Apint(1, 11), new Apint(2, 11)); fail("Zeta of s one"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.zeta(new Apfloat("-3.2"), new Apfloat("-4.2")); fail("Zeta of s noninteger and a nonpositive"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.zeta(new Apfloat("-3.2"), new Apfloat("-4.0")); fail("Zeta of s noninteger and a nonpositive"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.zeta(new Apfloat("-3.2"), new Apfloat("-4.2")); fail("Zeta of s noninteger and a nonpositive"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.zeta(new Apfloat("3.0"), new Apfloat("-3.0")); fail("3, -3 division by zero"); } catch (ArithmeticException ae) { // OK } } public static void testHypergeometric0F1() { Apfloat a = ApfloatMath.hypergeometric0F1(new Apfloat("2.00000"), new Apfloat("3.00000")); assertEquals("2, 3 precision", 6, a.precision()); assertEquals("2, 3 value", new Apfloat("3.46865"), a, new Apfloat("5e-5")); a = ApfloatMath.hypergeometric0F1(new Apfloat(2, 60, 2), new Apfloat(3, 60, 2)); assertEquals("2, 3 radix 2 precision", 60, a.precision()); assertEquals("2, 3 radix 2 radix", 2, a.radix()); assertEquals("2, 3 radix 2 value", new Apfloat("11.0111011111111001011010111110000111011011111111101110000100", 60, 2), a, new Apfloat("1e-58", 1, 2)); try { ApfloatMath.hypergeometric0F1(new Apfloat(3), new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHypergeometric1F1() { Apfloat a = ApfloatMath.hypergeometric1F1(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("4.00000")); assertEquals("2, 3, 4 precision", 6, a.precision()); assertEquals("2, 3, 4 value", new Apfloat("20.5993"), a, new Apfloat("5e-4")); a = ApfloatMath.hypergeometric1F1(new Apfloat(2, 60, 2), new Apfloat(3, 60, 2), new Apfloat(4, 60, 2)); assertEquals("2, 3, 4 radix 2 precision", 60, a.precision()); assertEquals("2, 3, 4 radix 2 radix", 2, a.radix()); assertEquals("2, 3, 4 radix 2 value", new Apfloat("10100.1001100101101100001000101001110101101011110000100100110", 60, 2), a, new Apfloat("1e-55", 1, 2)); try { ApfloatMath.hypergeometric1F1(new Apfloat(3), new Apfloat(4), new Apfloat(5)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHypergeometric2F1() { Apfloat a = ApfloatMath.hypergeometric2F1(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("0.100000")); assertEquals("1, 2.2, 3.3, 0.1 precision", 6, a.precision()); assertEquals("1, 2.2, 3.3, 0.1 value", new Apfloat("1.0720565"), a, new Apfloat("5e-6")); // x = 1 a = ApfloatMath.hypergeometric2F1(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("1.000000")); assertEquals("1, 2.2, 3.3, 1 precision", 6, a.precision()); assertEquals("1, 2.2, 3.3, 1 value", new Apfloat("23.0000"), a, new Apfloat("5e-4")); // Polynomial cases a = ApfloatMath.hypergeometric2F1(new Apfloat("-1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("5.000000")); assertEquals("-1, 2.2, 3.3, 5 precision", 6, a.precision()); assertEquals("-1, 2.2, 3.3, 5 value", new Apfloat("-2.33333"), a, new Apfloat("5e-5")); a = ApfloatMath.hypergeometric2F1(new Apfloat("-3.00000"), new Apfloat("-1.00000"), new Apfloat("-2.00000"), new Apfloat("1.00000")); assertEquals("-3, -1, -2, 1 precision", 6, a.precision()); assertEquals("-3, -1, -2, 1 value", new Apfloat("-0.500000"), a, new Apfloat("5e-6")); a = ApfloatMath.hypergeometric2F1(new Apfloat("-3.00000"), new Apfloat("-2.00000"), new Apfloat("-3.00000"), new Apfloat("1.00000")); assertEquals("-3, -2, -3, 1 precision", Apfloat.INFINITE, a.precision()); assertEquals("-3, -2, -3, 1 value", new Apfloat("0"), a); a = ApfloatMath.hypergeometric2F1(new Apfloat(1, 40, 2), new Apfloat(2, 40, 2), new Apfloat(3, 40, 2), new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2)); assertEquals("1, 2, 3, 0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("110101.0111001110100111011111010111000111", 40, 2), a, new Apfloat("1e-31", 1, 2)); assertEquals("1, 2, 3, 0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision()); try { ApfloatMath.hypergeometric2F1(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("1.000001")); fail("2F1 of x > 1"); } catch (ArithmeticException ae) { // OK result would be complex } try { ApfloatMath.hypergeometric2F1(new Apfloat(1), new Apfloat(2), new Apfloat(4), new Apfloat(2)); fail("2F1 of x > 1 with infinite precision"); } catch (ArithmeticException ae) { // OK result would be complex } try { ApfloatMath.hypergeometric2F1(new Apfloat("-2.00000"), new Apfloat("2.20000"), new Apfloat("-1.00000"), new Apfloat("0.000001")); fail("Infinite accepted"); } catch (ArithmeticException ae) { // OK result would be infinite } try { ApfloatMath.hypergeometric2F1(new Apfloat(2), new Apfloat(3), new Apfloat(6), new Apfloat(1)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } try { ApfloatMath.hypergeometric2F1(new Apfloat(-3), new Apfloat(-2), new Apfloat(-1), new Apfloat(1)); fail("Division by zero accepted"); } catch (ArithmeticException ae) { // OK } } public static void testHypergeometric0F1Regularized() { Apfloat a = ApfloatMath.hypergeometric0F1Regularized(new Apfloat("3.00000"), new Apfloat("4.00000")); assertEquals("3, 4 precision", 6, a.precision()); assertEquals("3, 4 value", new Apfloat("1.60555"), a, new Apfloat("5e-5")); a = ApfloatMath.hypergeometric0F1Regularized(new Apfloat("-3.00000"), new Apfloat("-4.00000")); assertEquals("-3, -4 precision", 5, a.precision()); assertEquals("-3, -4 value", new Apfloat("4.49807"), a, new Apfloat("5e-4")); a = ApfloatMath.hypergeometric0F1Regularized(new Apfloat(-3, 60, 2), new Apfloat(4, 60, 2)); assertEquals("-3, 4 radix 2 precision", 59, a.precision()); assertEquals("-3, 4 radix 2 radix", 2, a.radix()); assertEquals("-3, 4 radix 2 value", new Apfloat("10110.1010100100010000101101110110011111011100110111001110011", 60, 2), a, new Apfloat("1e-54", 1, 2)); try { ApfloatMath.hypergeometric0F1Regularized(new Apfloat(-3), new Apfloat(4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHypergeometric1F1Regularized() { Apfloat a = ApfloatMath.hypergeometric1F1Regularized(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("4.00000")); assertEquals("2, 3, 4 precision", 6, a.precision()); assertEquals("2, 3, 4 value", new Apfloat("10.2996"), a, new Apfloat("5e-4")); a = ApfloatMath.hypergeometric1F1Regularized(new Apfloat("2.00000"), new Apfloat("-3.00000"), new Apfloat("4.00000")); assertEquals("2, -3, 4 precision", 6, a.precision()); assertEquals("2, -3, 4 value", new Apfloat("125794"), a, new Apfloat("5e0")); a = ApfloatMath.hypergeometric1F1Regularized(new Apfloat(2, 60, 2), new Apfloat(-3, 60, 2), new Apfloat(4, 60, 2)); assertEquals("2, -3, 4 radix 2 precision", 59, a.precision()); assertEquals("2, -3, 4 radix 2 radix", 2, a.radix()); assertEquals("2, -3, 4 radix 2 value", new Apfloat("11110101101100010.0010001100111110110000100001101000110111010", 60, 2), a, new Apfloat("1e-42", 1, 2)); try { ApfloatMath.hypergeometric1F1Regularized(new Apfloat(3), new Apfloat(-4), new Apfloat(5)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHypergeometric2F1Regularized() { Apfloat a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("0.100000")); assertEquals("1, 2.2, 3.3, 0.1 precision", 6, a.precision()); assertEquals("1, 2.2, 3.3, 0.1 value", new Apfloat("0.399509"), a, new Apfloat("5e-6")); // x = 1 a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("1.000000")); assertEquals("1, 2.2, 3.3, 1 precision", 6, a.precision()); assertEquals("1, 2.2, 3.3, 1 value", new Apfloat("8.57110"), a, new Apfloat("5e-5")); // Polynomial cases a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("-1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("5.000000")); assertEquals("-1, 2.2, 3.3, 5 precision", 6, a.precision()); assertEquals("-1, 2.2, 3.3, 5 value", new Apfloat("-0.869532"), a, new Apfloat("5e-6")); a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("-3.00000"), new Apfloat("-1.00000"), new Apfloat("-2.00000"), new Apfloat("1.00000")); assertEquals("-3, -1, -2, 1 precision", Apfloat.INFINITE, a.precision()); assertEquals("-3, -1, -2, 1 value", new Apfloat("0"), a); a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("-3.00000"), new Apfloat("-2.00000"), new Apfloat("-3.00000"), new Apfloat("1.00000")); assertEquals("-3, -2, -3, 1 precision", Apfloat.INFINITE, a.precision()); assertEquals("-3, -2, -3, 1 value", new Apfloat("0"), a); // Needs regularization a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat("-2.00000"), new Apfloat("2.20000"), new Apfloat("-1.00000"), new Apfloat("0.100000")); assertEquals("-2, 2.2, -1, 0.1 precision", 6, a.precision()); assertEquals("-2, 2.2, -1, 0.1 value", new Apfloat("0.0704000"), a, new Apfloat("5e-7")); a = ApfloatMath.hypergeometric2F1Regularized(new Apfloat(1, 40, 2), new Apfloat(2, 40, 2), new Apfloat(3, 40, 2), new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2)); assertEquals("1, 2, 3, 0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("11010.10111001110100111011111010111000111", 40, 2), a, new Apfloat("1e-32", 1, 2)); assertEquals("1, 2, 3, 0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision()); try { ApfloatMath.hypergeometric2F1Regularized(new Apfloat("1.00000"), new Apfloat("2.20000"), new Apfloat("3.30000"), new Apfloat("1.000001")); fail("2F1 of x > 1"); } catch (ArithmeticException ae) { // OK result would be complex } try { ApfloatMath.hypergeometric2F1Regularized(new Apfloat(1), new Apfloat(2), new Apfloat(4), new Apfloat(2)); fail("2F1 of x > 1 with infinite precision"); } catch (ArithmeticException ae) { // OK result would be complex } try { ApfloatMath.hypergeometric2F1Regularized(new Apfloat(2), new Apfloat(3), new Apfloat(6), new Apfloat(1)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } try { ApfloatMath.hypergeometric2F1Regularized(new Apfloat(-3), new Apfloat(-2), new Apfloat(-1), new Apfloat(1)); // Needs regularization fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHypergeometricU() { Apfloat a = ApfloatMath.hypergeometricU(new Apfloat("2.00000"), new Apfloat("3.10000"), new Apfloat("4.00000")); assertEquals("2, 3.1, 4 precision", 6, a.precision()); assertEquals("2, 3.1, 4 value", new Apfloat("0.0649421"), a, new Apfloat("5e-7")); a = ApfloatMath.hypergeometricU(new Apfloat("-2.10000"), new Apfloat("3.30000"), new Apfloat("2.00000")); assertEquals("-2.1, 3.3, 2 precision", 6, a.precision()); assertEquals("-2.1, 3.3, 2 value", new Apfloat("2.13433"), a, new Apfloat("5e-5")); a = ApfloatMath.hypergeometricU(new Apfloat("2.10000"), new Apfloat("3.00000"), new Apfloat("2.00000")); assertEquals("2.1, 3, 2 precision", 6, a.precision()); assertEquals("2.1, 3, 2 value", new Apfloat("0.218408"), a, new Apfloat("5e-6")); // Polynomial cases a = ApfloatMath.hypergeometricU(new Apfloat(0), new Apfloat("3.10000"), new Apfloat("-2.00000")); assertEquals("0, 3.1, -2 precision", 6, a.precision()); assertEquals("0, 3.1, -2 value", new Apfloat("1.00000"), a, new Apfloat("5e-5")); a = ApfloatMath.hypergeometricU(new Apfloat("-2.00000"), new Apfloat("3.10000"), new Apfloat("-2.00000")); assertEquals("-2, 3.1, -2 precision", 6, a.precision()); assertEquals("-2, 3.1, -2 value", new Apfloat("33.1100"), a, new Apfloat("5e-4")); a = ApfloatMath.hypergeometricU(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("-2.00000")); assertEquals("2, 3, -2 precision", 6, a.precision()); assertEquals("2, 3, -2 value", new Apfloat("0.250000"), a, new Apfloat("5e-6")); a = ApfloatMath.hypergeometricU(new Apfloat("-1.0"), new Apfloat("-1.5"), new Apfloat("0")); assertEquals("-1, -1.5, 0 precision", 2, a.precision()); assertEquals("-1, -1.5, 0 value", new Apcomplex("1.5"), a, new Apfloat("5e-1")); a = ApfloatMath.hypergeometricU(new Apfloat("1.0"), new Apfloat("-1.5"), new Apfloat("0")); assertEquals("1, -1.5, 0 precision", 2, a.precision()); assertEquals("1, -1.5, 0 value", new Apcomplex("0.40"), a, new Apfloat("5e-2")); a = ApfloatMath.hypergeometricU(new Apfloat("1.0"), new Apfloat("0.50"), new Apfloat("0")); assertEquals("1, 0.5, 0 precision", 2, a.precision()); assertEquals("1, 0.5, 0 value", new Apcomplex("2.0"), a, new Apfloat("5e-1")); // Limit cases a = ApfloatMath.hypergeometricU(new Apfloat("1.50000"), new Apfloat("-2.00000"), new Apfloat("0.100000")); assertEquals("1.5, -2, 0.1 precision", 6, a.precision()); assertEquals("1.5, -2, 0.1 value", new Apfloat("0.160301"), a, new Apfloat("5e-6")); a = ApfloatMath.hypergeometricU(new Apfloat("1.50000"), new Apfloat("2.00000"), new Apfloat("0.100000")); assertEquals("1.5, 2, 0.1 precision", 6, a.precision()); assertEquals("1.5, 2, 0.1 value", new Apfloat("9.96165"), a, new Apfloat("5e-5")); try { ApfloatMath.hypergeometricU(new Apfloat("1.1"), new Apfloat("2.1"), new Apfloat("-0.10")); fail("x < 0 and not polynomial"); } catch (ArithmeticException ae) { // OK result would be complex } try { ApfloatMath.hypergeometricU(new Apfloat("1.0"), new Apfloat("2.1"), new Apfloat("-0.10")); fail("x < 0 and not polynomial"); } catch (ArithmeticException ae) { // OK result would be complex } try { ApfloatMath.hypergeometricU(new Apfloat("3.0"), new Apfloat("2.0"), new Apfloat("-1.0")); fail("x < 0 and not polynomial"); } catch (ArithmeticException ae) { // OK result would be complex } try { ApfloatMath.hypergeometricU(new Apfloat("-0.50"), new Apfloat("1.0"), new Apfloat("0")); fail("x == 0 and not polynomial"); } catch (ArithmeticException ae) { // OK result would be infinite } try { ApfloatMath.hypergeometricU(new Apfloat(3), new Apfloat(4), new Apfloat(5)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testErf() { Apfloat a = ApfloatMath.erf(new Apfloat("2.00000")); assertEquals("2 precision", 8, a.precision()); assertEquals("2 value", new Apfloat("0.99532226"), a, new Apfloat("5e-8")); } public static void testErfc() { Apfloat a = ApfloatMath.erfc(new Apfloat("2.00000")); assertEquals("2 precision", 6, a.precision()); assertEquals("2 value", new Apfloat("0.00467773"), a, new Apfloat("5e-8")); } public static void testErfi() { Apfloat a = ApfloatMath.erfi(new Apfloat("2.00000")); assertEquals("2 precision", 6, a.precision()); assertEquals("2 value", new Apfloat("18.5648"), a, new Apfloat("5e-4")); } public static void testInverseErf() { Apfloat a = ApfloatMath.inverseErf(new Apfloat("0.500000")); assertEquals("0.5 precision", 6, a.precision()); assertEquals("0.5 value", new Apfloat("0.476936"), a, new Apfloat("5e-6")); a = ApfloatMath.inverseErf(new Apfloat("-0.0100000")); assertEquals("-0.01 precision", 6, a.precision()); assertEquals("-0.01 value", new Apfloat("-0.00886250"), a, new Apfloat("5e-8")); a = ApfloatMath.inverseErf(new Apfloat("0.8", 100)); assertEquals("0.8 precision", 100, a.precision()); assertEquals("0.8 value", new Apfloat("0.9061938024368232200711627030956628666508668747462206614653792171330100552167389208141318241092656917"), a, new Apfloat("5e-100")); a = ApfloatMath.inverseErf(new Apfloat("0.99999999999999999999999999999999999999999999999999")); assertEquals("0.99999999999999999999999999999999999999999999999999 precision", 1, a.precision()); assertEquals("0.99999999999999999999999999999999999999999999999999 value", new Apfloat("10"), a, new Apfloat("5e1")); a = ApfloatMath.inverseErf(new Apfloat("0.99999999999999999999999999999999999999999999999999", 99)); assertEquals("0.99999999999999999999999999999999999999999999999999 precision", 50, a.precision()); assertEquals("0.99999999999999999999999999999999999999999999999999 value", new Apfloat("10.592090169527365189021663925329799115594206455417"), a, new Apfloat("5e-48")); a = ApfloatMath.inverseErf(new Apfloat("0.7", 100, 9)); assertEquals("0.7 precision", 100, a.precision()); assertEquals("0.7 radix", 9, a.radix()); assertEquals("0.7 value", new Apfloat("0.76818487807617820173552655636302134801487816266142015806376400456247340635433763871153387630807580274340", 100, 9), a, new Apfloat("5e-100", 1, 9)); a = ApfloatMath.inverseErf(new Apfloat("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apfloat("0"), a); try { ApfloatMath.inverseErf(new Apfloat("1")); fail("1 accepted"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.inverseErf(new Apfloat("-1")); fail("-1 accepted"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.inverseErf(new Apfloat("1.1")); fail("1.1 accepted"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.inverseErf(new Apfloat("-1.1")); fail("-1.1 accepted"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.inverseErf(new Aprational("1/2")); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testInverseErfc() { Apfloat a = ApfloatMath.inverseErfc(new Apfloat("0.500000")); assertEquals("0.5 precision", 6, a.precision()); assertEquals("0.5 value", new Apfloat("0.476936"), a, new Apfloat("5e-6")); a = ApfloatMath.inverseErfc(new Apfloat("1.0100000")); assertEquals("1.01 precision", 6, a.precision()); assertEquals("1.01 value", new Apfloat("-0.00886250"), a, new Apfloat("5e-8")); a = ApfloatMath.inverseErfc(new Apfloat("0.8", 100)); assertEquals("0.8 precision", 100, a.precision()); assertEquals("0.8 value", new Apfloat("0.1791434546212916764927490166264718703039092770195297157934243908496107231958296585375860598181676620"), a, new Apfloat("5e-100")); a = ApfloatMath.inverseErfc(new Apfloat("1.99999999999999999999999999999999999999999999999999")); assertEquals("1.99999999999999999999999999999999999999999999999999 precision", 1, a.precision()); assertEquals("1.99999999999999999999999999999999999999999999999999 value", new Apfloat("-10.592090169527365189021663925329799115594206455417"), a, new Apfloat("5e1")); a = ApfloatMath.inverseErfc(new Apfloat("1.99999999999999999999999999999999999999999999999999", 100)); assertEquals("1.99999999999999999999999999999999999999999999999999 precision", 50, a.precision()); assertEquals("1.99999999999999999999999999999999999999999999999999 value", new Apfloat("-10.592090169527365189021663925329799115594206455417"), a, new Apfloat("5e-48")); a = ApfloatMath.inverseErfc(new Apfloat("1e-50")); assertEquals("1e-50 precision", 1, a.precision()); assertEquals("1e-50 value", new Apfloat("10"), a, new Apfloat("5e1")); a = ApfloatMath.inverseErfc(new Apfloat("0.7", 100, 9)); assertEquals("0.7 precision", 100, a.precision()); assertEquals("0.7 radix", 9, a.radix()); assertEquals("0.7 value", new Apfloat("0.171425663605753727353512758150323485886618501752544182326432531337856381220182625185238532254168736114352", 100, 9), a, new Apfloat("5e-100", 1, 9)); a = ApfloatMath.inverseErfc(new Apfloat("1")); assertEquals("1 precision", Apfloat.INFINITE, a.precision()); assertEquals("1 value", new Apfloat("0"), a); try { ApfloatMath.inverseErfc(new Apfloat("0")); fail("0 accepted"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.inverseErfc(new Apfloat("2")); fail("2 accepted"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.inverseErfc(new Apfloat("-0.1")); fail("-0.1 accepted"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.inverseErfc(new Apfloat("2.1")); fail("2.1 accepted"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.inverseErfc(new Aprational("1/2")); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testFresnelS() { Apfloat a = ApfloatMath.fresnelS(new Apfloat("2.00000")); assertEquals("2 precision", 6, a.precision()); assertEquals("2 value", new Apfloat("0.343416"), a, new Apfloat("5e-6")); a = ApfloatMath.fresnelS(new Apfloat("200000.00000000000000")); assertEquals("200000 precision", 15, a.precision()); assertEquals("200000 value", new Apfloat("0.4999984084505691190421"), a, new Apfloat("5e-15")); } public static void testFresnelC() { Apfloat a = ApfloatMath.fresnelC(new Apfloat("2.00000")); assertEquals("2 precision", 6, a.precision()); assertEquals("2 value", new Apfloat("0.488253"), a, new Apfloat("5e-6")); a = ApfloatMath.fresnelC(new Apfloat("200000.00000000000000")); assertEquals("200000 precision", 15, a.precision()); assertEquals("200000 value", new Apfloat("0.500000000000000"), a, new Apfloat("5e-15")); } public static void testExpIntegralE() { Apfloat a = ApfloatMath.expIntegralE(new Apfloat("2.00000"), new Apfloat("3.00000")); assertEquals("2, 3 precision", 6, a.precision()); assertEquals("2, 3 value", new Apfloat("0.0106419"), a, new Apfloat("5e-7")); a = ApfloatMath.expIntegralE(new Apfloat("-0.100000"), new Apfloat("0.100000")); assertEquals("-0.1, 0.1 precision", 6, a.precision()); assertEquals("-0.1, 0.1 value", new Apfloat("11.1138"), a, new Apfloat("5e-4")); a = ApfloatMath.expIntegralE(new Apfloat("0"), new Apfloat("-0.100000")); assertEquals("0, -0.1 precision", 6, a.precision()); assertEquals("0, -0.1 value", new Apfloat("-11.0517"), a, new Apfloat("5e-4")); try { ApfloatMath.expIntegralE(new Apfloat("0"), new Apfloat("0")); fail("0, 0"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.expIntegralE(new Apfloat("0.100000"), new Apfloat("-0.100000")); fail("x negative"); } catch (ArithmeticException ae) { // OK } } public static void testExpIntegralEi() { Apfloat a = ApfloatMath.expIntegralEi(new Apfloat("3.00000")); assertEquals("3 precision", 6, a.precision()); assertEquals("3 value", new Apfloat("9.93383"), a, new Apfloat("5e-5")); a = ApfloatMath.expIntegralEi(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("-0.0130484"), a, new Apfloat("5e-7")); try { ApfloatMath.expIntegralEi(new Apfloat("0")); fail("Ei of zero"); } catch (ArithmeticException ae) { // OK } } public static void testLogIntegral() { Apfloat a = ApfloatMath.logIntegral(new Apfloat("3.000000")); assertEquals("3 precision", 6, a.precision()); assertEquals("3 value", new Apfloat("2.16359"), a, new Apfloat("5e-5")); a = ApfloatMath.logIntegral(new Apfloat("0.0500000")); assertEquals("0.05 precision", 6, a.precision()); assertEquals("0.05 value", new Apfloat("-0.0131194"), a, new Apfloat("5e-7")); a = ApfloatMath.logIntegral(new Apfloat("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Apfloat("0"), a, new Apfloat("5e-7")); try { ApfloatMath.logIntegral(new Apfloat("1")); fail("li of 1"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.logIntegral(new Apfloat("-0.1")); fail("li of negative number"); } catch (ArithmeticException ae) { // OK } } public static void testSinIntegral() { Apfloat a = ApfloatMath.sinIntegral(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("-1.84865"), a, new Apfloat("5e-5")); } public static void testCosIntegral() { Apfloat a = ApfloatMath.cosIntegral(new Apfloat("3.00000")); assertEquals("3 precision", 6, a.precision()); assertEquals("3 value", new Apfloat("0.119630"), a, new Apfloat("5e-6")); try { ApfloatMath.cosIntegral(new Apfloat("0")); fail("Ci of zero"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.cosIntegral(new Apfloat("-0.1")); fail("Ci of negative number"); } catch (ArithmeticException ae) { // OK } } public static void testSinhIntegral() { Apfloat a = ApfloatMath.sinhIntegral(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("-4.97344"), a, new Apfloat("5e-5")); } public static void testCoshIntegral() { Apfloat a = ApfloatMath.coshIntegral(new Apfloat("3.00000")); assertEquals("3 precision", 6, a.precision()); assertEquals("3 value", new Apfloat("4.96039"), a, new Apfloat("5e-5")); try { ApfloatMath.coshIntegral(new Apfloat("0")); fail("Chi of zero"); } catch (ArithmeticException ae) { // OK } try { ApfloatMath.coshIntegral(new Apfloat("-0.1")); fail("Chi of negative number"); } catch (ArithmeticException ae) { // OK } } public static void testAiryAi() { Apfloat a = ApfloatMath.airyAi(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("-0.378814"), a, new Apfloat("5e-6")); } public static void testAiryAiPrime() { Apfloat a = ApfloatMath.airyAiPrime(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("0.314584"), a, new Apfloat("5e-6")); } public static void testAiryBi() { Apfloat a = ApfloatMath.airyBi(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("-0.198290"), a, new Apfloat("5e-6")); } public static void testAiryBiPrime() { Apfloat a = ApfloatMath.airyBiPrime(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("-0.675611"), a, new Apfloat("5e-6")); } public static void testBesselJ() { Apfloat a = ApfloatMath.besselJ(new Apfloat("-3.00000"), new Apfloat("5.00000")); assertEquals("-3, 5 precision", 6, a.precision()); assertEquals("-3, 5 value", new Apfloat("-0.364831"), a, new Apfloat("9e-6")); a = ApfloatMath.besselJ(new Apfloat("-1.00000"), new Apfloat("-1.10000")); assertEquals("-1, -1.1 precision", 6, a.precision()); assertEquals("-1, -1.1 value", new Apfloat("0.470902"), a, new Apfloat("9e-6")); try { ApfloatMath.besselJ(new Apfloat("-0.1"), new Apfloat("0")); fail("-0.1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApfloatMath.besselJ(new Apfloat("0.1"), new Apfloat("-0.1")); fail("0.1, -0.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testBesselI() { Apfloat a = ApfloatMath.besselI(new Apfloat("-3.00000"), new Apfloat("5.00000")); assertEquals("-3, 5 precision", 6, a.precision()); assertEquals("-3, 5 value", new Apfloat("10.3312"), a, new Apfloat("5e-4")); a = ApfloatMath.besselI(new Apfloat("-1.00000"), new Apfloat("-1.10000")); assertEquals("-1, -1.1 precision", 6, a.precision()); assertEquals("-1, -1.1 value", new Apfloat("-0.637489"), a, new Apfloat("9e-6")); try { ApfloatMath.besselI(new Apfloat("-0.1"), new Apfloat("0")); fail("-0.1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApfloatMath.besselI(new Apfloat("0.1"), new Apfloat("-0.1")); fail("0.1, -0.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testBesselY() { Apfloat a = ApfloatMath.besselY(new Apfloat("-3.00000"), new Apfloat("5.00000")); assertEquals("-3, 5 precision", 6, a.precision()); assertEquals("-3, 5 value", new Apfloat("-0.146267"), a, new Apfloat("5e-6")); try { ApfloatMath.besselY(new Apfloat("1"), new Apfloat("0")); fail("1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApfloatMath.besselY(new Apfloat("1"), new Apfloat("-0.1")); fail("1, -0.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testBesselK() { Apfloat a = ApfloatMath.besselK(new Apfloat("-3.00000"), new Apfloat("5.00000")); assertEquals("-3, 5 precision", 6, a.precision()); assertEquals("-3, 5 value", new Apfloat("0.00829177"), a, new Apfloat("5e-8")); try { ApfloatMath.besselK(new Apfloat("1"), new Apfloat("0")); fail("1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApfloatMath.besselK(new Apfloat("1"), new Apfloat("-0.1")); fail("1, -0.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testEllipticK() { Apfloat a = ApfloatMath.ellipticK(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("1.07826"), a, new Apfloat("5e-5")); a = ApfloatMath.ellipticK(new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2)); assertEquals("0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("1111.001111111100111000001111010011000000", 40, 2), a, new Apfloat("1e-36", 1, 2)); assertEquals("0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision()); try { ApfloatMath.ellipticK(new Apfloat("1.10000", 6, 2)); fail("1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.ellipticK(new Apfloat("1.00000")); fail("1 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { ApfloatMath.ellipticK(new Apfloat("0")); fail("Infinite expansion of pi/2"); } catch (InfiniteExpansionException iee) { // OK } try { ApfloatMath.ellipticK(new Apfloat(-4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testEllipticE() { Apfloat a = ApfloatMath.ellipticE(new Apfloat("-3.00000")); assertEquals("-3 precision", 6, a.precision()); assertEquals("-3 value", new Apfloat("2.42211"), a, new Apfloat("5e-5")); a = ApfloatMath.ellipticE(new Apfloat("1.00000")); assertEquals("1 precision", 6, a.precision()); assertEquals("1 value", new Apfloat("1.00000"), a, new Apfloat("5e-5")); a = ApfloatMath.ellipticE(new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2)); assertEquals("0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("1.000000000000000000000000000000000000011", 40, 2), a, new Apfloat("1e-39", 1, 2)); assertEquals("0.1111111111111111111111111111111111111111 radix 2 precision", 40, a.precision()); try { ApfloatMath.ellipticE(new Apfloat("1.10000", 6, 2)); fail("1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.ellipticE(new Apfloat("0")); fail("Infinite expansion of pi/2"); } catch (InfiniteExpansionException iee) { // OK } try { ApfloatMath.ellipticE(new Apfloat(-4)); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testHermiteH() { Apfloat a = ApfloatMath.hermiteH(new Apfloat("2.00000"), new Apfloat("3.00000")); assertEquals("2, 3 precision", 6, a.precision()); assertEquals("2, 3 value", new Apfloat("34.0000"), a, new Apfloat("5e-4")); } public static void testLaguerreL() { Apfloat a = ApfloatMath.laguerreL(new Apfloat("2.00000"), new Apfloat("3.00000")); assertEquals("2, 3 precision", 6, a.precision()); assertEquals("2, 3 value", new Apfloat("-0.500000"), a, new Apfloat("5e-6")); } public static void testLaguerreLGeneralized() { Apfloat a = ApfloatMath.laguerreL(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("4.00000")); assertEquals("2, 3, 4 precision", 6, a.precision()); assertEquals("2, 3, 4 value", new Apfloat("-2.00000"), a, new Apfloat("5e-5")); } public static void testLegendreP() { Apfloat a = ApfloatMath.legendreP(new Apfloat("2.00000"), new Apfloat("3.00000")); assertEquals("2, 3 precision", 6, a.precision()); assertEquals("2, 3 value", new Apfloat("13.0000"), a, new Apfloat("5e-4")); a = ApfloatMath.legendreP(new Apfloat("2.00000"), new Apfloat("-1.10000")); assertEquals("2, -1.1 precision", 6, a.precision()); assertEquals("2, -1.1 value", new Apfloat("1.31500"), a, new Apfloat("5e-5")); a = ApfloatMath.legendreP(new Apfloat("5.000000"), new Apfloat("-1.000000")); assertEquals("5, -1 precision", 6, a.precision()); assertEquals("5, -1 value", new Apfloat("-1.00000"), a, new Apfloat("5e-5")); a = ApfloatMath.legendreP(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)); assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision()); assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix()); assertEquals("0.1, 0.11 radix 2 value", new Apfloat("0.111001101111110011", 18, 2), a, new Apfloat("1e-18", 1, 2)); try { ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("-1.00000")); fail("2.1, -1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("-1.10000")); fail("2.1, -1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testLegendrePAssociated() { Apfloat a = ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("3.20000"), new Apfloat("0.500000")); assertEquals("2.1, 3.2, 0.5 precision", 6, a.precision()); assertEquals("2.1, 3.2, 0.5 value", new Apfloat("-5.81509"), a, new Apfloat("5e-5")); a = ApfloatMath.legendreP(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("1.10000")); assertEquals("2, 3, 1.1 precision", Apfloat.INFINITE, a.precision()); assertEquals("2, 3, 1.1 value", new Apfloat("0"), a); a = ApfloatMath.legendreP(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("-1.10000")); assertEquals("2, 3, -1.1 precision", Apfloat.INFINITE, a.precision()); assertEquals("2, 3, -1.1 value", new Apfloat("0"), a); a = ApfloatMath.legendreP(new Apfloat("0"), new Apfloat("1.00000"), new Apfloat("1.100000")); assertEquals("0, 3, -1.1 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 3, -1.1 value", new Apfloat("0"), a); a = ApfloatMath.legendreP(new Apfloat("-5.00000"), new Apfloat("5.00000"), new Apfloat("1.100000")); assertEquals("-5, 5, -1.1 precision", Apfloat.INFINITE, a.precision()); assertEquals("-5, 5, -1.1 value", new Apfloat("0"), a); a = ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("2.00000"), new Apfloat("1.10000")); assertEquals("2.1, 2, 1.1 precision", 6, a.precision()); assertEquals("2.1, 2, 1.1 value", new Apfloat("-0.777038"), a, new Apfloat("5e-6")); a = ApfloatMath.legendreP(new Apfloat("-5.000000"), new Apfloat("4.000000"), new Apfloat("-1.100000")); assertEquals("-5, 4, -1.1 precision", 6, a.precision()); assertEquals("-5, 4, -1.1 value", new Apfloat("4.63050"), a, new Apfloat("5e-5")); a = ApfloatMath.legendreP(new Apfloat("-3.00000"), new Apfloat("-4.00000"), new Apfloat("-1.10000")); assertEquals("-3, -4, -1.1 precision", 6, a.precision()); assertEquals("-3, -4, -1.1 value", new Apfloat("3.32587"), a, new Apfloat("5e-5")); a = ApfloatMath.legendreP(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2), new Apfloat("0.111", 18, 2)); assertEquals("0.1, 0.11, 0.111 radix 2 precision", 18, a.precision()); assertEquals("0.1, 0.11, 0.111 radix 2 radix", 2, a.radix()); assertEquals("0.1, 0.11, 0.111 radix 2 value", new Apfloat("0.1001110100101111011", 18, 2), a, new Apfloat("1e-18", 1, 2)); try { ApfloatMath.legendreP(new Apfloat("1.10000"), new Apfloat("1.00000"), new Apfloat("1.100000")); fail("1.1, 1, 1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreP(new Apfloat("1.00000"), new Apfloat("1.10000"), new Apfloat("1.100000")); fail("1, 1.1, 1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreP(new Apfloat("2.10000"), new Apfloat("4.00000"), new Apfloat("-1.10000")); fail("2.1, 4, -1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreP(new Apfloat("-4.00000"), new Apfloat("-3.00000"), new Apfloat("-1.10000")); fail("-4, -3, -1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreP(new Apfloat("1.00000"), new Apfloat("1.00000"), new Apfloat("1.100000")); fail("1, 1, 1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreP(new Apfloat("-6.00000"), new Apfloat("5.00000"), new Apfloat("1.100000")); fail("-6, 5, 1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testLegendreQ() { Apfloat a = ApfloatMath.legendreQ(new Apfloat("2.00000"), new Apfloat("0.300000")); assertEquals("2, 0.3 precision", 6, a.precision()); assertEquals("2, 0.3 value", new Apfloat("-0.562975"), a, new Apfloat("5e-6")); a = ApfloatMath.legendreQ(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)); assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision()); assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix()); assertEquals("0.1, 0.11 radix 2 value", new Apfloat("0.00111001011011111100", 18, 2), a, new Apfloat("1e-20", 1, 2)); try { ApfloatMath.legendreQ(new Apfloat("2.00000"), new Apfloat("1.00000")); fail("2, 1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("-1.00000")); fail("2.1, -1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("-1.10000")); fail("2.1, -1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testLegendreQAssociated() { Apfloat a = ApfloatMath.legendreQ(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("0.300000")); assertEquals("2, 3, 0.3 precision", 6, a.precision()); assertEquals("2, 3, 0.3 value", new Apfloat("-9.21569"), a, new Apfloat("5e-5")); a = ApfloatMath.legendreQ(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2), new Apfloat("0.111", 18, 2)); assertEquals("0.1, 0.11, 0.111 radix 2 precision", 18, a.precision()); assertEquals("0.1, 0.11, 0.111 radix 2 radix", 2, a.radix()); assertEquals("0.1, 0.11, 0.111 radix 2 value", new Apfloat("-1.110000000111111111", 18, 2), a, new Apfloat("1e-17", 1, 2)); try { ApfloatMath.legendreQ(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("1.00000")); fail("2, 3, 1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("3.00000"), new Apfloat("-1.00000")); fail("2.1, 3, -1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.legendreQ(new Apfloat("2.10000"), new Apfloat("3.00000"), new Apfloat("-1.10000")); fail("2.1, 3, -1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testChebyshevT() { Apfloat a = ApfloatMath.chebyshevT(new Apfloat("2.00000"), new Apfloat("3.00000")); assertEquals("2, 3 precision", 6, a.precision()); assertEquals("2, 3 value", new Apfloat("17.0000"), a, new Apfloat("5e-4")); a = ApfloatMath.chebyshevT(new Apfloat("2.30000"), new Apfloat("-1.00000")); assertEquals("2.3, -1 precision", 6, a.precision()); assertEquals("2.3, -1 value", new Apfloat("0.587785"), a, new Apfloat("5e-6")); a = ApfloatMath.chebyshevT(new Apfloat("2.000000"), new Apfloat("-1.100000")); assertEquals("2, -1.1 precision", 6, a.precision()); assertEquals("2, -1.1 value", new Apfloat("1.42000"), a, new Apfloat("5e-5")); a = ApfloatMath.chebyshevT(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)); assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision()); assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix()); assertEquals("0.1, 0.11 radix 2 value", new Apfloat("0.111011110111011101", 18, 2), a, new Apfloat("1e-18", 1, 2)); try { ApfloatMath.chebyshevT(new Apfloat("2.30000"), new Apfloat("-1.00001")); fail("2.3, -1.00001 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testChebyshevU() { Apfloat a = ApfloatMath.chebyshevU(new Apfloat("2.00000"), new Apfloat("3.00000")); assertEquals("2, 3 precision", 6, a.precision()); assertEquals("2, 3 value", new Apfloat("35.0000"), a, new Apfloat("5e-4")); a = ApfloatMath.chebyshevU(new Apfloat("2.00000"), new Apfloat("-1.00000")); assertEquals("2, -1 precision", 6, a.precision()); assertEquals("2, -1 value", new Apfloat("3.00000"), a, new Apfloat("5e-5")); a = ApfloatMath.chebyshevU(new Apfloat("2.000000"), new Apfloat("-1.100000")); assertEquals("2, -1.1 precision", 6, a.precision()); assertEquals("2, -1.1 value", new Apfloat("3.84000"), a, new Apfloat("5e-5")); a = ApfloatMath.chebyshevU(new Apfloat("0.1", 20, 2), new Apfloat("0.11", 20, 2)); assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision()); assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix()); assertEquals("0.1, 0.11 radix 2 value", new Apfloat("1.01010110000110000", 18, 2), a, new Apfloat("1e-17", 1, 2)); try { ApfloatMath.chebyshevU(new Apfloat("2.10000"), new Apfloat("-1.00000")); fail("2.1, -1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.chebyshevU(new Apfloat("2.10000"), new Apfloat("-1.00001")); fail("2.1, -1.00001 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testGegenbauerCRenormalized() { Apfloat a = ApfloatMath.gegenbauerC(new Apfloat("2.00000"), new Apfloat("3.00000")); assertEquals("2, 3 precision", 6, a.precision()); assertEquals("2, 3 value", new Apfloat("17.0000"), a, new Apfloat("5e-4")); a = ApfloatMath.gegenbauerC(new Apfloat("2.10000"), new Apfloat("-1.00000")); assertEquals("2.1, -1 precision", 6, a.precision()); assertEquals("2.1, -1 value", new Apfloat("0.905768"), a, new Apfloat("5e-6")); a = ApfloatMath.gegenbauerC(new Apfloat("-2.000000"), new Apfloat("-1.100000")); assertEquals("-2, -1.1 precision", 6, a.precision()); assertEquals("-2, -1.1 value", new Apfloat("-1.42000"), a, new Apfloat("5e-5")); a = ApfloatMath.gegenbauerC(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2)); assertEquals("0.1, 0.11 radix 2 precision", 18, a.precision()); assertEquals("0.1, 0.11 radix 2 radix", 2, a.radix()); assertEquals("0.1, 0.11 radix 2 value", new Apfloat("11.1011110111011101", 18, 2), a, new Apfloat("1e-16", 1, 2)); try { ApfloatMath.gegenbauerC(new Apfloat("0"), new Apfloat("1.00000")); fail("0, 1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.gegenbauerC(new Apfloat("2.10000"), new Apfloat("-1.00001")); fail("2.1, -1.00001 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testGegenbauerC() { Apfloat a = ApfloatMath.gegenbauerC(new Apfloat("2.00000"), new Apfloat("3.00000"), new Apfloat("4.00000")); assertEquals("2, 3, 4 precision", 6, a.precision()); assertEquals("2, 3, 4 value", new Apfloat("381.000"), a, new Apfloat("5e-3")); a = ApfloatMath.gegenbauerC(new Apfloat("-2.10000"), new Apfloat("-0.500000"), new Apfloat("2.10000")); assertEquals("-2.1, -0.5, 2.1 precision", 6, a.precision()); assertEquals("-2.1, -0.5, 2.1 value", new Apfloat("-3.90011"), a, new Apfloat("5e-5")); a = ApfloatMath.gegenbauerC(new Apfloat("-2.000000"), new Apfloat("-3.10000"), new Apfloat("-1.100000")); assertEquals("-2, -3.1, -1.1 precision", Apfloat.INFINITE, a.precision()); assertEquals("-2, -3.1, -1.1 value", new Apfloat("0"), a); a = ApfloatMath.gegenbauerC(new Apfloat("3.00000"), new Apfloat("0.500000"), new Apfloat("-1.00000")); assertEquals("3, 0.5, 2.1 precision", 6, a.precision()); assertEquals("3, 0.5, 2.1 value", new Apfloat("-1.00000"), a, new Apfloat("5e-5")); a = ApfloatMath.gegenbauerC(new Apfloat("-3.00000"), new Apfloat("0.500000"), new Apfloat("-1.00000")); assertEquals("-3, 0.5, 2.1 precision", 6, a.precision()); assertEquals("-3, 0.5, 2.1 value", new Apfloat("1.00000"), a, new Apfloat("5e-5")); a = ApfloatMath.gegenbauerC(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2), new Apfloat("0.111", 18, 2)); assertEquals("0.1, 0.11, 0.111 radix 2 precision", 18, a.precision()); assertEquals("0.1, 0.11, 0.111 radix 2 radix", 2, a.radix()); assertEquals("0.1, 0.11, 0.111 radix 2 value", new Apfloat("1.00110101010011001", 18, 2), a, new Apfloat("1e-17", 1, 2)); try { ApfloatMath.gegenbauerC(new Apfloat("2.10000"), new Apfloat("3.10000"), new Apfloat("-1.00000")); fail("2.1, 3.1, -1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.gegenbauerC(new Apfloat("-2.10000"), new Apfloat("0.500000"), new Apfloat("-1.00000")); fail("-2.1, 0.5, -1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.gegenbauerC(new Apfloat("2.10000"), new Apfloat("1"), new Apfloat("-1.00001")); fail("2.1, 1, -1.00001 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testJacobiP() { Apfloat a = ApfloatMath.jacobiP(new Apfloat("3.0000"), new Apfloat("4.0000"), new Apfloat("5.0000"), new Apfloat("6.0000")); assertEquals("3, 4, 5, 6 precision", 6, a.precision()); assertEquals("3, 4, 5, 6 value", new Apfloat("11808.1"), a, new Apfloat("5e-1")); a = ApfloatMath.jacobiP(new Apfloat("2.10000"), new Apfloat("-1.00000"), new Apfloat("-1.00000"), new Apfloat("-1.00000")); assertEquals("2.1, -1, -1, -1 precision", 6, a.precision()); assertEquals("2.1, -1, -1, -1 value", new Apfloat("0.0468396"), a, new Apfloat("5e-7")); a = ApfloatMath.jacobiP(new Apfloat("1.0000000"), new Apfloat("-2.0000000"), new Apfloat("-1.0000000"), new Apfloat("-1.1000000")); assertEquals("1, -2, -1, -1.1 precision", 6, a.precision()); assertEquals("1, -2, -1, -1.1 value", new Apfloat("0.0500000"), a, new Apfloat("5e-7")); a = ApfloatMath.jacobiP(new Apfloat("0.1", 18, 2), new Apfloat("0.11", 18, 2), new Apfloat("0.111", 18, 2), new Apfloat("0.1111", 18, 2)); assertEquals("0.1, 0.11, 0.111, 0.1111 radix 2 precision", 18, a.precision()); assertEquals("0.1, 0.11, 0.111, 0.1111 radix 2 radix", 2, a.radix()); assertEquals("0.1, 0.11, 0.111, 0.1111 radix 2 value", new Apfloat("1.0101101000001101011", 18, 2), a, new Apfloat("1e-17", 1, 2)); try { ApfloatMath.jacobiP(new Apfloat("2.10000"), new Apfloat("-1.00000"), new Apfloat("0.100000"), new Apfloat("-1.00000")); fail("2.1, -1, 0.1, -1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.jacobiP(new Apfloat("2.10000"), new Apfloat("-1.00000"), new Apfloat("-1.00000"), new Apfloat("-1.10000")); fail("2.1, -1, -1, -1.1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.jacobiP(new Apfloat("-0.50000"), new Apfloat("-0.50000"), new Apfloat("1.00000"), new Apfloat("1.00000")); fail("-0.5, -0.5, 1, 1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testFibonacci() { Apfloat a = ApfloatMath.fibonacci(new Apfloat("3.00000"), new Apfloat("4.00000")); assertEquals("3, 4 precision", 6, a.precision()); assertEquals("3, 4 value", new Apfloat("17.0000"), a, new Apfloat("5e-4")); a = ApfloatMath.fibonacci(new Apfloat("5.60000"), new Apfloat("7.80000")); assertEquals("5.6, 7.8 precision", 6, a.precision()); assertEquals("5.6, 7.8 value", new Apfloat("13453.4"), a, new Apfloat("5e-1")); } public static void testEulerE() { Apfloat a = ApfloatMath.eulerE(3, new Apfloat("4.00000")); assertEquals("3, 4 precision", 6, a.precision()); assertEquals("3, 4 value", new Apfloat("40.2500"), a, new Apfloat("5e-4")); a = ApfloatMath.eulerE(56, new Apfloat("7.80000")); assertEquals("56, 7.8 precision", 6, a.precision()); assertEquals("56, 7.8 value", new Apfloat("6.61538e45"), a, new Apfloat("5e40")); } public static void testBernoulliB() { Apfloat a = ApfloatMath.bernoulliB(3, new Apfloat("4.00000")); assertEquals("3, 4 precision", 6, a.precision()); assertEquals("3, 4 value", new Apfloat("42.0000"), a, new Apfloat("5e-4")); a = ApfloatMath.bernoulliB(56, new Apfloat("7.80000")); assertEquals("56, 7.8 precision", 6, a.precision()); assertEquals("56, 7.8 value", new Apfloat("3.43754e47"), a, new Apfloat("5e42")); } public static void testHarmonicNumber() { Apfloat a = ApfloatMath.harmonicNumber(new Apfloat("3.45000")); assertEquals("3.45 precision", 6, a.precision()); assertEquals("3.45 value", new Apfloat("1.95357"), a, new Apfloat("5e-5")); try { ApfloatMath.harmonicNumber(new Apfloat("-1.0000")); fail("-1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testHarmonicNumberGeneralized() { Apfloat a = ApfloatMath.harmonicNumber(new Apfloat("3.40000"), new Apfloat("5.60000")); assertEquals("3.4, 5.6 precision", 6, a.precision()); assertEquals("3.4, 5.6 value", new Apfloat("1.02299"), a, new Apfloat("5e-5")); a = ApfloatMath.harmonicNumber(new Apfloat("-1.00000"), new Apfloat("0")); assertEquals("-1, 0 precision", 6, a.precision()); assertEquals("-1, 0 value", new Apfloat("-1.00000"), a, new Apfloat("5e-5")); a = ApfloatMath.harmonicNumber(new Apfloat("-1.00000"), new Apfloat("-1.00000")); assertEquals("-1, -1 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, -1 value", new Apfloat("0"), a); a = ApfloatMath.harmonicNumber(new Apfloat("-1.100000"), new Apfloat("-1.000000")); assertEquals("-1.1, -1 precision", 6, a.precision()); assertEquals("-1.1, -1 value", new Apfloat("0.0550000"), a, new Apfloat("5e-5")); a = ApfloatMath.harmonicNumber(new Apfloat("-4.00000"), new Apfloat("-3.00000")); assertEquals("-4, -3 precision", 6, a.precision()); assertEquals("-4, -3 value", new Apfloat("36.0000"), a, new Apfloat("5e-4")); a = ApfloatMath.harmonicNumber(new Apfloat("0.1", 21, 2), new Apfloat("0.11", 21, 2)); assertEquals("0.5, 0.75 precision", 18, a.precision()); assertEquals("0.5, 0.75 radix", 2, a.radix()); assertEquals("0.5, 0.75 value", new Apfloat("0.10010110001101010101", 18, 2), a, new Apfloat("1e-18", 1, 2)); try { ApfloatMath.harmonicNumber(new Apfloat("-1.0000"), new Apfloat("1.0000")); fail("-1, 1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.harmonicNumber(new Apfloat("-1.10000"), new Apfloat("1.10000")); fail("-1.1, 1,1 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } } public static void testPolylog() { Apfloat a = ApfloatMath.polylog(new Apfloat("3.40000"), new Apfloat("-5.60000")); assertEquals("3.4, -5.6 precision", 6, a.precision()); assertEquals("3.4, -5.6 value", new Apfloat("-4.15566"), a, new Apfloat("5e-5")); a = ApfloatMath.polylog(new Apfloat("2.00000"), new Apfloat("-3.40000")); assertEquals("2, -3.4 precision", 6, a.precision()); assertEquals("2, -3.4 value", new Apfloat("-2.11882"), a, new Apfloat("5e-5")); try { ApfloatMath.polylog(new Apfloat("3.40000"), new Apfloat("5.60000")); fail("3.4, 5.6 accepted"); } catch (ArithmeticException ae) { // OK, result would be complex } try { ApfloatMath.polylog(new Apfloat("1.00000"), new Apfloat("1.00000")); fail("1, 1 accepted"); } catch (ArithmeticException ae) { // OK, result would be infinite } try { ApfloatMath.polylog(new Apfloat("0.900000"), new Apfloat("1.00000")); fail("0.9, 1 accepted"); } catch (ArithmeticException ae) { // OK, result would be infinite } } public static void testLogisticSigmoid() { Apfloat a = ApfloatMath.logisticSigmoid(new Apfloat(4, 19)); assertEquals("4 precision", 19, a.precision()); assertEquals("4 value", new Apfloat("0.9820137900379084420"), a, new Apfloat("5e-19")); a = ApfloatMath.logisticSigmoid(new Apfloat(3000, 19)); assertEquals("3000 precision", 19, a.precision()); assertEquals("3000 value", new Apfloat("1.000000000000000000"), a, new Apfloat("5e-18")); a = ApfloatMath.logisticSigmoid(new Apfloat(-3000, 19)); assertEquals("-3000 precision", 16, a.precision()); assertEquals("-3000 value", new Apfloat("1.3078390189212504e-1303"), a, new Apfloat("5e-1319")); a = ApfloatMath.logisticSigmoid(new Apfloat("1.000000000000000000e-1000000000000000000")); assertEquals("1e-1000000000000000000 precision", 19, a.precision()); assertEquals("1e-1000000000000000000 value", new Apfloat("0.5000000000000000000"), a, new Apfloat("5e-19")); a = ApfloatMath.logisticSigmoid(new Apfloat("0")); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 value", new Aprational("1/2"), a); a = ApfloatMath.logisticSigmoid(new Apint(0, 9)); assertEquals("0 radix 9 precision", Apfloat.INFINITE, a.precision()); assertEquals("0 radix 9 radix", 9, a.radix()); assertEquals("0 radix 9 value", new Aprational("1/2", 9), a); a = ApfloatMath.logisticSigmoid(new Apfloat("0.1", 18, 2)); assertEquals("0.5 precision", 18, a.precision()); assertEquals("0.5 radix", 2, a.radix()); assertEquals("0.5 value", new Apfloat("0.10011111010110011", 18, 2), a, new Apfloat("1e-18", 1, 2)); } public static void testRandom() { long maxScale = 0; long minScale = Long.MAX_VALUE; for (int i = 0; i < 1000; i++) { Apfloat a = ApfloatMath.random(1000); maxScale = Math.max(maxScale, a.scale()); minScale = Math.min(minScale, a.scale()); } assertEquals("random max scale", 0, maxScale); assertTrue("random min scale", minScale < 0); for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { for (int i = 0; i < 100; i++) { Apfloat a = ApfloatMath.random(1, radix); assertEquals("value < 1", -1, a.compareTo(new Apfloat(1, Apfloat.INFINITE, radix))); assertTrue("value >= 0", a.signum() >= 0); } } } public static void testRandomGaussian() { Apfloat sum = Apfloat.ZERO, squareSum = Apfloat.ZERO; final int N = 1000; for (int i = 0; i < N; i++) { Apfloat a = ApfloatMath.randomGaussian(N); sum = sum.add(a); squareSum = squareSum.add(a.multiply(a)); } Apfloat n = new Apfloat(N), mean = sum.divide(n), standardDeviation = ApfloatMath.sqrt(squareSum.divide(n).subtract(mean)); assertEquals("random mean", Apfloat.ZERO, mean, new Apfloat(0.15)); assertEquals("random standard deviation", Apfloat.ONE, standardDeviation, new Apfloat(0.2)); for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { for (int i = 0; i < 100; i++) { Apfloat a = ApfloatMath.randomGaussian(1, radix); assertEquals("abs value <= 5", Apfloat.ZERO, a, new Apfloat(5, Apfloat.INFINITE, radix)); } } Apfloat a = ApfloatMath.randomGaussian(100); assertEquals("precision 1", 100, a.precision(), 7); a = ApfloatMath.randomGaussian(10); assertEquals("precision 2", 10, a.precision(), 7); a = ApfloatMath.randomGaussian(100); assertEquals("precision 3", 100, a.precision(), 7); a = ApfloatMath.randomGaussian(200); assertEquals("precision 4", 200, a.precision(), 7); } public static void testContinuedFraction() { Apfloat a = new Apfloat("3.14159"); assertEquals("3.14159, 3", Arrays.asList(new Apint(3), new Apint(7), new Apint(15)), Arrays.asList(ApfloatMath.continuedFraction(a, 3))); assertEquals("3.14159, 30", Arrays.asList(new Apint(3), new Apint(7), new Apint(15), new Apint(1)), Arrays.asList(ApfloatMath.continuedFraction(a, 30))); assertEquals("3.14159, 1", Arrays.asList(new Apint(3)), Arrays.asList(ApfloatMath.continuedFraction(a, 1))); a = new Apfloat("-3.14159"); assertEquals("-3.14159, 3", Arrays.asList(new Apint(-3), new Apint(-7), new Apint(-15)), Arrays.asList(ApfloatMath.continuedFraction(a, 3))); assertEquals("-3.14159, 30", Arrays.asList(new Apint(-3), new Apint(-7), new Apint(-15), new Apint(-1)), Arrays.asList(ApfloatMath.continuedFraction(a, 30))); try { ApfloatMath.continuedFraction(new Apfloat(2), 0); fail("Zero n allowed"); } catch (IllegalArgumentException iae) { // OK } try { ApfloatMath.continuedFraction(new Apfloat(2), Integer.MIN_VALUE); fail("Negative n allowed"); } catch (IllegalArgumentException iae) { // OK } } public static void testConvergents() { Apfloat a = new Apfloat("3.14159"); assertEquals("3.14159, 3", Arrays.asList(new Aprational(3), new Aprational("22/7"), new Aprational("333/106")), Arrays.asList(ApfloatMath.convergents(a, 3))); assertEquals("3.14159, 30", Arrays.asList(new Aprational(3), new Aprational("22/7"), new Aprational("333/106"), new Aprational("355/113")), Arrays.asList(ApfloatMath.convergents(a, 30))); assertEquals("3.14159, 1", Arrays.asList(new Aprational(3)), Arrays.asList(ApfloatMath.convergents(a, 1))); a = new Apfloat("-3.14159"); assertEquals("-3.14159, 3", Arrays.asList(new Aprational(-3), new Aprational("-22/7"), new Aprational("-333/106")), Arrays.asList(ApfloatMath.convergents(a, 3))); assertEquals("-3.14159, 30", Arrays.asList(new Aprational(-3), new Aprational("-22/7"), new Aprational("-333/106"), new Aprational("-355/113")), Arrays.asList(ApfloatMath.convergents(a, 30))); try { ApfloatMath.convergents(new Apfloat(2), 0); fail("Zero n allowed"); } catch (IllegalArgumentException iae) { // OK } try { ApfloatMath.convergents(new Apfloat(2), Integer.MIN_VALUE); fail("Negative n allowed"); } catch (IllegalArgumentException iae) { // OK } } public static void testMax() { assertEquals("max of 1 and 1", new Apfloat(1), ApfloatMath.max(new Apfloat(1), new Apfloat(1))); assertEquals("max of 1 and 2", new Apfloat(2), ApfloatMath.max(new Apfloat(1), new Apfloat(2))); assertEquals("max of 2 and 1", new Apfloat(2), ApfloatMath.max(new Apfloat(2), new Apfloat(1))); } public static void testMin() { assertEquals("min of 1 and 1", new Apfloat(1), ApfloatMath.min(new Apfloat(1), new Apfloat(1))); assertEquals("min of 1 and 2", new Apfloat(1), ApfloatMath.min(new Apfloat(1), new Apfloat(2))); assertEquals("min of 2 and 1", new Apfloat(1), ApfloatMath.min(new Apfloat(2), new Apfloat(1))); } public static void testNextAfter() { assertEquals("next after 0 and 0", new Apfloat(0), ApfloatMath.nextAfter(new Apfloat(0), new Apfloat(0))); assertEquals("next after 0 and 1", new Apfloat(0), ApfloatMath.nextAfter(new Apfloat(0), new Apfloat(1))); assertEquals("next after 0 and -1", new Apfloat(0), ApfloatMath.nextAfter(new Apfloat(0), new Apfloat(-1))); Apfloat a = ApfloatMath.nextAfter(new Apfloat("1"), new Apfloat(2)); assertEquals("next after 1. and 2", new Apfloat(2), a); assertEquals("next after 1. and 2 precision", 1, a.precision()); a = ApfloatMath.nextAfter(new Apfloat("1"), new Apfloat(0)); assertEquals("next after 1. and 0", new Apfloat(0), a); a = ApfloatMath.nextAfter(new Apfloat("-1"), new Apfloat(-2)); assertEquals("next after -1. and -2", new Apfloat(-2), a); assertEquals("next after -1. and -2 precision", 1, a.precision()); a = ApfloatMath.nextAfter(new Apfloat("-1"), new Apfloat(-1)); assertEquals("next after -1. and -1", new Apfloat(-1), a); assertEquals("next after -1. and -1 precision", 1, a.precision()); a = ApfloatMath.nextAfter(new Apfloat(1), new Apfloat(2)); assertEquals("next after 1 and 2", new Apfloat(1), a); assertEquals("next after 1 and 2 precision", Apfloat.INFINITE, a.precision()); } public static void testNextUp() { assertEquals("next up 0", new Apfloat(0), ApfloatMath.nextUp(new Apfloat(0))); Apfloat a = ApfloatMath.nextUp(new Apfloat(1)); assertEquals("next up 1", new Apfloat(1), a); assertEquals("next up 1 precision", Apfloat.INFINITE, a.precision()); a = ApfloatMath.nextUp(new Apfloat("1.")); assertEquals("next up 1.", new Apfloat(2), a); assertEquals("next up 1. precision", 1, a.precision()); a = ApfloatMath.nextUp(new Apfloat("1.0")); assertEquals("next up 1.0", new Apfloat("1.1"), a); assertEquals("next up 1.0 precision", 2, a.precision()); a = ApfloatMath.nextUp(new Apfloat("0.9")); assertEquals("next up 0.9", new Apfloat("1.0"), a); assertEquals("next up 0.9 precision", 2, a.precision()); a = ApfloatMath.nextUp(new Apfloat("0.1")); assertEquals("next up 0.1", new Apfloat("0.2"), a); assertEquals("next up 0.1 precision", 1, a.precision()); a = ApfloatMath.nextUp(new Apfloat("10")); assertEquals("next up 10.", new Apfloat("11"), a); assertEquals("next up 10. precision", 2, a.precision()); a = ApfloatMath.nextUp(new Apfloat("1e1")); assertEquals("next up 1e1", new Apfloat("2e1"), a); assertEquals("next up 1e1 precision", 1, a.precision()); a = ApfloatMath.nextUp(new Apfloat("-1e1")); assertEquals("next up -1e1", new Apfloat(0), a); assertEquals("next up -1e1 precision", Apfloat.INFINITE, a.precision()); a = ApfloatMath.nextUp(new Apfloat("1.a", 2, 11)); assertEquals("next up 1.a", new Apfloat("2.0", 2, 11), a); assertEquals("next up 1.a precision", 2, a.precision()); assertEquals("next up 1.a radix", 11, a.radix()); a = ApfloatMath.nextUp(new Apfloat("1e-9000000000000000000")); assertEquals("next up 1e-9000000000000000000", new Apfloat("2e-9000000000000000000"), a); assertEquals("next up 1e-9000000000000000000 precision", 1, a.precision()); a = ApfloatMath.nextUp(new Apfloat("1e-9000000000000000000", 9000000000000000000L)); assertEquals("next up 1e-9000000000000000000.000...", new Apfloat("1e-9000000000000000000"), a); assertEquals("next up 1e-9000000000000000000.000... precision", 9000000000000000000L, a.precision()); a = ApfloatMath.nextUp(new Apfloat("1e-4611686018427387904", 4611686018427387904L)); assertEquals("next up 1e-4611686018427387904.000...", new Apfloat("1e-4611686018427387904"), a); assertEquals("next up 1e-4611686018427387904.000... precision", 4611686018427387904L, a.precision()); a = ApfloatMath.nextUp(new Apfloat("1e-4611686018427387905", 4611686018427387904L)); assertEquals("next up 1e-4611686018427387905.000...", new Apfloat("1e-4611686018427387905"), a); assertEquals("next up 1e-4611686018427387905.000... precision", 4611686018427387904L, a.precision()); a = ApfloatMath.nextUp(new Apfloat("1e-4611686018427387906", 4611686018427387904L)); assertEquals("next up 1e-4611686018427387906.000...", new Apfloat("1e-4611686018427387906"), a); assertEquals("next up 1e-4611686018427387906.000... precision", 4611686018427387904L, a.precision()); } public static void testNextDown() { assertEquals("next down 0", new Apfloat(0), ApfloatMath.nextDown(new Apfloat(0))); Apfloat a = ApfloatMath.nextDown(new Apfloat(1)); assertEquals("next down 1", new Apfloat(1), a); assertEquals("next down 1 precision", Apfloat.INFINITE, a.precision()); a = ApfloatMath.nextDown(new Apfloat("1")); assertEquals("next down 1.", new Apfloat(0), a); assertEquals("next down 1. precision", Apfloat.INFINITE, a.precision()); a = ApfloatMath.nextDown(new Apfloat("1.0")); assertEquals("next down 1.0", new Apfloat("0.9"), a); assertEquals("next down 1.0 precision", 1, a.precision()); a = ApfloatMath.nextDown(new Apfloat("1.1")); assertEquals("next down 1.1", new Apfloat("1.0"), a); assertEquals("next down 1.1 precision", 2, a.precision()); a = ApfloatMath.nextDown(new Apfloat("0.1")); assertEquals("next down 0.1", new Apfloat(0), a); assertEquals("next down 0.1 precision", Apfloat.INFINITE, a.precision()); a = ApfloatMath.nextDown(new Apfloat("0.2")); assertEquals("next down 0.2", new Apfloat("0.1"), a); assertEquals("next down 0.2 precision", 1, a.precision()); a = ApfloatMath.nextDown(new Apfloat("10")); assertEquals("next down 10.", new Apfloat("9"), a); assertEquals("next down 10. precision", 1, a.precision()); a = ApfloatMath.nextDown(new Apfloat("1e1")); assertEquals("next down 1e1", new Apfloat(0), a); assertEquals("next down 1e1 precision", Apfloat.INFINITE, a.precision()); a = ApfloatMath.nextDown(new Apfloat("-1e1")); assertEquals("next down -1e1", new Apfloat("-2e1"), a); assertEquals("next down -1e1 precision", 1, a.precision()); a = ApfloatMath.nextDown(new Apfloat("1.a", 2, 11)); assertEquals("next down 1.a", new Apfloat("1.9", 2, 11), a); assertEquals("next down 1.a precision", 2, a.precision()); assertEquals("next down 1.a radix", 11, a.radix()); a = ApfloatMath.nextDown(new Apfloat("1e-9000000000000000000")); assertEquals("next down 1e-9000000000000000000", new Apfloat(0), a); assertEquals("next down 1e-9000000000000000000 precision", Apfloat.INFINITE, a.precision()); a = ApfloatMath.nextDown(new Apfloat("1e-9000000000000000000", 9000000000000000000L)); assertEquals("next down 1e-9000000000000000000.000", new Apfloat("1e-9000000000000000000"), a); assertEquals("next down 1e-9000000000000000000.000 precision", 9000000000000000000L, a.precision()); } public static void testUlp() { assertEquals("ulp 0", new Apfloat(0), ApfloatMath.ulp(new Apfloat(0))); assertEquals("ulp 0 radix", 12, ApfloatMath.ulp(new Apfloat(0, 1, 12)).radix()); Apfloat a = ApfloatMath.ulp(new Apfloat(1)); assertEquals("ulp 1", new Apfloat(0), a); assertEquals("ulp 1 precision", Apfloat.INFINITE, a.precision()); a = ApfloatMath.ulp(new Apfloat("1")); assertEquals("ulp 1.", new Apfloat("1"), a); assertEquals("ulp 1. precision", 1, a.precision()); a = ApfloatMath.ulp(new Apfloat("1.0")); assertEquals("ulp 1.0", new Apfloat("0.1"), a); assertEquals("ulp 1.0 precision", 1, a.precision()); a = ApfloatMath.ulp(new Apfloat("1.1")); assertEquals("ulp 1.1", new Apfloat("0.1"), a); assertEquals("ulp 1.1 precision", 1, a.precision()); a = ApfloatMath.ulp(new Apfloat("0.1")); assertEquals("ulp 0.1", new Apfloat("0.1"), a); assertEquals("ulp 0.1 precision", 1, a.precision()); a = ApfloatMath.ulp(new Apfloat("0.2")); assertEquals("ulp 0.2", new Apfloat("0.1"), a); assertEquals("ulp 0.2 precision", 1, a.precision()); a = ApfloatMath.ulp(new Apfloat("10")); assertEquals("ulp 10.", new Apfloat("1"), a); assertEquals("ulp 10. precision", 1, a.precision()); a = ApfloatMath.ulp(new Apfloat("1e1")); assertEquals("ulp 1e1", new Apfloat("1e1"), a); assertEquals("ulp 1e1 precision", 1, a.precision()); a = ApfloatMath.ulp(new Apfloat("-1e1")); assertEquals("ulp -1e1", new Apfloat("1e1"), a); assertEquals("ulp -1e1 precision", 1, a.precision()); a = ApfloatMath.ulp(new Apfloat("1.a", 2, 11)); assertEquals("ulp 1.a", new Apfloat("0.1", 1, 11), a); assertEquals("ulp 1.a precision", 1, a.precision()); assertEquals("ulp 1.a radix", 11, a.radix()); a = ApfloatMath.ulp(new Apfloat("1e-9000000000000000000")); assertEquals("ulp 1e-9000000000000000000", new Apfloat("1e-9000000000000000000"), a); assertEquals("ulp 1e-9000000000000000000 precision", 1, a.precision()); a = ApfloatMath.ulp(new Apfloat("1e-9000000000000000000", 9000000000000000000L)); assertEquals("ulp 1e-9000000000000000000.000", new Apfloat(0), a); assertEquals("ulp 1e-9000000000000000000.000 precision", Apfloat.INFINITE, a.precision()); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ApfloatTest.java000066400000000000000000001752041461767713300246760ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.BigInteger; import java.math.BigDecimal; import java.io.PushbackReader; import java.io.Writer; import java.io.StringReader; import java.io.StringWriter; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; import java.util.Formatter; import java.util.Locale; import junit.framework.TestSuite; /** * @version 1.11.1 * @author Mikko Tommila */ public class ApfloatTest extends ApfloatTestCase { public ApfloatTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApfloatTest("testLongConstructor")); suite.addTest(new ApfloatTest("testFloatConstructor")); suite.addTest(new ApfloatTest("testDoubleConstructor")); suite.addTest(new ApfloatTest("testStringConstructor")); suite.addTest(new ApfloatTest("testStreamConstructor")); suite.addTest(new ApfloatTest("testBigIntegerConstructor")); suite.addTest(new ApfloatTest("testBigDecimalConstructor")); suite.addTest(new ApfloatTest("testComplexMethods")); suite.addTest(new ApfloatTest("testRadix")); suite.addTest(new ApfloatTest("testPrecision")); suite.addTest(new ApfloatTest("testScale")); suite.addTest(new ApfloatTest("testSize")); suite.addTest(new ApfloatTest("testIsInteger")); suite.addTest(new ApfloatTest("testNegate")); suite.addTest(new ApfloatTest("testAdd")); suite.addTest(new ApfloatTest("testSubtract")); suite.addTest(new ApfloatTest("testMultiply")); suite.addTest(new ApfloatTest("testDivide")); suite.addTest(new ApfloatTest("testMod")); suite.addTest(new ApfloatTest("testFloor")); suite.addTest(new ApfloatTest("testCeil")); suite.addTest(new ApfloatTest("testTruncate")); suite.addTest(new ApfloatTest("testFrac")); suite.addTest(new ApfloatTest("testRoundAway")); suite.addTest(new ApfloatTest("testAbs")); suite.addTest(new ApfloatTest("testCompareToHalf")); suite.addTest(new ApfloatTest("testNumberValues")); suite.addTest(new ApfloatTest("testNumberValuesExact")); suite.addTest(new ApfloatTest("testEqualDigits")); suite.addTest(new ApfloatTest("testCompareTo")); suite.addTest(new ApfloatTest("testEquals")); suite.addTest(new ApfloatTest("testTest")); suite.addTest(new ApfloatTest("testHashCode")); suite.addTest(new ApfloatTest("testToString")); suite.addTest(new ApfloatTest("testWriteTo")); suite.addTest(new ApfloatTest("testFormatTo")); suite.addTest(new ApfloatTest("testSerialization")); return suite; } public static void testLongConstructor() { Apfloat a = new Apfloat(5); assertEquals("5 radix", 10, a.radix()); assertEquals("5 precision", Apfloat.INFINITE, a.precision()); assertEquals("5 String", "5", a.toString(true)); a = new Apfloat(6, Apfloat.DEFAULT); assertEquals("6 radix", 10, a.radix()); assertEquals("6 precision", Apfloat.INFINITE, a.precision()); assertEquals("6 String", "6", a.toString(true)); a = new Apfloat(7, Apfloat.DEFAULT, 12); assertEquals("7 radix", 12, a.radix()); assertEquals("7 precision", Apfloat.INFINITE, a.precision()); assertEquals("7 String", "7", a.toString(true)); assertEquals("7 imag radix", 12, a.imag().radix()); try { new Apfloat(1, 1, Character.MIN_RADIX - 1); fail("Radix 1 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat(1, 1, Character.MAX_RADIX + 1); fail("Radix 37 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat(1, 0); fail("Precision 0 allowed"); } catch (IllegalArgumentException iae) { // OK: invalid precision } } public static void testFloatConstructor() { Apfloat a = new Apfloat(5.0f); assertEquals("5 radix", 10, a.radix()); assertEquals("5 precision", 8, a.precision()); assertEquals("5 String", "5", a.toString(true)); a = new Apfloat(6.0f, Apfloat.DEFAULT); assertEquals("6 radix", 10, a.radix()); assertEquals("6 precision", 8, a.precision()); assertEquals("6 String", "6", a.toString(true)); a = new Apfloat(7.0f, Apfloat.DEFAULT, 12); assertEquals("7 radix", 12, a.radix()); assertEquals("7 precision", 7, a.precision()); assertEquals("7 String", "7", a.toString(true)); try { new Apfloat(1.0f, 1, Character.MIN_RADIX - 1); fail("Radix 1 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat(1.0f, 1, Character.MAX_RADIX + 1); fail("Radix 37 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat(1.0f, 0); fail("Precision 0 allowed"); } catch (IllegalArgumentException iae) { // OK: invalid precision } } public static void testDoubleConstructor() { Apfloat a = new Apfloat(5.0); assertEquals("5 radix", 10, a.radix()); assertEquals("5 precision", 16, a.precision()); assertEquals("5 String", "5", a.toString(true)); a = new Apfloat(6.0, Apfloat.DEFAULT); assertEquals("6 radix", 10, a.radix()); assertEquals("6 precision", 16, a.precision()); assertEquals("6 String", "6", a.toString(true)); a = new Apfloat(7.0, Apfloat.DEFAULT, 12); assertEquals("7 radix", 12, a.radix()); assertEquals("7 precision", 15, a.precision()); assertEquals("7 String", "7", a.toString(true)); a = new Apfloat(-9.999999999999996E-10); // Internally causes strange round-off errors assertEquals("-9.999999999999996E-10 precision", 16, a.precision()); a = new Apfloat(0.33333333333333333, 14); assertEquals("0.3 size 14", 14, a.size()); try { new Apfloat(1.0, 1, Character.MIN_RADIX - 1); fail("Radix 1 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat(1.0, 1, Character.MAX_RADIX + 1); fail("Radix 37 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat(1.0, 0); fail("Precision 0 allowed"); } catch (IllegalArgumentException iae) { // OK: invalid precision } } public static void testStringConstructor() { Apfloat a = new Apfloat("5"); assertEquals("5 radix", 10, a.radix()); assertEquals("5 precision", 1, a.precision()); assertEquals("5 String", "5", a.toString(true)); a = new Apfloat("99", Apfloat.DEFAULT); assertEquals("99 radix", 10, a.radix()); assertEquals("99 precision", 2, a.precision()); assertEquals("99 String", "99", a.toString(true)); a = new Apfloat("aa", Apfloat.DEFAULT, 12); assertEquals("aa radix", 12, a.radix()); assertEquals("aa precision", 2, a.precision()); assertEquals("aa String", "aa", a.toString(true)); a = new Apfloat("१२३४५६"); assertEquals("localized", "123456", a.toString(true)); try { new Apfloat("1", 1, Character.MIN_RADIX - 1); fail("Radix 1 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat("1", 1, Character.MAX_RADIX + 1); fail("Radix 37 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat("1", 0); fail("Precision 0 allowed"); } catch (IllegalArgumentException iae) { // OK: invalid precision } try { new Apfloat("1e" + (0x8000000000000000L - 100), 1, 2); fail("Overflow allowed"); } catch (OverflowException iae) { // OK: overflow } } public static void testStreamConstructor() throws IOException { PushbackReader in = new PushbackReader(new StringReader("5")); Apfloat a = new Apfloat(in); assertEquals("5 radix", 10, a.radix()); assertEquals("5 precision", 1, a.precision()); assertEquals("5 String", "5", a.toString(true)); in = new PushbackReader(new StringReader("99a")); a = new Apfloat(in, Apfloat.DEFAULT); assertEquals("99 radix", 10, a.radix()); assertEquals("99 precision", 2, a.precision()); assertEquals("99 String", "99", a.toString(true)); in = new PushbackReader(new StringReader("aa")); a = new Apfloat(in, Apfloat.DEFAULT, 12); assertEquals("aa radix", 12, a.radix()); assertEquals("aa precision", 2, a.precision()); assertEquals("aa String", "aa", a.toString(true)); in = new PushbackReader(new StringReader("00099.000")); a = new Apfloat(in, Apfloat.DEFAULT); assertEquals("00099.000 radix", 10, a.radix()); assertEquals("00099.000 precision", 5, a.precision()); assertEquals("00099.000 String", "99", a.toString(true)); in = new PushbackReader(new StringReader("990.0")); a = new Apfloat(in, Apfloat.DEFAULT); assertEquals("990.0 radix", 10, a.radix()); assertEquals("990.0 precision", 4, a.precision()); assertEquals("990.0 String", "990", a.toString(true)); try { in = new PushbackReader(new StringReader("0")); new Apfloat(in, 1, Character.MIN_RADIX - 1); fail("Radix 1 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { in = new PushbackReader(new StringReader("0")); new Apfloat(in, 1, Character.MAX_RADIX + 1); fail("Radix 37 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { in = new PushbackReader(new StringReader("0")); new Apfloat(in, 0); fail("Precision 0 allowed"); } catch (IllegalArgumentException iae) { // OK: invalid precision } try { in = new PushbackReader(new StringReader("9.9e9223372036854775807")); new Apfloat(in); fail("Overflow allowed"); } catch (NumberFormatException nfe) { // OK: should overflow } try { in = new PushbackReader(new StringReader("9.9e9223372036854775707")); new Apfloat(in); fail("Overflow allowed"); } catch (NumberFormatException | OverflowException e) { // OK: should overflow } } public static void testBigIntegerConstructor() { Apfloat a = new Apfloat(BigInteger.valueOf(5)); assertEquals("5 radix", 10, a.radix()); assertEquals("5 precision", Apfloat.INFINITE, a.precision()); assertEquals("5 String", "5", a.toString(true)); a = new Apfloat(BigInteger.valueOf(-6), Apfloat.DEFAULT); assertEquals("-6 radix", 10, a.radix()); assertEquals("-6 precision", Apfloat.INFINITE, a.precision()); assertEquals("-6 String", "-6", a.toString(true)); a = new Apfloat(BigInteger.valueOf(7), Apfloat.DEFAULT, 12); assertEquals("7 radix", 12, a.radix()); assertEquals("7 precision", Apfloat.INFINITE, a.precision()); assertEquals("7 String", "7", a.toString(true)); a = new Apfloat(BigInteger.valueOf(99999999999999L)); assertEquals("99999999999999 radix", 10, a.radix()); assertEquals("99999999999999 precision", Apfloat.INFINITE, a.precision()); assertEquals("99999999999999 String", "99999999999999", a.toString(true)); a = new Apfloat(BigInteger.valueOf(-99999999999999L)); assertEquals("-99999999999999 radix", 10, a.radix()); assertEquals("-99999999999999 precision", Apfloat.INFINITE, a.precision()); assertEquals("-99999999999999 String", "-99999999999999", a.toString(true)); a = new Apfloat(BigInteger.valueOf(999999999999999L)); assertEquals("999999999999999 radix", 10, a.radix()); assertEquals("999999999999999 precision", Apfloat.INFINITE, a.precision()); assertEquals("999999999999999 String", "999999999999999", a.toString(true)); a = new Apfloat(BigInteger.valueOf(-999999999999999L)); assertEquals("-999999999999999 radix", 10, a.radix()); assertEquals("-999999999999999 precision", Apfloat.INFINITE, a.precision()); assertEquals("-999999999999999 String", "-999999999999999", a.toString(true)); try { new Apfloat(BigInteger.valueOf(5), 1, Character.MIN_RADIX - 1); fail("Radix 1 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat(BigInteger.valueOf(5), 1, Character.MAX_RADIX + 1); fail("Radix 37 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { new Apfloat(BigInteger.valueOf(5), 0); fail("Precision 0 allowed"); } catch (IllegalArgumentException iae) { // OK: invalid precision } } public static void testBigDecimalConstructor() { Apfloat a = new Apfloat(new BigDecimal("5")); assertEquals("5 radix", 10, a.radix()); assertEquals("5 precision", 1, a.precision()); assertEquals("5 String", "5", a.toString(true)); a = new Apfloat(new BigDecimal("6"), Apfloat.DEFAULT); assertEquals("6 radix", 10, a.radix()); assertEquals("6 precision", 1, a.precision()); assertEquals("6 String", "6", a.toString(true)); a = new Apfloat(new BigDecimal("1.23e7")); assertEquals("1.23e7 radix", 10, a.radix()); assertEquals("1.23e7 precision", 3, a.precision()); assertEquals("1.23e7 String", "1.23e7", a.toString()); try { new Apfloat(new BigDecimal("5"), 0); fail("Precision 0 allowed"); } catch (IllegalArgumentException iae) { // OK: invalid precision } } public static void testComplexMethods() { Apfloat a = new Apfloat(5); assertEquals("real", a, a.real()); assertEquals("imag", Apfloat.ZERO, a.imag()); } public static void testRadix() { Apfloat a = new Apfloat(2, 500, 5); assertEquals("radix", 5, a.radix()); a = new Apfloat(65535); assertEquals("65535 10 -> 16", new Apfloat("FFFF", Apfloat.INFINITE, 16), a.toRadix(16)); assertEquals("65535 10 -> 16 precision", Apfloat.INFINITE, a.toRadix(16).precision()); a = new Apfloat("65535.50"); assertEquals("65535.5 10 -> 16", new Apfloat("FFFF.8", Apfloat.INFINITE, 16), a.toRadix(16)); a = new Apfloat("65535.25"); assertEquals("65535.25 10 -> 16", new Apfloat("FFFF.4", Apfloat.INFINITE, 16), a.toRadix(16)); a = new Apfloat("65535.125"); assertEquals("65535.125 10 -> 16", new Apfloat("FFFF.2", Apfloat.INFINITE, 16), a.toRadix(16)); a = new Apfloat("123000000000"); assertEquals("123000000000 10 -> 16", new Apfloat("1CA35F0E00", Apfloat.INFINITE, 16), a.toRadix(16)); assertEquals("123000000000 10 -> 16 precision", 9, a.toRadix(16).precision()); a = new Apfloat("0.000000000931322574615478515625"); assertEquals("0.000000000931322574615478515625 10 -> 16", new Apfloat("0.00000004", Apfloat.INFINITE, 16), a.toRadix(16), new Apfloat("0.000000000000000000000001", Apfloat.INFINITE, 16)); assertEquals("0.000000000931322574615478515625 10 -> 16 precision", 17, a.toRadix(16).precision()); assertEquals("0", Apfloat.ZERO, Apfloat.ZERO.toRadix(16)); a = new Apfloat(1, 1, 2); assertEquals("1 2 -> 36", new Apfloat(1, 1, 36), a.toRadix(36)); assertEquals("1 2 -> 36 precision", 1, a.toRadix(36).precision()); a = new Apfloat(1, Long.MAX_VALUE - 1000000000, 36); assertEquals("1 36 -> 2", new Apfloat(1, Apfloat.INFINITE, 2), a.toRadix(2)); assertEquals("1 36 -> 2 precision", Apfloat.INFINITE, a.toRadix(2).precision()); a = new Apfloat("30663651432036134110263402244652226643520650240155443215426431025161154565220002622436103301443233631011304100550041024125352116552105536251503033124242402610043630564530526330241326140210045006340104466521000354000404111331215235323543345406426461100254233215013111611145330503541442000526254312414615064636661250340621566513342655053121614145360201046310465243314220526011154664430043014201423420324045214415130132414620525166152443345045032350015230030362164454610650213462563452443511056450311105.22332541403314616306305566400025124136353353135500314364221261503410163015234165116544562313163301340550004143332123320511041210402240503346501010222303304655116161250452506544564304213630542260560421643101224533463224115516324432200114053015605444210505633501042351630165624443056253363046253533144415643620525422651636016443512214133340311231201415424110210002660121216352350661533034035553261641500660122112023312140250433042514535345621255544000222315031426131123345316551523042065315342155413506", 1000, 7); assertEquals("pi*7^499 7 -> 36", new Apfloat("2rv02k6m9ibha286eemjtdx59crclwjbkxum8hn0nc2eaj8u4fbltf547z5lqh4g0euy4p9wo0u5h3iza23atp64rirlqk9xvck8u1s2w4efuhhg3mjkhrpd8rx7hqgxgqadotv3gzun0elz30tlwrnrm8ydc8syy06a88yfdmgt37ee5gok338r2vwfhr6a5ifka3bv75xvardxighwf0r1o6sgtdsh9ynno3k0ug1u56s17ajcaj8lsox1dw02lyjk4vvi8u8atao1.c4cr2sltzlqouiqpz54wugysq73j65kwm4xlny74dwtxlmquu7l40nltbbhhyw40f6075p1pt8joyggssiri3x4151kai4hslu24fha924duoenty0w6ar6ivz92x51nbtot8n6pyxmbfomd4ph8nstk0fyy0hmawmf2c310s3dztsi7amyexdgoa7jobl4aigqexsqddwkshtfvo71l2omiomph837ocwaprkx9bm91a2mnx39e1uo7k8sca59ezhr1kqcrfh7olwt", 543, 36), a.toRadix(36), ApfloatMath.scale(new Apfloat(1, 1, 36), -271)); assertEquals("pi*7^499 7 -> 36 precision", 543, a.toRadix(36).precision()); a = new Apfloat("3184809493b918664573a6211bb151551a05729290a7809a492742140a60a55256a0661a03753a3aa54805646880181a3683083272bbba0a370b12265529a828903b4b256b8403759a71626b8a54687621849b849a8225616b442796a31737b229b2391489853943b8763725616447236b027a421aa17a38b52a18a838b01514a51144a23315a3009a8906b61b8b48a62253a88a50a43ba0944572315933664476b3aabb77583975120683526b75b462060bb03b432551913772729a2147553531793848a0402b999b5058535374465a68806716644039539a8431935198527b9399b112990abb0383b107645424577a51601b3624a88b7a676a.3992912121a213887b92873946a61332242217aa7354115357744939112602ba4b888818a3269222b528487747839994ab223b65b8762695422822669ba00a586097842a51750362073b5a768363b21bb1a97a4a194447749399804922175a068a46739461990a2065bb0a30bbab7024a585b1a84428195489784a07a331a7b0a1574565b373b05b03a5a80a13ab87857734679985558a5373178a7b28271992a3894a5776085083b9b238b2220542462888641a2bab8b3083ab49659172a312b78518654494a068662586a181835a64440b2970a122813975898815367208905801032881449223841428763329617531239b9a657405584014", 1000, 12); assertEquals("pi*7^499 12 -> 2", new Apfloat("101110110001110110000110100110001111010111001001000010110000010100110010101011001011010011000101011110110000111110011111101101110000111101010111000111101000101100010100011111011110101001011111111111101110000100101011110010011111001001110101010110111000110011111010000000001011011101111001110001110011011101011110100100010110000001001100000110110011011100111111011011011110010111001000010101110001100110110001101001010000110100110101111110101011110001001000100110110000110110001111110010100111110000110010001110111100000001000101000010101100110111111101110001101100100110010111000101010010001011111110110001111001011100011010001010101110101111010101010100001100000001110110100000110001001000111110011101001110101110000010000101001110000101101111011010000011110100110011011011111011101000110110011010101001001010000000101010000101101010111110111011010011110110111001111111111010011111000110011101110011111101111000110010101011010101000100100000011011001101110001000011010111111110110011000110100101111010011011100011101001001100001100100100011110001111100110010101001101100111010001010011111010101110111110101110000001000100011100001010110011000101010010110100101111101110110000010111101100010100000001101010111000001100100001000001011000100001001111110000111100111011010111001100111101000010000010101001001110011110011110001011110110001111000010011001110011000001001101011111000010110101010100101101001001001001111110000101000000010110111000010000101000101110010010101001100001010011010111011110010100101101010100110100100110100100001101000011101110100100010101100111110101000110010010011110011000100001111100001000011110001011011010000110010101111000011001010100101011001101011100111001100001101011010101011100001111000100111101100110010100100100111100100110000000101011010010001101011000010.01010001010111100000110011101100000011110100100010011101001100001011010000101001001100000111001001100001000000100110100001011001001010110011100011111000001110001101110110101010101010101001010000011101010110011000111101010100000011000010101001101011100000001110000011101100011100111110100001110110010111011001000100000000001100100100100011100101000111010011001011000101010001001101101001111101011100101001110100001101010101011011000001101000111011010101101001010011010111011011011000101101010010101110000000000001011110000010000100011010001001010101001011010110000100000100101011111011101110000001110101101001101111100011111110100000100111001100001010100100101000100100101011111100110001000110010001110100111110011000111101111101110111000001110000001001100101101100001111010100100110011000000010100010110100010010111101010010000010011011010101010101110010100100000010100111101100000111111111100100011000101000010010011111100110001011000010000101001111111111011111101010011101101101101100111101000101111001101000010110101000101100100100110101101001000000001011001000111100001000111000011011101010111010011001011111101111101110111010001000100101110100110011111101000111010100011101110100100011001000101100100000001000001110000001010011101110101110011111000000000001001101001011111000010111110100100010010101001000011000110111100010100111011111010100110010010100111101110011011110010100100001000111100111111101111110000011000111111110001000100010101000000001011110110010111011111111000001001111010001100111010110100010001110011100110110000011110100001010010000010011000011010110001011101110001011101110110011010001101111011111001101110100010101001110101110101000111100101100101110011101011111001001111010101110101110001010110000101000101011100110010110010111001110101111000100100111101101101101001", 3584, 2), a.toRadix(2), new Apfloat("1e-1793", 1, 2)); assertEquals("pi*7^499 12 -> 2 precision", 3584, a.toRadix(2).precision()); a = new Apfloat("1e1000000000", 10); assertEquals("1e1000000000 10 -> 8", new Apfloat("7.3142764265e1107309364", 11, 8), a.toRadix(8), new Apfloat("0.0000000001e1107309364", 1, 8)); for (int fromRadix = Character.MIN_RADIX; fromRadix <= Character.MAX_RADIX; fromRadix++) { for (int toRadix = Character.MIN_RADIX; toRadix <= Character.MAX_RADIX; toRadix++) { final int LENGTH = 1000; StringBuilder buffer = new StringBuilder(LENGTH); for (int i = 0; i < LENGTH; i++) { buffer.append(Character.forDigit(fromRadix - 1, fromRadix)); } Apfloat actual = new Apfloat(buffer.toString(), Apfloat.INFINITE, fromRadix).toRadix(toRadix), expected = ApfloatMath.pow(new Apfloat(fromRadix, Apfloat.INFINITE, toRadix), LENGTH).subtract(new Apfloat(1, Apfloat.INFINITE, toRadix)); assertEquals("999...999 " + fromRadix + " -> " + toRadix, expected, actual); } } try { a.toRadix(Character.MIN_RADIX - 1); fail("To radix 1 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } try { a.toRadix(Character.MAX_RADIX + 1); fail("To radix 37 allowed"); } catch (NumberFormatException nfe) { // OK: invalid radix } } public static void testPrecision() { Apfloat a = new Apfloat(5, 5); assertEquals("5 precision", 5, a.precision()); a = a.precision(4); assertEquals("4 precision", 4, a.precision()); a = a.precision(6); assertEquals("6 precision", 6, a.precision()); a = new Apfloat(0); assertEquals("0 precision", Apfloat.INFINITE, a.precision()); } public static void testScale() { Apfloat a = new Apfloat(9); assertEquals("9 scale", 1, a.scale()); a = new Apfloat(10); assertEquals("10 scale", 2, a.scale()); a = new Apfloat(0); assertEquals("0 scale", -Apfloat.INFINITE, a.scale()); a = new Apfloat(9); assertEquals("9 scaled 1", new Apfloat(90), a.scale(1)); assertEquals("9 scaled -1", new Apfloat("0.9"), a.scale(-1)); } public static void testSize() { Apfloat a = new Apfloat(9); assertEquals("9 size", 1, a.size()); a = new Apfloat(1); assertEquals("1 size", 1, a.size()); a = new Apfloat(10); assertEquals("10 size", 1, a.size()); a = new Apfloat(99); assertEquals("99 size", 2, a.size()); a = new Apfloat(110); assertEquals("110 size", 2, a.size()); a = new Apfloat("0.11"); assertEquals("0.11 size", 2, a.size()); a = new Apfloat("-0.00123456789"); assertEquals("-0.00123456789 size", 9, a.size()); a = new Apfloat(9909, 2); assertEquals("9909 prec 2 size", 2, a.size()); a = new Apfloat(9999, 2); assertEquals("9999 prec 2 size", 2, a.size()); a = new Apfloat(999999999999999L); assertEquals("999999999999999 size", 15, a.size()); a = new Apfloat(999999999999990L); assertEquals("999999999999990 size", 14, a.size()); a = new Apfloat(999999999999900L); assertEquals("999999999999900 size", 13, a.size()); a = new Apfloat(999999999999000L); assertEquals("999999999999000 size", 12, a.size()); a = new Apfloat(999999999990000L); assertEquals("999999999990000 size", 11, a.size()); a = new Apfloat(999999999900000L); assertEquals("999999999900000 size", 10, a.size()); a = new Apfloat(999999999000000L); assertEquals("999999999000000 size", 9, a.size()); a = new Apfloat(999999990000000L); assertEquals("999999990000000 size", 8, a.size()); a = new Apfloat(999999900000000L); assertEquals("999999900000000 size", 7, a.size()); a = new Apfloat(999999000000000L); assertEquals("999999000000000 size", 6, a.size()); a = new Apfloat(999990000000000L); assertEquals("999990000000000 size", 5, a.size()); a = new Apfloat(999900000000000L); assertEquals("999900000000000 size", 4, a.size()); a = new Apfloat(999000000000000L); assertEquals("999000000000000 size", 3, a.size()); a = new Apfloat(990000000000000L); assertEquals("990000000000000 size", 2, a.size()); a = new Apfloat(900000000000000L); assertEquals("900000000000000 size", 1, a.size()); a = new Apfloat(0); assertEquals("0 size", 0, a.size()); a = new Apfloat("1.1e-1000000", Apfloat.INFINITE - 1); assertEquals("1.1e-1000000 precision infinite-1 size", 2, a.size()); a = new Apfloat("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"); assertEquals("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 size", 100, a.size()); a = a.precision(99); assertEquals("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 prec 99 size", 1, a.size()); a = a.precision(90); assertEquals("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001 prec 90 size", 1, a.size()); a = new Apfloat("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001"); a = a.precision(99); assertEquals("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001 prec 99 size", 90, a.size()); a = new Apfloat("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001"); a = a.precision(90); assertEquals("1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001 prec 90 size", 90, a.size()); a = new Apfloat("11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001"); a = a.precision(1); assertEquals("11000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000001 prec 1 size", 1, a.size()); } public static void testIsInteger() { Apfloat a = new Apfloat("1.5"); assertFalse("1.5", a.isInteger()); a = new Apfloat("-0.1"); assertFalse("-0.1", a.isInteger()); a = new Apfloat("1"); assertTrue("1", a.isInteger()); a = new Apfloat("0"); assertTrue("0", a.isInteger()); a = new Apfloat(-1); assertTrue("-1", a.isInteger()); a = new Apfloat("1e1000000"); assertTrue("1e1000000", a.isInteger()); } public static void testNegate() { Apfloat x = new Apfloat(2); assertEquals("2", new Apfloat(-2), x.negate()); x = new Apfloat(-2); assertEquals("-2", new Apfloat(2), x.negate()); x = new Apfloat(0); assertEquals("0", new Apfloat(0), x.negate()); Apcomplex y = new Apfloat(2); assertEquals("-2", new Apcomplex("-2"), y.negate()); } public static void testAdd() { Apfloat a = new Apfloat(4), b = new Apfloat(5); assertEquals("4 + 5", new Apfloat(9), a.add(b)); assertEquals("4 + 0", new Apfloat(4), a.add(new Apfloat(0))); assertEquals("0 + 4", new Apfloat(4), new Apfloat(0).add(a)); a = new Apfloat("1"); b = new Apfloat("0.00001"); assertEquals("1 + 0.00001", new Apfloat(1), a.add(b), b); assertEquals("0.00001 + 1", new Apfloat(1), b.add(a), b); } public static void testSubtract() { Apfloat a = new Apfloat(4), b = new Apfloat(5); assertEquals("4 - 5", new Apfloat(-1), a.subtract(b)); assertEquals("4 - 0", new Apfloat(4), a.subtract(new Apfloat(0))); assertEquals("0 - 4", new Apfloat(-4), new Apfloat(0).subtract(a)); a = new Apfloat("1"); b = new Apfloat("0.00001"); assertEquals("1 - 0.00001", new Apfloat(1), a.subtract(b), b); assertEquals("0.00001 - 1", new Apfloat(-1), b.subtract(a), b); } public static void testMultiply() { Apfloat a = new Apfloat(4, Apfloat.INFINITE, 12), b = new Apfloat(5, Apfloat.INFINITE, 12); assertEquals("4 * 5", new Apfloat(20, Apfloat.DEFAULT, 12), a.multiply(b)); assertEquals("4 * 0", new Apfloat(0), a.multiply(new Apfloat(0))); assertEquals("0 * 4", new Apfloat(0), new Apfloat(0).multiply(a)); assertEquals("4 * 1", new Apfloat(4, Apfloat.DEFAULT, 12), a.multiply(new Apfloat(1, Apfloat.DEFAULT, 12))); assertEquals("1 * 4", new Apfloat(4, Apfloat.DEFAULT, 12), new Apfloat(1, Apfloat.DEFAULT, 12).multiply(a)); assertEquals("4 * ONE", new Apfloat(4, Apfloat.DEFAULT, 12), a.multiply(Apfloat.ONE)); assertEquals("ONE * 4", new Apfloat(4, Apfloat.DEFAULT, 12), Apfloat.ONE.multiply(a)); } public static void testDivide() { Apfloat a = new Apfloat(4, Apfloat.INFINITE, 12), b = new Apfloat(6, Apfloat.INFINITE, 12); assertEquals("4 / 6", new Apfloat("0.8", Apfloat.DEFAULT, 12), a.divide(b)); assertEquals("0 / 4", new Apfloat(0), new Apfloat(0).divide(a)); assertEquals("4 / 1", new Apfloat(4, Apfloat.INFINITE, 12), a.divide(new Apfloat(1, Apfloat.DEFAULT, 12))); assertEquals("4 / ONE", new Apfloat(4, Apfloat.INFINITE, 12), a.divide(Apfloat.ONE)); try { a.divide(new Apfloat(0)); fail("Division by zero allowed"); } catch (ArithmeticException ae) { // OK: division by zero } assertEquals("long / long", new Apfloat(1), new Apfloat("101010101010101010101010101010101010101").divide(new Apfloat("101010101010101010101010101010101010101")), new Apfloat(2e-38)); } public static void testMod() { Apfloat a = new Apfloat(4), b = new Apfloat(3); assertEquals("4 % 3", new Apfloat(1), a.mod(b)); } public static void testFloor() { Apfloat a = new Apfloat("1.1"); assertEquals("1.1 floor", new Apfloat(1), a.floor()); assertEquals("1.1 floor reverse", a.floor(), new Apfloat(1)); a = new Apfloat(1); assertEquals("1 floor", new Apfloat(1), a.floor()); a = new Apfloat("1.99999999999999"); assertEquals("1.99999999999999 floor", new Apfloat(1), a.floor()); a = new Apfloat(0); assertEquals("0 floor", new Apfloat(0), a.floor()); a = new Apfloat("-1.1"); assertEquals("-1.1 floor", new Apfloat(-2), a.floor()); } public static void testCeil() { Apfloat a = new Apfloat("1.1"); assertEquals("1.1 ceil", new Apfloat(2), a.ceil()); a = new Apfloat(1); assertEquals("1 ceil", new Apfloat(1), a.ceil()); a = new Apfloat("1.99999999999999"); assertEquals("1.99999999999999 ceil", new Apfloat(2), a.ceil()); a = new Apfloat(0); assertEquals("0 ceil", new Apfloat(0), a.ceil()); a = new Apfloat("-1.1"); assertEquals("-1.1 ceil", new Apfloat(-1), a.ceil()); } public static void testTruncate() { Apfloat a = new Apfloat("1.1"); assertEquals("1.1 truncate", new Apfloat(1), a.truncate()); a = new Apfloat(1); assertEquals("1 truncate", new Apfloat(1), a.truncate()); a = new Apfloat("1.99999999999999"); assertEquals("1.99999999999999 truncate", new Apfloat(1), a.truncate()); a = new Apfloat(0); assertEquals("0 truncate", new Apfloat(0), a.truncate()); a = new Apfloat("-1.1"); assertEquals("-1.1 truncate", new Apfloat(-1), a.truncate()); a = new Apfloat("1e" + (0x8000000000000000L - 1000), 1, 2); assertEquals("1e7FFFFFFFFFFFFF9C base 2 truncate", new Apfloat("1e" + (0x8000000000000000L - 1000), 1, 2), a.truncate()); } public static void testFrac() { Apfloat a = new Apfloat("1.1"); assertEquals("1.1 frac", new Apfloat("0.1"), a.frac()); a = new Apfloat(1); assertEquals("1 frac", new Apfloat(0), a.frac()); a = new Apfloat("1.99999999999999"); assertEquals("1.99999999999999 frac", new Apfloat("0.99999999999999"), a.frac()); a = new Apfloat(0); assertEquals("0 frac", new Apfloat(0), a.frac()); a = new Apfloat("-1.1"); assertEquals("-1.1 frac", new Apfloat("-0.1"), a.frac()); a = new Apfloat("1.01").precision(2); assertEquals("1.01 lost precision frac", new Apfloat(0), a.frac()); } public static void testRoundAway() { Apfloat a = new Apfloat("1.1"); assertEquals("1.1 roundAway", new Apfloat(2), a.roundAway()); a = new Apfloat("-1.1"); assertEquals("-1.1 roundAway", new Apfloat(-2), a.roundAway()); } public static void testAbs() { Apfloat a = new Apfloat("2"); assertEquals("2 abs", new Apfloat(2), a.abs()); a = new Apfloat(0); assertEquals("0 abs", new Apfloat(0), a.abs()); a = new Apfloat(-2); assertEquals("-2 abs", new Apfloat(2), a.abs()); } public static void testCompareToHalf() { Apfloat a = new Apfloat("0.4"); assertEquals("0.4 compareToHalf", -1, a.compareToHalf()); a = new Apfloat("0.5"); assertEquals("0.5 compareToHalf", 0, a.compareToHalf()); a = new Apfloat("0.6"); assertEquals("0.6 compareToHalf", 1, a.compareToHalf()); } public static void testNumberValues() { Apfloat a = new Apfloat(5); assertEquals("5 longValue", 5, a.longValue()); assertEquals("5 intValue", 5, a.intValue()); assertEquals("5 shortValue", 5, a.shortValue()); assertEquals("5 byteValue", 5, a.byteValue()); assertEquals("5 floatValue", 5.0f, a.floatValue(), 0.0f); assertEquals("5 doubleValue", 5.0, a.doubleValue(), 0.0); a = new Apfloat(1000000000000L); assertEquals("1000000000000 intValue", Integer.MAX_VALUE, a.intValue()); assertEquals("1000000000000 shortValue", Short.MAX_VALUE, a.shortValue()); assertEquals("1000000000000 byteValue", Byte.MAX_VALUE, a.byteValue()); a = new Apfloat(-1000000000000L); assertEquals("-1000000000000 intValue", Integer.MIN_VALUE, a.intValue()); assertEquals("-1000000000000 shortValue", Short.MIN_VALUE, a.shortValue()); assertEquals("-1000000000000 byteValue", Byte.MIN_VALUE, a.byteValue()); a = new Apfloat("1e100"); assertEquals("1e100 floatValue", Float.POSITIVE_INFINITY, a.floatValue(), 0.0f); a = new Apfloat("-1e100"); assertEquals("-1e100 floatValue", Float.NEGATIVE_INFINITY, a.floatValue(), 0.0f); a = new Apfloat("1e1000"); assertEquals("1e1000 doubleValue", Double.POSITIVE_INFINITY, a.doubleValue(), 0.0); a = new Apfloat("-1e1000"); assertEquals("-1e1000 doubleValue", Double.NEGATIVE_INFINITY, a.doubleValue(), 0.0); } public static void testNumberValuesExact() { Apfloat a = new Apfloat(5); assertEquals("5 longValueExact", 5, a.longValueExact()); assertEquals("5 intValueExact", 5, a.intValueExact()); assertEquals("5 shortValueExact", 5, a.shortValueExact()); assertEquals("5 byteValueExact", 5, a.byteValueExact()); assertEquals("MAX_VALUE longValueExact", Long.MAX_VALUE, new Apfloat(Long.MAX_VALUE).longValueExact()); assertEquals("MIN_VALUE longValueExact", Long.MIN_VALUE, new Apfloat(Long.MIN_VALUE).longValueExact()); assertEquals("MAX_VALUE intValueExact", Integer.MAX_VALUE, new Apfloat(Integer.MAX_VALUE).intValueExact()); assertEquals("MIN_VALUE intValueExact", Integer.MIN_VALUE, new Apfloat(Integer.MIN_VALUE).intValueExact()); assertEquals("MAX_VALUE shortValueExact", Short.MAX_VALUE, new Apfloat(Short.MAX_VALUE).shortValueExact()); assertEquals("MIN_VALUE shortValueExact", Short.MIN_VALUE, new Apfloat(Short.MIN_VALUE).shortValueExact()); assertEquals("MAX_VALUE byteValueExact", Byte.MAX_VALUE, new Apfloat(Byte.MAX_VALUE).byteValueExact()); assertEquals("MIN_VALUE byteValueExact", Byte.MIN_VALUE, new Apfloat(Byte.MIN_VALUE).byteValueExact()); try { new Apfloat("5.5").longValueExact(); fail("Non-integer number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat("5.5").intValueExact(); fail("Non-integer number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat("5.5").shortValueExact(); fail("Non-integer number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat("5.5").byteValueExact(); fail("Non-integer number accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat(Long.MAX_VALUE).add(new Apfloat(1)).longValueExact(); fail("Value out of range accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat(Long.MIN_VALUE).subtract(new Apfloat(1)).longValueExact(); fail("Value out of range accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat(Integer.MAX_VALUE + 1L).intValueExact(); fail("Value out of range accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat(Integer.MIN_VALUE - 1L).intValueExact(); fail("Value out of range accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat(Short.MAX_VALUE + 1L).shortValueExact(); fail("Value out of range accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat(Short.MIN_VALUE- 1L).shortValueExact(); fail("Value out of range accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat(Byte.MAX_VALUE + 1L).byteValueExact(); fail("Value out of range accepted"); } catch (ArithmeticException ae) { // OK } try { new Apfloat(Byte.MIN_VALUE - 1L).byteValueExact(); fail("Value out of range accepted"); } catch (ArithmeticException ae) { // OK } } public static void testEqualDigits() { Apfloat a = new Apfloat(5), b = new Apfloat(6); assertEquals("5 eq 6", 0, a.equalDigits(b)); a = new Apfloat(10); b = new Apfloat(11); assertEquals("10 eq 11", 1, a.equalDigits(b)); a = new Apfloat(7); b = new Apfloat(7); assertEquals("7 eq 7", Apfloat.INFINITE, a.equalDigits(b)); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static void testCompareTo() { Apfloat a = new Apfloat(0), b = new Apfloat(1); assertEquals("0 cmp 1", -1, a.compareTo(b)); a = new Apfloat(6); b = new Apfloat(5); assertEquals("6 cmp 5", 1, a.compareTo(b)); a = new Apfloat(6); b = new Apfloat(6); assertEquals("6 cmp 6", 0, a.compareTo(b)); a = new Apfloat(6); b = a.floor(); assertEquals("6 cmp 6.floor()", 0, a.compareTo(b)); Comparable o = a; assertEquals("6 cmp object 6", 0, o.compareTo(o)); try { Comparable c = a; c.compareTo("bogus"); fail("Comparison to different class allowed"); } catch (ClassCastException cce) { // OK: class can't be cast to Apfloat } } public static void testEquals() { Apfloat a = new Apfloat(0), b = new Apfloat(1); assertEquals("0 == 1", false, a.equals(b)); a = new Apfloat(6); b = new Apfloat(5); assertEquals("6 == 5", false, a.equals(b)); a = new Apfloat(6); b = new Apfloat(6); assertEquals("6 == 6", true, a.equals(b)); a = new Apfloat("1.1e-1000000"); b = new Apfloat("1.1e-1000000", Apfloat.INFINITE - 1); assertEquals("1.1e-1000000 == 1.1e-1000000 different precision", true, a.equals(b)); assertEquals("6 == something else", false, a.equals("bogus")); a = new Apfloat(0, 1, 10); b = new Apfloat(0, 1, 12); assertEquals("0 == 0 different radixes", true, a.equals(b)); a = new Apfloat(1, 1, 10); b = new Apfloat(1, 1, 12); assertEquals("1 == 1 different radixes", true, a.equals(b)); ApfloatContext ctx = (ApfloatContext) ApfloatContext.getGlobalContext().clone(); a = new Apfloat(0); b = new Apfloat(1); ctx.setBuilderFactory(new org.apfloat.internal.DoubleBuilderFactory()); ApfloatContext.setThreadContext(ctx); assertEquals("0 == 0 different implementations", true, a.equals(new Apfloat(0))); assertEquals("1 == 1 different implementations", true, b.equals(new Apfloat(1))); ApfloatContext.removeThreadContext(); } public static void testTest() { Apfloat a = new Apfloat(0), b = new Apfloat(0); assertTrue("0 test 0", a.test(b)); a = new Apfloat(0); b = new Apfloat(1); assertFalse("0 test 1", a.test(b)); a = new Apfloat(1); b = new Apfloat(0); assertFalse("1 test 0", a.test(b)); a = new Apfloat(1); b = new Apfloat(1); assertTrue("1 test 1", a.test(b)); a = new Apfloat(1); b = new Apfloat(-1); assertFalse("1 test -1", a.test(b)); a = new Apfloat(-1); b = new Apfloat(1); assertFalse("-1 test 1", a.test(b)); a = new Apfloat(1); b = new Apfloat(10); assertFalse("1 test 10", a.test(b)); a = new Apfloat(10); b = new Apfloat(1); assertFalse("10 test 1", a.test(b)); a = new Apfloat(10); b = new Apfloat(11); assertFalse("10 test 11", a.test(b)); a = new Apfloat(11); b = new Apfloat(10); assertFalse("11 test 10", a.test(b)); a = new Apfloat(1, 1); b = new Apfloat(1, 2); assertTrue("1 test 1, prec", a.test(b)); a = new Apfloat(1, 1, 10); b = new Apfloat(1, 1, 11); assertTrue("1 test 1, radix", a.test(b)); } public static void testHashCode() { Apfloat a = new Apfloat(0), b = new Apfloat(1); assertTrue("0 != 1", a.hashCode() != b.hashCode()); a = new Apfloat(6); b = new Apfloat(5); assertTrue("5 != 6", a.hashCode() != b.hashCode()); a = new Apfloat(6); b = new Apfloat(6); assertEquals("6 == 6", a.hashCode(), b.hashCode()); } public static void testToString() { Apfloat a = new Apfloat(0); assertEquals("0", "0", "" + a); a = new Apfloat(6); assertEquals("6", "6", "" + a); a = new Apfloat(123456789, 9); assertEquals("123456789", "1.23456789e8", "" + a); a = new Apfloat(123456789, 9); assertEquals("123456789 pretty", "123456789", a.toString(true)); a = new Apfloat("1.1e-1000000", Apfloat.INFINITE - 1); assertEquals("1.1e-1000000 infinite-1 precision", "1.1e-1000000", a.toString()); } public static void testWriteTo() throws IOException { StringWriter out = new StringWriter(); Apfloat a = new Apfloat(0); a.writeTo(out); a = new Apfloat(6); a.writeTo(out); a = new Apfloat(123456789, 9); a.writeTo(out); a.writeTo(out, true); assertEquals("string", "061.23456789e8123456789", out.toString()); } public static void testFormatTo() throws IOException { System.setProperty("java.locale.providers", "COMPAT,SPI"); // Required since Java 10 to have all locale providers available Locale locale = null; assertEquals("null %s", "1.234567890123456e5", String.format(locale, "%s", new Apfloat("123456.7890123456"))); assertEquals("null %S", "1.234567890123456E5", String.format(locale, "%S", new Apfloat("123456.7890123456"))); assertEquals("null %#s", "123456.7890123456", String.format(locale, "%#s", new Apfloat("123456.7890123456"))); assertEquals("null %.3s", "1.23e5", String.format(locale, "%.3s", new Apfloat("123456.7890123456"))); assertEquals("null %.20s", "1.234567890123456e5", String.format(locale, "%.20s", new Apfloat("123456.7890123456"))); assertEquals("null %20s", " 1.234567890123456e5", String.format(locale, "%20s", new Apfloat("123456.7890123456"))); assertEquals("null %-20s", "1.234567890123456e5 ", String.format(locale, "%-20s", new Apfloat("123456.7890123456"))); assertEquals("null %#20s", " 123456.7890123456", String.format(locale, "%#20s", new Apfloat("123456.7890123456"))); assertEquals("null %#-20s", "123456.7890123456 ", String.format(locale, "%#-20s", new Apfloat("123456.7890123456"))); locale = new Locale("fi", "FI"); assertEquals("fi_FI %s", "1,234567890123456e5", String.format(locale, "%s", new Apfloat("123456.7890123456"))); assertEquals("fi_FI %s radix 11", "1,23456e5", String.format(locale, "%s", new Apfloat("123456", 6, 11))); assertEquals("fi_FI %S radix 11", "1,23456789AE9", String.format(locale, "%S", new Apfloat("123456789a", 10, 11))); locale = new Locale("hi", "IN"); assertEquals("hi_IN %#.6s", "१२३४५६", String.format(locale, "%#.6s", new Apfloat("123456.7890123456"))); assertEquals("hi_IN %#s radix 9", "१२३४५६", String.format(locale, "%#s", new Apfloat("123456", 6, 9))); assertEquals("hi_IN %s radix 11", "1.23456e5", String.format(locale, "%s", new Apfloat("123456", 6, 11))); Writer writer = new Writer() { @Override public void write(char cbuf[], int off, int len) throws IOException { throw new IOException(); } @Override public void flush() throws IOException { throw new IOException(); } @Override public void close() throws IOException { throw new IOException(); } }; Formatter formatter = new Formatter(writer); new Apfloat("123456.789").formatTo(formatter, 0, -1, -1); } private static String getString(char character, int length) { StringBuilder buffer = new StringBuilder(length); for (int i = 0; i < length; i++) { buffer.append(character); } return buffer.toString(); } public static void testSerialization() throws IOException, ClassNotFoundException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(buffer); Apfloat a = new Apfloat(5); out.writeObject(a); out.close(); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray())); Apfloat b = (Apfloat) in.readObject(); assertEquals("5 equals", a, b); assertNotSame("5 !=", a, b); a = new Apfloat(getString('a', 1000000) + ".a", Apfloat.DEFAULT, 12); Apfloat a2 = a.floor(); buffer.reset(); out = new ObjectOutputStream(buffer); out.writeObject(a); assertTrue("Data has been used: " + buffer.size() + " > 400000", buffer.size() > 400000); out.writeObject(a2); out.close(); in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray())); b = (Apfloat) in.readObject(); Apfloat b2 = (Apfloat) in.readObject(); assertEquals("1000000 equals", a, b); assertNotSame("1000000 !=", a, b); assertEquals("1000000 floor equals", a2, b2); assertNotSame("1000000 floor !=", a2, b2); assertTrue("Data has been shared: " + buffer.size() + " < 700000", buffer.size() < 700000); // Serialization from legacy data // new Apfloat(12345678900000L) in apfloat 1.0.3 format byte[] bytes = { -84, -19, 0, 5, 115, 114, 0, 19, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 65, 112, 102, 108, 111, 97, 116, -1, 125, -106, -56, -92, 28, 107, 73, 2, 0, 1, 76, 0, 4, 105, 109, 112, 108, 116, 0, 29, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 115, 112, 105, 47, 65, 112, 102, 108, 111, 97, 116, 73, 109, 112, 108, 59, 120, 114, 0, 21, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 65, 112, 99, 111, 109, 112, 108, 101, 120, 50, -114, 76, 62, -100, 91, -70, -73, 2, 0, 2, 76, 0, 4, 105, 109, 97, 103, 116, 0, 21, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 65, 112, 102, 108, 111, 97, 116, 59, 76, 0, 4, 114, 101, 97, 108, 113, 0, 126, 0, 3, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 112, 112, 115, 114, 0, 35, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 73, 110, 116, 65, 112, 102, 108, 111, 97, 116, 73, 109, 112, 108, -53, -46, 125, 34, -23, 16, 34, -76, 2, 0, 7, 74, 0, 8, 101, 120, 112, 111, 110, 101, 110, 116, 73, 0, 8, 104, 97, 115, 104, 67, 111, 100, 101, 73, 0, 13, 105, 110, 105, 116, 105, 97, 108, 68, 105, 103, 105, 116, 115, 74, 0, 9, 112, 114, 101, 99, 105, 115, 105, 111, 110, 73, 0, 5, 114, 97, 100, 105, 120, 73, 0, 4, 115, 105, 103, 110, 76, 0, 11, 100, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 116, 0, 29, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 115, 112, 105, 47, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 59, 120, 114, 0, 32, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 73, 110, 116, 66, 97, 115, 101, 77, 97, 116, 104, 30, 42, 36, -111, 88, -64, 50, -9, 2, 0, 1, 73, 0, 5, 114, 97, 100, 105, 120, 120, 112, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, -128, 0, 0, 0, 127, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 10, 0, 0, 0, 1, 115, 114, 0, 41, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 73, 110, 116, 77, 101, 109, 111, 114, 121, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 55, -4, -106, 47, -6, 125, -73, 87, 2, 0, 1, 91, 0, 4, 100, 97, 116, 97, 116, 0, 2, 91, 73, 120, 114, 0, 27, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 115, 112, 105, 46, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 25, -41, 65, 37, -43, -67, -21, -93, 2, 0, 5, 90, 0, 10, 105, 115, 82, 101, 97, 100, 79, 110, 108, 121, 90, 0, 14, 105, 115, 83, 117, 98, 115, 101, 113, 117, 101, 110, 99, 101, 100, 74, 0, 6, 108, 101, 110, 103, 116, 104, 74, 0, 6, 111, 102, 102, 115, 101, 116, 76, 0, 19, 111, 114, 105, 103, 105, 110, 97, 108, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 113, 0, 126, 0, 7, 120, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 112, 117, 114, 0, 2, 91, 73, 77, -70, 96, 38, 118, -22, -78, -91, 2, 0, 0, 120, 112, 0, 0, 0, 2, 0, 0, 48, 57, 40, 119, 49, 32 }; in = new ObjectInputStream(new ByteArrayInputStream(bytes)); a = (Apfloat) in.readObject(); assertEquals("Legacy scale", 14, a.scale()); assertEquals("Legacy size", 9, a.size()); assertFalse("Legacy isOne", a.getImpl(a.precision()).isOne()); // new Apfloat(1) in apfloat 1.0 format byte[] bytes2 = { -84, -19, 0, 5, 115, 114, 0, 19, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 65, 112, 102, 108, 111, 97, 116, -1, 125, -106, -56, -92, 28, 107, 73, 2, 0, 1, 76, 0, 4, 105, 109, 112, 108, 116, 0, 29, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 115, 112, 105, 47, 65, 112, 102, 108, 111, 97, 116, 73, 109, 112, 108, 59, 120, 114, 0, 21, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 65, 112, 99, 111, 109, 112, 108, 101, 120, 50, -114, 76, 62, -100, 91, -70, -73, 2, 0, 2, 76, 0, 4, 105, 109, 97, 103, 116, 0, 21, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 65, 112, 102, 108, 111, 97, 116, 59, 76, 0, 4, 114, 101, 97, 108, 113, 0, 126, 0, 3, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 112, 112, 115, 114, 0, 36, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 76, 111, 110, 103, 65, 112, 102, 108, 111, 97, 116, 73, 109, 112, 108, -30, 36, -29, 106, -22, 40, -77, 43, 2, 0, 7, 74, 0, 8, 101, 120, 112, 111, 110, 101, 110, 116, 73, 0, 8, 104, 97, 115, 104, 67, 111, 100, 101, 73, 0, 13, 105, 110, 105, 116, 105, 97, 108, 68, 105, 103, 105, 116, 115, 74, 0, 9, 112, 114, 101, 99, 105, 115, 105, 111, 110, 73, 0, 5, 114, 97, 100, 105, 120, 73, 0, 4, 115, 105, 103, 110, 76, 0, 11, 100, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 116, 0, 29, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 115, 112, 105, 47, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 59, 120, 114, 0, 33, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 76, 111, 110, 103, 66, 97, 115, 101, 77, 97, 116, 104, -90, 56, -79, 77, -38, 28, -98, -104, 2, 0, 2, 68, 0, 11, 105, 110, 118, 101, 114, 115, 101, 66, 97, 115, 101, 73, 0, 5, 114, 97, 100, 105, 120, 120, 112, 60, 103, 14, -11, 70, 70, -44, -105, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 1, 115, 114, 0, 42, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 76, 111, 110, 103, 77, 101, 109, 111, 114, 121, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, -84, 74, -31, 104, 107, 113, 66, 75, 2, 0, 1, 91, 0, 4, 100, 97, 116, 97, 116, 0, 2, 91, 74, 120, 114, 0, 27, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 115, 112, 105, 46, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 25, -41, 65, 37, -43, -67, -21, -93, 2, 0, 5, 90, 0, 10, 105, 115, 82, 101, 97, 100, 79, 110, 108, 121, 90, 0, 14, 105, 115, 83, 117, 98, 115, 101, 113, 117, 101, 110, 99, 101, 100, 74, 0, 6, 108, 101, 110, 103, 116, 104, 74, 0, 6, 111, 102, 102, 115, 101, 116, 76, 0, 19, 111, 114, 105, 103, 105, 110, 97, 108, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 113, 0, 126, 0, 7, 120, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 112, 117, 114, 0, 2, 91, 74, 120, 32, 4, -75, 18, -79, 117, -109, 2, 0, 0, 120, 112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }; in = new ObjectInputStream(new ByteArrayInputStream(bytes2)); a = (Apfloat) in.readObject(); assertEquals("Legacy 1 scale", 1, a.scale()); assertEquals("Legacy 1 size", 1, a.size()); assertTrue("Legacy 1 isOne", a.getImpl(a.precision()).isOne()); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ApfloatTestCase.java000066400000000000000000000036341461767713300254670ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import junit.framework.TestCase; /** * @version 1.0 * @author Mikko Tommila */ public class ApfloatTestCase extends TestCase { public ApfloatTestCase(String methodName) { super(methodName); } public static void assertEquals(String message, Apcomplex a, Apcomplex b, Apfloat delta) { if (ApcomplexMath.abs(a.subtract(b)).compareTo(delta) > 0) { assertEquals(message, a.toString(), b.toString()); } } public static void assertEquals(String message, Apfloat a, Apfloat b, Apfloat delta) { if (ApfloatMath.abs(a.subtract(b)).compareTo(delta) > 0) { assertEquals(message, a.toString(), b.toString()); } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ApintMathTest.java000066400000000000000000001246321461767713300251740ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.HashMap; import java.util.Map; import junit.framework.TestSuite; /** * @version 1.14.0 * @author Mikko Tommila */ public class ApintMathTest extends ApfloatTestCase { public ApintMathTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApintMathTest("testIntegerPow")); suite.addTest(new ApintMathTest("testRoot")); suite.addTest(new ApintMathTest("testScale")); suite.addTest(new ApintMathTest("testAbs")); suite.addTest(new ApintMathTest("testCopySign")); suite.addTest(new ApintMathTest("testNegate")); suite.addTest(new ApintMathTest("testDiv")); suite.addTest(new ApintMathTest("testGcd")); suite.addTest(new ApintMathTest("testLcm")); suite.addTest(new ApintMathTest("testModMultiply")); suite.addTest(new ApintMathTest("testModPow")); suite.addTest(new ApintMathTest("testFactorial")); suite.addTest(new ApintMathTest("testDoubleFactorial")); suite.addTest(new ApintMathTest("testProduct")); suite.addTest(new ApintMathTest("testBinomial")); suite.addTest(new ApintMathTest("testSum")); suite.addTest(new ApintMathTest("testRandom")); suite.addTest(new ApintMathTest("testMax")); suite.addTest(new ApintMathTest("testMin")); return suite; } public static void testIntegerPow() { Apint x = new Apint(2); assertEquals("2^30", new Apint(1 << 30), ApintMath.pow(x, 30)); assertEquals("2^60", new Apint(1L << 60), ApintMath.pow(x, 60)); assertEquals("2^-1", new Apint(0), ApintMath.pow(x, -1)); assertEquals("2^-3", new Apint(0), ApintMath.pow(x, -3)); assertEquals("2^0", new Apint(1), ApintMath.pow(x, 0)); assertEquals("2^-3 radix", 12, ApintMath.pow(new Apint(2, 12), -3).radix()); try { ApintMath.pow(new Apint(0), 0); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } } public static void testRoot() { Apint[] r = ApintMath.sqrt(new Apint(143)); assertEquals("sqrt(143) quot", new Apint(11), r[0]); assertEquals("sqrt(143) rem", new Apint(22), r[1]); r = ApintMath.sqrt(new Apint(144)); assertEquals("sqrt(144) quot", new Apint(12), r[0]); assertEquals("sqrt(144) rem", new Apint(0), r[1]); r = ApintMath.sqrt(new Apint("15241578780673678546105778281054720515622620750190520")); assertEquals("sqrt(123456789123456789123456789^2-1) quot", new Apint("123456789123456789123456788"), r[0]); assertEquals("sqrt(123456789123456789123456789^2-1) rem", new Apint("246913578246913578246913576"), r[1]); r = ApintMath.sqrt(new Apint("15241578780673678546105778281054720515622620750190521")); assertEquals("sqrt(123456789123456789123456789^2) quot", new Apint("123456789123456789123456789"), r[0]); assertEquals("sqrt(123456789123456789123456789^2) rem", new Apint(0), r[1]); r = ApintMath.sqrt(new Apint("15241578780673678546105778311537878076969977842402077577351019811918920046486820281054720515622620750190521")); assertEquals("sqrt(123456789123456789123456789123456789123456789123456789^2) quot", new Apint("123456789123456789123456789123456789123456789123456789"), r[0]); assertEquals("sqrt(123456789123456789123456789123456789123456789123456789^2) rem", new Apint(0), r[1]); r = ApintMath.cbrt(new Apint(-1727)); assertEquals("cbrt(-1727) quot", new Apint(-11), r[0]); assertEquals("cbrt(-1727) rem", new Apint(-396), r[1]); r = ApintMath.cbrt(new Apint(-1728)); assertEquals("cbrt(-1728) quot", new Apint(-12), r[0]); assertEquals("cbrt(-1728) rem", new Apint(0), r[1]); r = ApintMath.cbrt(new Apint("1881676377434183987554591826597870779196556262659441282631554954480361860897068")); assertEquals("cbrt(123456789123456789123456789^3-1) quot", new Apint("123456789123456789123456788"), r[0]); assertEquals("cbrt(123456789123456789123456789^3-1) rem", new Apint("45724736342021035638317334472793794176497494880201196"), r[1]); r = ApintMath.cbrt(new Apint("1881676377434183987554591826597870779196556262659441282631554954480361860897069")); assertEquals("cbrt(123456789123456789123456789^3) quot", new Apint("123456789123456789123456789"), r[0]); assertEquals("cbrt(123456789123456789123456789^3) rem", new Apint(0), r[1]); r = ApintMath.root(new Apint(20735), 4); assertEquals("root(20735, 4) quot", new Apint(11), r[0]); assertEquals("root(20735, 4) rem", new Apint(6094), r[1]); r = ApintMath.root(new Apint(20736), 4); assertEquals("root(20736, 4) quot", new Apint(12), r[0]); assertEquals("root(20736, 4) rem", new Apint(0), r[1]); r = ApintMath.root(new Apint("232305723727482137666188006551300203692658625799727977970043302090695104949336681913044437155857798251440"), 4); assertEquals("root(123456789123456789123456789^4-1, 4) quot", new Apint("123456789123456789123456788"), r[0]); assertEquals("root(123456789123456789123456789^4-1, 4) rem", new Apint("7526705509736735950218367214942010432744153774003095938025053218012879436272304"), r[1]); r = ApintMath.root(new Apint("232305723727482137666188006551300203692658625799727977970043302090695104949336681913044437155857798251441"), 4); assertEquals("root(123456789123456789123456789^4, 4) quot", new Apint("123456789123456789123456789"), r[0]); assertEquals("root(123456789123456789123456789^4, 4) rem", new Apint(0), r[1]); r = ApintMath.root(new Apint("-28679718746395774517519299647974067853199588896463036970972834315105461935781603131036162289536454167206060221256216795681720482948"), 5); assertEquals("root(-123456789123456789123456789^5-1, 5) quot", new Apint("-123456789123456789123456788"), r[0]); assertEquals("root(-123456789123456789123456789^5-1, 5) rem", new Apint("-1161528618637410688330940013939737244121453253452721776287296525224698359210052776512932179917932266907780"), r[1]); r = ApintMath.root(new Apint("-28679718746395774517519299647974067853199588896463036970972834315105461935781603131036162289536454167206060221256216795681720482949"), 5); assertEquals("root(-123456789123456789123456789^5, 5) quot", new Apint("-123456789123456789123456789"), r[0]); assertEquals("root(-123456789123456789123456789^5, 5) rem", new Apint(0), r[1]); for (int i = 6; i < 40; i++) { Apint one = new Apint((i & 1) == 1 ? -1 : 1), x = new Apint("123456789123456789123456789").multiply(one), xm1 = x.subtract(one), pow = ApintMath.pow(x, i); r = ApintMath.root(pow.subtract(one), i); assertEquals("root(-123456789123456789123456789^" + i + "-1, " + i + ") quot", xm1, r[0]); assertEquals("root(-123456789123456789123456789^" + i + "-1, " + i + ") rem", ApintMath.pow(x, i).subtract(ApintMath.pow(xm1, i)).subtract(one), r[1]); r = ApintMath.root(pow, i); assertEquals("root(-123456789123456789123456789^" + i + ", " + i + ") quot", x, r[0]); assertEquals("root(-123456789123456789123456789^" + i + ", " + i + ") rem", new Apint(0), r[1]); } r = ApintMath.root(ApintMath.pow(new Apint(23), 7912), 7912); assertEquals("root(23^7912, 7912) quot", new Apint(23), r[0]); assertEquals("root(23^7912, 7912) rem", new Apint(0), r[1]); assertEquals("0 quot", new Apint(0), ApintMath.root(Apint.ZERO, 3)[0]); assertEquals("0 rem", new Apint(0), ApintMath.root(Apint.ZERO, 3)[1]); assertEquals("1 quot", new Apint(1), ApintMath.root(Apint.ONE, 5)[0]); assertEquals("1 rem", new Apint(0), ApintMath.root(Apint.ONE, 5)[1]); assertEquals("zeroth root quot", new Apint(1), ApintMath.root(new Apint(3), 0)[0]); assertEquals("zeroth root rem", new Apint(2), ApintMath.root(new Apint(3), 0)[1]); assertEquals("1st root quot", new Apint(2), ApintMath.root(new Apint(2), 1)[0]); assertEquals("1st root rem", new Apint(0), ApintMath.root(new Apint(2), 1)[1]); assertEquals("-1st root quot", new Apint(0), ApintMath.root(new Apint(2), -1)[0]); assertEquals("-1st root rem", new Apint(2), ApintMath.root(new Apint(2), -1)[1]); assertEquals("1st root rem radix", 12, ApintMath.root(new Apint(2, 12), 1)[1].radix()); assertEquals("-1st root quot radix", 12, ApintMath.root(new Apint(2, 12), -1)[0].radix()); try { ApintMath.root(new Apint(-2), 2); fail("sqrt of -2 accepted"); } catch (ArithmeticException ae) { // OK: result would be imaginary } try { ApintMath.root(new Apint(0), 0); fail("0th root of 0 accepted"); } catch (ArithmeticException ae) { // OK: result would be undefined } } public static void testScale() { Apint x = ApintMath.scale(new Apint(1), 5); assertEquals("1 string", "100000", x.toString()); x = ApintMath.scale(new Apint(-1), -1); assertEquals("-1 string", "0", x.toString()); x = ApintMath.scale(new Apint(1), Long.MIN_VALUE); assertEquals("underflow", "0", x.toString()); x = ApintMath.scale(new Apint(1), Long.MIN_VALUE / 2); assertEquals("underflow 2", "0", x.toString()); } public static void testAbs() { Apint x = new Apint(2); assertEquals("2", new Apint(2), ApintMath.abs(x)); x = new Apint(-2); assertEquals("-2", new Apint(2), ApintMath.abs(x)); x = new Apint(0); assertEquals("0", new Apint(0), ApintMath.abs(x)); } public static void testCopySign() { assertEquals("2, 1", new Apint(2), ApintMath.copySign(new Apint(2), new Apint(1))); assertEquals("2, -1", new Apint(-2), ApintMath.copySign(new Apint(2), new Apint(-1))); assertEquals("-2, 1", new Apint(2), ApintMath.copySign(new Apint(-2), new Apint(1))); assertEquals("-2, -1", new Apint(-2), ApintMath.copySign(new Apint(-2), new Apint(-1))); assertEquals("0, 0", new Apint(0), ApintMath.copySign(new Apint(0), new Apint(0))); assertEquals("0, 1", new Apint(0), ApintMath.copySign(new Apint(0), new Apint(1))); assertEquals("0, -1", new Apint(0), ApintMath.copySign(new Apint(0), new Apint(-1))); assertEquals("1, 0", new Apint(0), ApintMath.copySign(new Apint(1), new Apint(0))); assertEquals("-1, 0", new Apint(0), ApintMath.copySign(new Apint(-1), new Apint(0))); } @SuppressWarnings("deprecation") public static void testNegate() { Apint x = new Apint(2); assertEquals("2", new Apint(-2), ApintMath.negate(x)); x = new Apint(-2); assertEquals("-2", new Apint(2), ApintMath.negate(x)); x = new Apint(0); assertEquals("0", new Apint(0), ApintMath.negate(x)); } public static void testDiv() { Apint[] r = ApintMath.div(new Apint(5), new Apint(3)); assertEquals("5 / 3", new Apint(1), r[0]); assertEquals("5 % 3", new Apint(2), r[1]); r = ApintMath.div(new Apint(-5), new Apint(3)); assertEquals("-5 / 3", new Apint(-1), r[0]); assertEquals("-5 % 3", new Apint(-2), r[1]); r = ApintMath.div(new Apint(5), new Apint(-3)); assertEquals("5 / -3", new Apint(-1), r[0]); assertEquals("5 % -3", new Apint(2), r[1]); r = ApintMath.div(new Apint(-5), new Apint(-3)); assertEquals("-5 / -3", new Apint(1), r[0]); assertEquals("-5 % -3", new Apint(-2), r[1]); r = ApintMath.div(new Apint(0), new Apint(3)); assertEquals("0 / 3", new Apint(0), r[0]); assertEquals("0 % 3", new Apint(0), r[1]); r = ApintMath.div(new Apint("101010101010101010101010101010101010101010101010101010101010101010101010101010101"), new Apint("101010101010101010101010101010101010101010101010101010101010101010101010101010101")); assertEquals("101...101 / 101...101", new Apint(1), r[0]); assertEquals("101...101 % 101...101", new Apint(0), r[1]); r = ApintMath.div(new Apint("-101010101010101010101010101010101010101010101010101010101010101010101010101010101"), new Apint("101010101010101010101010101010101010101010101010101010101010101010101010101010101")); assertEquals("-101...101 / 101...101", new Apint(-1), r[0]); assertEquals("-101...101 % 101...101", new Apint(0), r[1]); r = ApintMath.div(new Apint("101010101010101010101010101010101010101010101010101010101010101010101010101010101"), new Apint("-101010101010101010101010101010101010101010101010101010101010101010101010101010101")); assertEquals("101...101 / -101...101", new Apint(-1), r[0]); assertEquals("101...101 % -101...101", new Apint(0), r[1]); r = ApintMath.div(new Apint("-101010101010101010101010101010101010101010101010101010101010101010101010101010101"), new Apint("-101010101010101010101010101010101010101010101010101010101010101010101010101010101")); assertEquals("-101...101 / -101...101", new Apint(1), r[0]); assertEquals("-101...101 % -101...101", new Apint(0), r[1]); r = ApintMath.div(new Apint("610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151")); assertEquals("very long / very long", new Apint("88887588172852973806344237990766854843278434484762916030592876582400800681711796943572298887271879881107698627193143861585371238964537515138970410491320347"), r[0]); assertEquals("very long % very long", new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), r[1]); r = ApintMath.div(new Apint("610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151")); assertEquals("very long / -very long", new Apint("-88887588172852973806344237990766854843278434484762916030592876582400800681711796943572298887271879881107698627193143861585371238964537515138970410491320347"), r[0]); assertEquals("very long % -very long", new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), r[1]); r = ApintMath.div(new Apint("-610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151")); assertEquals("-very long / very long", new Apint("-88887588172852973806344237990766854843278434484762916030592876582400800681711796943572298887271879881107698627193143861585371238964537515138970410491320347"), r[0]); assertEquals("-very long % very long", new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), r[1]); r = ApintMath.div(new Apint("-610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547"), new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151")); assertEquals("-very long / -very long", new Apint("88887588172852973806344237990766854843278434484762916030592876582400800681711796943572298887271879881107698627193143861585371238964537515138970410491320347"), r[0]); assertEquals("-very long % -very long", new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), r[1]); r = ApintMath.div(new Apint(1, 12), new Apint(3, 12)); assertEquals("1 / 3 radix", 12, r[0].radix()); r = ApintMath.div(new Apint(3, 12), new Apint(1, 12)); assertEquals("3 % 1 radix", 12, r[1].radix()); try { ApintMath.div(new Apint(3), new Apint(0)); fail("3 div 0 accepted"); } catch (ArithmeticException ae) { // OK: result would be infinite } } public static void testGcd() { assertEquals("2 gcd 3", new Apint(1), ApintMath.gcd(new Apint(2), new Apint(3))); assertEquals("2 gcd -4", new Apint(2), ApintMath.gcd(new Apint(2), new Apint(-4))); assertEquals("12 gcd 18", new Apint(6), ApintMath.gcd(new Apint(12), new Apint(18))); assertEquals("1 gcd 3", new Apint(1), ApintMath.gcd(new Apint(1), new Apint(3))); assertEquals("3 gcd 1", new Apint(1), ApintMath.gcd(new Apint(3), new Apint(1))); assertEquals("0 gcd 3", new Apint(3), ApintMath.gcd(new Apint(0), new Apint(3))); assertEquals("3 gcd 0", new Apint(3), ApintMath.gcd(new Apint(3), new Apint(0))); assertEquals("0 gcd -3", new Apint(3), ApintMath.gcd(new Apint(0), new Apint(-3))); assertEquals("-3 gcd 0", new Apint(3), ApintMath.gcd(new Apint(-3), new Apint(0))); assertEquals("0 gcd 0", new Apint(0), ApintMath.gcd(new Apint(0), new Apint(0))); Apint a = new Apfloat("1e100000").truncate().add(new Apint(1)); assertEquals("1e100000+1 gcd 0", a, ApintMath.gcd(a, new Apint(0))); assertEquals("0 gcd 1e100000+1", a, ApintMath.gcd(new Apint(0), a)); } public static void testLcm() { assertEquals("2 lcm 3", new Apint(6), ApintMath.lcm(new Apint(2), new Apint(3))); assertEquals("2 lcm -4", new Apint(4), ApintMath.lcm(new Apint(2), new Apint(-4))); assertEquals("12 lcm 18", new Apint(36), ApintMath.lcm(new Apint(12), new Apint(18))); assertEquals("1 lcm 3", new Apint(3), ApintMath.lcm(new Apint(1), new Apint(3))); assertEquals("3 lcm 1", new Apint(3), ApintMath.lcm(new Apint(3), new Apint(1))); assertEquals("0 lcm 3", new Apint(0), ApintMath.lcm(new Apint(0), new Apint(3))); assertEquals("3 lcm 0", new Apint(0), ApintMath.lcm(new Apint(3), new Apint(0))); assertEquals("0 lcm 0", new Apint(0), ApintMath.lcm(new Apint(0), new Apint(0))); assertEquals("0 lcm 0 radix", 12, ApintMath.lcm(new Apint(0, 12), new Apint(0, 12)).radix()); } public static void testModMultiply() { assertEquals("2 * 4 % 5", new Apint(3), ApintMath.modMultiply(new Apint(2), new Apint(4), new Apint(5))); assertEquals("0 * 4 % 5", new Apint(0), ApintMath.modMultiply(new Apint(0), new Apint(4), new Apint(5))); assertEquals("long % long", new Apint(0), ApintMath.modMultiply(new Apint(41), new Apint("2463661000246366100024636610002463661"), new Apint("101010101010101010101010101010101010101"))); assertEquals("long % -long", new Apint(0), ApintMath.modMultiply(new Apint(41), new Apint("2463661000246366100024636610002463661"), new Apint("-101010101010101010101010101010101010101"))); assertEquals("-long % long", new Apint(0), ApintMath.modMultiply(new Apint(41), new Apint("-2463661000246366100024636610002463661"), new Apint("101010101010101010101010101010101010101"))); assertEquals("-long % -long", new Apint(0), ApintMath.modMultiply(new Apint(41), new Apint("-2463661000246366100024636610002463661"), new Apint("-101010101010101010101010101010101010101"))); assertEquals("very long % very long", new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApintMath.modMultiply(new Apint(3), new Apint("203398435767884784222172707147245883636634681829295423257142999964213853451095715528681592748730146051031207844100579549984145088023052204225982849968979266817799317009500737731925213205924598136328480702197102564604528141713912050180804285220530661352483937695271447796732784767805982620765656733465699156402849"), new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); assertEquals("very long % -very long", new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApintMath.modMultiply(new Apint(3), new Apint("203398435767884784222172707147245883636634681829295423257142999964213853451095715528681592748730146051031207844100579549984145088023052204225982849968979266817799317009500737731925213205924598136328480702197102564604528141713912050180804285220530661352483937695271447796732784767805982620765656733465699156402849"), new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); assertEquals("-very long % very long", new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApintMath.modMultiply(new Apint(3), new Apint("-203398435767884784222172707147245883636634681829295423257142999964213853451095715528681592748730146051031207844100579549984145088023052204225982849968979266817799317009500737731925213205924598136328480702197102564604528141713912050180804285220530661352483937695271447796732784767805982620765656733465699156402849"), new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); assertEquals("-very long % -very long", new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057150"), ApintMath.modMultiply(new Apint(3), new Apint("-203398435767884784222172707147245883636634681829295423257142999964213853451095715528681592748730146051031207844100579549984145088023052204225982849968979266817799317009500737731925213205924598136328480702197102564604528141713912050180804285220530661352483937695271447796732784767805982620765656733465699156402849"), new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); } public static void testModPow() { assertEquals("2 ^ 7 % 63", new Apint(2), ApintMath.modPow(new Apint(2), new Apint(7), new Apint(63))); assertEquals("-2 ^ 7 % 63", new Apint(-2), ApintMath.modPow(new Apint(-2), new Apint(7), new Apint(63))); assertEquals("2 ^ 7 % -63", new Apint(2), ApintMath.modPow(new Apint(2), new Apint(7), new Apint(-63))); assertEquals("-2 ^ 7 % -63", new Apint(-2), ApintMath.modPow(new Apint(-2), new Apint(7), new Apint(-63))); assertEquals("brute 60 ^ 20 % 63", new Apint(9), ApintMath.pow(new Apint(60), 20).mod(new Apint(63))); assertEquals("60 ^ 20 % 63", new Apint(9), ApintMath.modPow(new Apint(60), new Apint(20), new Apint(63))); assertEquals("-60 ^ 20 % 63", new Apint(9), ApintMath.modPow(new Apint(-60), new Apint(20), new Apint(63))); assertEquals("60 ^ 20 % -63", new Apint(9), ApintMath.modPow(new Apint(60), new Apint(20), new Apint(-63))); assertEquals("-60 ^ 20 % -63", new Apint(9), ApintMath.modPow(new Apint(-60), new Apint(20), new Apint(-63))); assertEquals("12345 ^ 23456 % 63", new Apint(9), ApintMath.modPow(new Apint(12345), new Apint(23456), new Apint(63))); assertEquals("-12345 ^ 23456 % 63", new Apint(9), ApintMath.modPow(new Apint(-12345), new Apint(23456), new Apint(63))); assertEquals("12345 ^ 23456 % -63", new Apint(9), ApintMath.modPow(new Apint(12345), new Apint(23456), new Apint(-63))); assertEquals("-12345 ^ 23456 % -63", new Apint(9), ApintMath.modPow(new Apint(-12345), new Apint(23456), new Apint(-63))); assertEquals("a ^ b % c", new Apint("7491153279929021784053819542230143577477242735007791983639160648989490758264323"), ApintMath.modPow(new Apint("6251289725125823481258278078012201234862578962346891205091256612909786215690123"), new Apint("7124389714096813469801349081346689134098613461490781691409146149904781661401906"), new Apint("11111111111111111111111111111111111111111111111111111111111111111111111111111203"))); assertEquals("2 ^ 7 % 0", new Apint(0), ApintMath.modPow(new Apint(2), new Apint(7), new Apint(0))); assertEquals("2 ^ 0 % 63", new Apint(1), ApintMath.modPow(new Apint(2, 12), new Apint(0), new Apint(63))); assertEquals("2 ^ 0 % 63 radix", 12, ApintMath.modPow(new Apint(2, 12), new Apint(0), new Apint(63)).radix()); assertEquals("0 ^ 7 % 2", new Apint(0), ApintMath.modPow(new Apint(0), new Apint(7), new Apint(2))); assertEquals("3 ^ -1 % 5", new Apint(2), ApintMath.modPow(new Apint(3), new Apint(-1), new Apint(5))); assertEquals("2 ^ -1 % 15", new Apint(8), ApintMath.modPow(new Apint(2), new Apint(-1), new Apint(15))); assertEquals("4 ^ -1 % 15", new Apint(4), ApintMath.modPow(new Apint(4), new Apint(-1), new Apint(15))); assertEquals("-4 ^ -1 % 15", new Apint(-11), ApintMath.modPow(new Apint(-4), new Apint(-1), new Apint(15))); assertEquals("4 ^ -1 % -15", new Apint(4), ApintMath.modPow(new Apint(4), new Apint(-1), new Apint(-15))); assertEquals("-4 ^ -1 % -15", new Apint(-11), ApintMath.modPow(new Apint(-4), new Apint(-1), new Apint(-15))); assertEquals("12345 ^ -345 % 64", new Apint(9), ApintMath.modPow(new Apint(12345), new Apint(-345), new Apint(64))); assertEquals("-12345 ^ -345 % 64", new Apint(-55), ApintMath.modPow(new Apint(-12345), new Apint(-345), new Apint(64))); assertEquals("12345 ^ -345 % -64", new Apint(9), ApintMath.modPow(new Apint(12345), new Apint(-345), new Apint(-64))); assertEquals("-12345 ^ -345 % -64", new Apint(-55), ApintMath.modPow(new Apint(-12345), new Apint(-345), new Apint(-64))); assertEquals("2 ^ -7 % 63", new Apint(32, 12), ApintMath.modPow(new Apint(2, 12), new Apint(-7, 12), new Apint(63, 12))); assertEquals("2 ^ -7 % 63 radix", 12, ApintMath.modPow(new Apint(2, 12), new Apint(-7, 12), new Apint(63, 12)).radix()); assertEquals("1 ^ -1 % 2", new Apint(1), ApintMath.modPow(new Apint(1), new Apint(-1), new Apint(2))); assertEquals("1 ^ -1 % 1", new Apint(0), ApintMath.modPow(new Apint(1), new Apint(-1), new Apint(1))); try { ApintMath.modPow(new Apint(14), new Apint(-1), new Apint(65536)); fail("Non-existent modular inverse allowed"); } catch (ArithmeticException ae) { // OK: modular inverse does not exist } try { ApintMath.modPow(new Apint(0), new Apint(-1), new Apint(2)); fail("Non-existent modular inverse allowed"); } catch (ArithmeticException ae) { // OK: modular inverse does not exist } try { ApintMath.modPow(new Apint(0), new Apint(0), new Apint(7)); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } } public static void testFactorial() { assertEquals("0!", new Apint(1), ApintMath.factorial(0)); assertEquals("1!", new Apint(1), ApintMath.factorial(1)); assertEquals("2!", new Apint(2), ApintMath.factorial(2)); assertEquals("3!", new Apint(6), ApintMath.factorial(3)); assertEquals("7!", new Apint(5040), ApintMath.factorial(7)); assertEquals("7! radix", 10, ApintMath.factorial(7).radix()); assertEquals("7! radix 7", new Apint(5040, 7), ApintMath.factorial(7, 7)); assertEquals("7! radix 7 radix", 7, ApintMath.factorial(7, 7).radix()); assertEquals("20!", new Apint("2432902008176640000"), ApintMath.factorial(20)); assertEquals("29!", new Apint("8841761993739701954543616000000"), ApintMath.factorial(29)); try { ApintMath.factorial(-1); fail("Factorial of negative number allowed"); } catch (ArithmeticException ae) { // OK: factorial of negative number } } public static void testDoubleFactorial() { assertEquals("0!!", new Apint(1), ApintMath.doubleFactorial(0)); assertEquals("1!!", new Apint(1), ApintMath.doubleFactorial(1)); assertEquals("2!!", new Apint(2), ApintMath.factorial(2)); assertEquals("3!!", new Apint(3), ApintMath.doubleFactorial(3)); assertEquals("7!!", new Apint(105), ApintMath.doubleFactorial(7)); assertEquals("7!! radix", 10, ApintMath.doubleFactorial(7).radix()); assertEquals("7!! radix 7", new Apint(105, 7), ApintMath.doubleFactorial(7, 7)); assertEquals("7!! radix 7 radix", 7, ApintMath.doubleFactorial(7, 7).radix()); assertEquals("20!!", new Apint("3715891200"), ApintMath.doubleFactorial(20)); assertEquals("29!!", new Apint("6190283353629375"), ApintMath.doubleFactorial(29)); try { ApintMath.doubleFactorial(-1); fail("Double factorial of negative number allowed"); } catch (ArithmeticException ae) { // OK: double factorial of negative number } } public static void testBinomial() { Apint a = ApintMath.binomial(10, 2); assertEquals("10,2 value", new Apint(45), a); a = ApintMath.binomial(10, 3); assertEquals("10,3 value", new Apint(120), a); a = ApintMath.binomial(10, 4); assertEquals("10,4 value", new Apint(210), a); a = ApintMath.binomial(10, 5); assertEquals("10,5 value", new Apint(252), a); a = ApintMath.binomial(10, 6); assertEquals("10,6 value", new Apint(210), a); a = ApintMath.binomial(10, 0); assertEquals("10,0 value", new Apint(1), a); a = ApintMath.binomial(10, 1); assertEquals("10,1 value", new Apint(10), a); a = ApintMath.binomial(10, 10); assertEquals("10,10 value", new Apint(1), a); a = ApintMath.binomial(11, 4); assertEquals("11,4 value", new Apint(330), a); a = ApintMath.binomial(11, 5); assertEquals("11,5 value", new Apint(462), a); a = ApintMath.binomial(11, 6); assertEquals("11,6 value", new Apint(462), a); a = ApintMath.binomial(2, 3); assertEquals("2,3 value", new Apint(0), a); a = ApintMath.binomial(0,0); assertEquals("0,0 value", new Apint(1), a); a = ApintMath.binomial(-4, -9); assertEquals("-4,-9 value", new Apint(-56), a); a = ApintMath.binomial(-4, 9); assertEquals("-4,9 value", new Apint(-220), a); a = ApintMath.binomial(4, -9); assertEquals("4,-9 value", new Apint(0), a); a = ApintMath.binomial(-9, -4); assertEquals("-9,-4 value", new Apint(0), a); a = ApintMath.binomial(-9, 4); assertEquals("-9,4 value", new Apint(495), a); a = ApintMath.binomial(9, -4); assertEquals("9,-4 value", new Apint(0), a); a = ApintMath.binomial(Long.MAX_VALUE, Long.MAX_VALUE - 1); assertEquals("MAX_VALUE,MAX_VALUE-1 value", new Apint(Long.MAX_VALUE), a); a = ApintMath.binomial(Long.MAX_VALUE, 1); assertEquals("MAX_VALUE,1 value", new Apint(Long.MAX_VALUE), a); a = ApintMath.binomial(Long.MIN_VALUE, 0); assertEquals("MIN_VALUE, 0 value", new Apint(1), a); a = ApintMath.binomial(-1, Long.MAX_VALUE, 9); assertEquals("-1 Long.MAX_VALUE value", new Apint(-1, 9), a); a = ApintMath.binomial(Long.MAX_VALUE, -1, 9); assertEquals("MAX_VALUE, -1 value", new Apint(0, 9), a); a = ApintMath.binomial(9, 5, 11); assertEquals("9,5 radix 11 value", new Apint(126, 11), a); a = ApintMath.binomial(new Apint(10), new Apint(2)); assertEquals("10,2 apint value", new Apint(45), a); a = ApintMath.binomial(new Apint(10), new Apint(3)); assertEquals("10,3 apint value", new Apint(120), a); a = ApintMath.binomial(new Apint(10), new Apint(4)); assertEquals("10,4 apint value", new Apint(210), a); a = ApintMath.binomial(new Apint(10), new Apint(5)); assertEquals("10,5 apint value", new Apint(252), a); a = ApintMath.binomial(new Apint(10), new Apint(6)); assertEquals("10,6 apint value", new Apint(210), a); a = ApintMath.binomial(new Apint(10), new Apint(0)); assertEquals("10,0 apint value", new Apint(1), a); a = ApintMath.binomial(new Apint(10), new Apint(1)); assertEquals("10,1 apint value", new Apint(10), a); a = ApintMath.binomial(new Apint(10), new Apint(10)); assertEquals("10,10 apint value", new Apint(1), a); a = ApintMath.binomial(new Apint(11), new Apint(4)); assertEquals("11,4 apint value", new Apint(330), a); a = ApintMath.binomial(new Apint(11), new Apint(5)); assertEquals("11,5 apint value", new Apint(462), a); a = ApintMath.binomial(new Apint(11), new Apint(6)); assertEquals("11,6 apint value", new Apint(462), a); a = ApintMath.binomial(new Apint(2), new Apint(3)); assertEquals("2,3 apint value", new Apint(0), a); a = ApintMath.binomial(new Apint(0), new Apint(0)); assertEquals("0,0 apint value", new Apint(1), a); a = ApintMath.binomial(new Apint(-4), new Apint(-9)); assertEquals("-4,-9 apint value", new Apint(-56), a); a = ApintMath.binomial(new Apint(-4), new Apint(9)); assertEquals("-4,9 apint value", new Apint(-220), a); a = ApintMath.binomial(new Apint(4), new Apint(-9)); assertEquals("4,-9 apint value", new Apint(0), a); a = ApintMath.binomial(new Apint(-9), new Apint(-4)); assertEquals("-9,-4 apint value", new Apint(0), a); a = ApintMath.binomial(new Apint(-9), new Apint(4)); assertEquals("-9,4 apint value", new Apint(495), a); a = ApintMath.binomial(new Apint(9), new Apint(-4)); assertEquals("9,-4 apint value", new Apint(0), a); a = ApintMath.binomial(new Apint("1000000000000000000000000000000"), new Apint(3)); assertEquals("1000000000000000000000000000000,3 value", new Apint("166666666666666666666666666666166666666666666666666666666667000000000000000000000000000000"), a); a = ApintMath.binomial(new Apint(9, 9), new Apint(4, 9)); assertEquals("9,4 radix 9 apint value", new Apint(126, 9), a); try { ApintMath.binomial(new Apint("200000000000000000000"), new Apint("100000000000000000000")); fail("Overflow allowed"); } catch (OverflowException oe) { // OK: overflow } } public static void testProduct() { Apint a = ApintMath.product(new Apint(2), new Apint(3)); assertEquals("2,3 value", new Apint(6), a); a = ApintMath.product(new Apint(2), new Apint(3), new Apint(7)); assertEquals("2,3,7 value", new Apint(42), a); a = ApintMath.product(Apint.ZERO, new Apint(12345)); assertEquals("0 value", new Apint("0"), a); Apint[] x = new Apint[] { new Apint("1000000000000"), new Apint("1") }; ApintMath.product(x); assertEquals("Array product 1 [0]", new Apint("1000000000000"), x[0]); assertEquals("Array product 1 [1]", new Apint("1"), x[1]); x = new Apint[] { new Apint("1"), new Apint("1000000000000") }; ApintMath.product(x); assertEquals("Array product 2 [0]", new Apint("1"), x[0]); assertEquals("Array product 2 [1]", new Apint("1000000000000"), x[1]); assertEquals("Empty product", new Apint("1"), ApintMath.product()); } public static void testSum() { Apint a = ApintMath.sum(new Apint("2"), new Apint("3")); assertEquals("2,3 value", new Apint("5"), a); a = ApintMath.sum(new Apint(2), new Apint(3), new Apint(4)); assertEquals("2,3,4 value", new Apint(9), a); a = ApintMath.sum(new Apint(0), new Apint(12345)); assertEquals("0-0 value", new Apint(12345), a); a = ApintMath.sum(new Apint(2)); assertEquals("2 value", new Apint(2), a); Apint[] x = new Apint[] { new Apint("1000000000000"), new Apint("1") }; ApintMath.sum(x); assertEquals("Array sum 1 [0]", new Apint("1000000000000"), x[0]); assertEquals("Array sum 1 [1]", new Apint("1"), x[1]); x = new Apint[] { new Apint("1"), new Apint("1000000000000") }; ApintMath.sum(x); assertEquals("Array sum 2 [0]", new Apint("1"), x[0]); assertEquals("Array sum 2 [1]", new Apint("1000000000000"), x[1]); assertEquals("Empty sum", new Apint("0"), ApintMath.sum()); } public static void testRandom() { long maxScale = 0; long minScale = Long.MAX_VALUE; for (int i = 0; i < 1000; i++) { Apint a = ApintMath.random(1000); maxScale = Math.max(maxScale, a.scale()); minScale = Math.min(minScale, a.scale()); } assertEquals("random max scale", 1000, maxScale); assertTrue("random min scale", minScale < 1000); for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { Map counts = new HashMap<>(); for (int i = 0; i < 20 * radix; i++) { Apint a = ApintMath.random(1, radix); counts.put(a, counts.getOrDefault(a, 0) + 1); assertEquals("value less than radix", -1, a.compareTo(new Apint(radix, radix))); assertTrue("value >= 0", a.signum() >= 0); } assertEquals("All values occurred", radix, counts.size()); } try { ApintMath.random(0); fail("Zero allowed"); } catch (IllegalArgumentException iae) { // OK: zero precision } try { ApintMath.random(Apfloat.INFINITE); fail("Infinite allowed"); } catch (InfiniteExpansionException iee) { // OK: Infinite size } } public static void testMax() { assertEquals("max of 1 and 1", new Apint(1), ApintMath.max(new Apint(1), new Apint(1))); assertEquals("max of 1 and 2", new Apint(2), ApintMath.max(new Apint(1), new Apint(2))); assertEquals("max of 2 and 1", new Apint(2), ApintMath.max(new Apint(2), new Apint(1))); } public static void testMin() { assertEquals("min of 1 and 1", new Apint(1), ApintMath.min(new Apint(1), new Apint(1))); assertEquals("min of 1 and 2", new Apint(1), ApintMath.min(new Apint(1), new Apint(2))); assertEquals("min of 2 and 1", new Apint(1), ApintMath.min(new Apint(2), new Apint(1))); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ApintTest.java000066400000000000000000000663441461767713300243670ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.BigInteger; import java.io.PushbackReader; import java.io.StringReader; import java.io.StringWriter; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; import java.util.Locale; import java.util.IllegalFormatException; import junit.framework.TestSuite; /** * @version 1.10.1 * @author Mikko Tommila */ public class ApintTest extends ApfloatTestCase { public ApintTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ApintTest("testLongConstructor")); suite.addTest(new ApintTest("testStringConstructor")); suite.addTest(new ApintTest("testStreamConstructor")); suite.addTest(new ApintTest("testBigIntegerConstructor")); suite.addTest(new ApintTest("testRationalMethods")); suite.addTest(new ApintTest("testRadix")); suite.addTest(new ApintTest("testPrecision")); suite.addTest(new ApintTest("testScale")); suite.addTest(new ApintTest("testSize")); suite.addTest(new ApintTest("testIsInteger")); suite.addTest(new ApintTest("testNegate")); suite.addTest(new ApintTest("testAdd")); suite.addTest(new ApintTest("testSubtract")); suite.addTest(new ApintTest("testMultiply")); suite.addTest(new ApintTest("testDivide")); suite.addTest(new ApintTest("testMod")); suite.addTest(new ApintTest("testFloor")); suite.addTest(new ApintTest("testCeil")); suite.addTest(new ApintTest("testTruncate")); suite.addTest(new ApintTest("testFrac")); suite.addTest(new ApintTest("testRoundAway")); suite.addTest(new ApintTest("testAbs")); suite.addTest(new ApintTest("testCompareToHalf")); suite.addTest(new ApintTest("testNumberValues")); suite.addTest(new ApintTest("testEqualDigits")); suite.addTest(new ApintTest("testToBigInteger")); suite.addTest(new ApintTest("testCompareTo")); suite.addTest(new ApintTest("testEquals")); suite.addTest(new ApintTest("testTest")); suite.addTest(new ApintTest("testHashCode")); suite.addTest(new ApintTest("testToString")); suite.addTest(new ApintTest("testWriteTo")); suite.addTest(new ApintTest("testFormatTo")); suite.addTest(new ApintTest("testSerialization")); return suite; } public static void testLongConstructor() { Apint a = new Apint(5); assertEquals("5 radix", 10, a.radix()); assertEquals("5 String", "5", a.toString()); a = new Apint(5, 6); assertEquals("5, 6 radix", 6, a.radix()); assertEquals("5, 6 String", "5", a.toString()); } public static void testStringConstructor() { Apint a = new Apint("5"); assertEquals("5 radix", 10, a.radix()); assertEquals("5 String", "5", a.toString()); a = new Apint("aa", 12); assertEquals("aa radix", 12, a.radix()); assertEquals("aa String", "aa", a.toString()); a = new Apint("-bb", 13); assertEquals("-bb radix", 13, a.radix()); assertEquals("-bb String", "-bb", a.toString()); try { a = new Apint("2."); fail("2. accepted"); } catch (NumberFormatException nfe) { // OK: illegal number } try { a = new Apint("2e"); fail("2e accepted"); } catch (NumberFormatException nfe) { // OK: illegal number } } public static void testStreamConstructor() throws IOException { PushbackReader in = new PushbackReader(new StringReader("5")); Apint a = new Apint(in); assertEquals("5 radix", 10, a.radix()); assertEquals("5 String", "5", a.toString()); in = new PushbackReader(new StringReader("aa")); a = new Apint(in, 12); assertEquals("aa radix", 12, a.radix()); assertEquals("aa String", "aa", a.toString()); in = new PushbackReader(new StringReader("2.")); a = new Apint(in); assertEquals("2. String", "2", a.toString()); assertEquals("2. next char", '.', in.read()); in = new PushbackReader(new StringReader("2e")); a = new Apint(in); assertEquals("2e String", "2", a.toString()); assertEquals("2e next char", 'e', in.read()); in = new PushbackReader(new StringReader("05")); a = new Apint(in); assertEquals("05 String", "5", a.toString()); assertEquals("05 next char", -1, in.read()); } public static void testBigIntegerConstructor() { Apint a = new Apint(BigInteger.valueOf(5)); assertEquals("5 radix", 10, a.radix()); assertEquals("5 String", "5", a.toString()); a = new Apint(BigInteger.valueOf(6), 12); assertEquals("6 radix", 12, a.radix()); assertEquals("6 String", "6", a.toString()); } public static void testRationalMethods() { Apint a = new Apint(5); assertEquals("numerator", a, a.numerator()); assertEquals("denominator", Apint.ONE, a.denominator()); } public static void testRadix() { Apint a = new Apint(2, 5); assertEquals("radix", 5, a.radix()); a = new Apint(16); assertEquals("10 -> 16", new Apint("10", 16), a.toRadix(16)); } public static void testPrecision() { Apint a = new Apint(5); assertEquals("int precision", Apfloat.INFINITE, a.precision()); Apfloat f = a.precision(4); assertEquals("4 precision", 4, f.precision()); a = new Apint(0); assertEquals("0 precision", Apint.INFINITE, a.precision()); } public static void testScale() { Apint a = new Apint(9); assertEquals("9 scale", 1, a.scale()); a = new Apint(10); assertEquals("10 scale", 2, a.scale()); a = new Apint(0); assertEquals("0 scale", -Apint.INFINITE, a.scale()); a = new Apint(9); assertEquals("9 scaled 1", new Apint(90), a.scale(1)); assertEquals("9 scaled -1", new Aprational("9/10"), a.scale(-1)); } public static void testSize() { Apint a = new Apint(9); assertEquals("9 size", 1, a.size()); a = new Apint(10); assertEquals("10 size", 1, a.size()); a = new Apint(100010); assertEquals("100010 size", 5, a.size()); a = new Apint(1000000000000010L); assertEquals("1000000000000010 size", 15, a.size()); a = new Apint("100000000000000000000000100"); assertEquals("100000000000000000000000100 size", 25, a.size()); a = new Apint(0); assertEquals("0 size", 0, a.size()); } public static void testIsInteger() { Apint a = new Apint(0); assertTrue("0", a.isInteger()); a = new Apint(1); assertTrue("1", a.isInteger()); a = new Apint(-1); assertTrue("-1", a.isInteger()); } public static void testNegate() { Apint x = new Apint(2); assertEquals("2", new Apint(-2), x.negate()); x = new Apint(-2); assertEquals("-2", new Apint(2), x.negate()); x = new Apint(0); assertEquals("0", new Apint(0), x.negate()); Aprational y = new Apint(2); assertEquals("-2", new Aprational("-2"), y.negate()); } public static void testAdd() { Apint a = new Apint(4), b = new Apint(5); assertEquals("4 + 5", new Apint(9), a.add(b)); assertEquals("4 + 0", new Apint(4), a.add(new Apint(0))); assertEquals("0 + 4", new Apint(4), new Apint(0).add(a)); a = new Apint("1"); Apfloat f = new Apfloat("0.00001"); assertEquals("1 + 0.00001", new Apfloat("1.00001"), a.add(f)); assertEquals("1 + 0.00001 precision", 6, a.add(f).precision()); assertEquals("0.00001 + 1", new Apfloat("1.00001"), f.add(a)); } public static void testSubtract() { Apint a = new Apint(4), b = new Apint(5); assertEquals("4 - 5", new Apint(-1), a.subtract(b)); assertEquals("4 - 0", new Apint(4), a.subtract(new Apint(0))); assertEquals("0 - 4", new Apint(-4), new Apint(0).subtract(a)); } public static void testMultiply() { Apint a = new Apint(4, 12), b = new Apint(5, 12); assertEquals("4 * 5", new Apint(20, 12), a.multiply(b)); assertEquals("4 * 0", new Apint(0), a.multiply(new Apint(0))); assertEquals("0 * 4", new Apint(0), new Apint(0).multiply(a)); assertEquals("4 * 1", new Apint(4, 12), a.multiply(new Apint(1, 12))); assertEquals("1 * 4", new Apint(4, 12), new Apint(1, 12).multiply(a)); assertEquals("4 * ONE", new Apint(4, 12), a.multiply(Apint.ONE)); assertEquals("ONE * 4", new Apint(4, 12), Apint.ONE.multiply(a)); } public static void testDivide() { Apint a = new Apint(4, 12), b = new Apint(3, 12); assertEquals("4 / 3", new Apint("1", 12), a.divide(b)); assertEquals("0 / 4", new Apint(0), new Apint(0).divide(a)); assertEquals("4 / 1", new Apint(4, 12), a.divide(new Apint(1, 12))); assertEquals("4 / ONE", new Apint(4, 12), a.divide(Apint.ONE)); assertEquals("4 / 3 radix", 12, b.divide(a).radix()); try { a.divide(new Apint(0)); fail("Division by zero allowed"); } catch (ArithmeticException ae) { // OK: division by zero } assertEquals("long / long", new Apint(1), new Apint("101010101010101010101010101010101010101").divide(new Apint("101010101010101010101010101010101010101"))); assertEquals("long / -long", new Apint(-1), new Apint("101010101010101010101010101010101010101").divide(new Apint("-101010101010101010101010101010101010101"))); assertEquals("-long / long", new Apint(-1), new Apint("-101010101010101010101010101010101010101").divide(new Apint("101010101010101010101010101010101010101"))); assertEquals("-long / -long", new Apint(1), new Apint("-101010101010101010101010101010101010101").divide(new Apint("-101010101010101010101010101010101010101"))); assertEquals("very long / very long", new Apint("88887588172852973806344237990766854843278434484762916030592876582400800681711796943572298887271879881107698627193143861585371238964537515138970410491320347"), new Apint("610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547").divide(new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); assertEquals("very long / -very long", new Apint("-88887588172852973806344237990766854843278434484762916030592876582400800681711796943572298887271879881107698627193143861585371238964537515138970410491320347"), new Apint("610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547").divide(new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); assertEquals("-very long / very long", new Apint("-88887588172852973806344237990766854843278434484762916030592876582400800681711796943572298887271879881107698627193143861585371238964537515138970410491320347"), new Apint("-610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547").divide(new Apint("6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); assertEquals("-very long / -very long", new Apint("88887588172852973806344237990766854843278434484762916030592876582400800681711796943572298887271879881107698627193143861585371238964537515138970410491320347"), new Apint("-610195307303654352666518121441737650909904045487886269771428999892641560353287146586044778246190438153093623532301738649952435264069156612677948549906937800453397951028502213195775639617773794408985442106591307693813584425141736150542412855661591984057451813085814343390198354303417947862296970200397097469208547").divide(new Apint("-6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151"))); } public static void testMod() { Apint a = new Apint(4), b = new Apint(3); assertEquals("4 % 3", new Apint(1), a.mod(b)); } public static void testFloor() { Apint a = new Apint("2"); assertEquals("2 floor", new Apint(2), a.floor()); a = new Apint(0); assertEquals("0 floor", new Apint(0), a.floor()); } public static void testCeil() { Apint a = new Apint("2"); assertEquals("2 ceil", new Apint(2), a.ceil()); a = new Apint(0); assertEquals("0 ceil", new Apint(0), a.ceil()); } public static void testTruncate() { Apint a = new Apint("2"); assertEquals("2 truncate", new Apint(2), a.truncate()); a = new Apint(0); assertEquals("0 truncate", new Apint(0), a.truncate()); } public static void testFrac() { Apint a = new Apint("2", 12); assertEquals("2 frac", new Apint(0), a.frac()); assertEquals("2 frac radix", 12, a.frac().radix()); a = new Apint(0); assertEquals("0 frac", new Apint(0), a.frac()); } public static void testRoundAway() { Apint a = new Apint("2"); assertEquals("2 roundAway", new Apint(2), a.roundAway()); a = new Apint(0); assertEquals("0 roundAway", new Apint(0), a.roundAway()); } public static void testAbs() { Apint a = new Apint("2"); assertEquals("2 abs", new Apint(2), a.abs()); a = new Apint(0); assertEquals("0 abs", new Apint(0), a.abs()); a = new Apint(-2); assertEquals("-2 abs", new Apint(2), a.abs()); } public static void testCompareToHalf() { Apint a = new Apint(0); assertEquals("0 compareToHalf", -1, a.compareToHalf()); a = new Apint(1); assertEquals("1 compareToHalf", 1, a.compareToHalf()); a = new Apint(2); assertEquals("2 compareToHalf", 1, a.compareToHalf()); } public static void testNumberValues() { Apint a = new Apint(5); assertEquals("5 longValue", 5, a.longValue()); assertEquals("5 intValue", 5, a.intValue()); assertEquals("5 shortValue", 5, a.shortValue()); assertEquals("5 byteValue", 5, a.byteValue()); assertEquals("5 floatValue", 5.0f, a.floatValue(), 0.0f); assertEquals("5 doubleValue", 5.0, a.doubleValue(), 0.0); a = new Apint(1000000000000L); assertEquals("1000000000000 intValue", Integer.MAX_VALUE, a.intValue()); assertEquals("1000000000000 shortValue", Short.MAX_VALUE, a.shortValue()); assertEquals("1000000000000 byteValue", Byte.MAX_VALUE, a.byteValue()); a = new Apint(-1000000000000L); assertEquals("-1000000000000 intValue", Integer.MIN_VALUE, a.intValue()); assertEquals("-1000000000000 shortValue", Short.MIN_VALUE, a.shortValue()); assertEquals("-1000000000000 byteValue", Byte.MIN_VALUE, a.byteValue()); a = new Apfloat("1e100").floor(); assertEquals("1e100 floatValue", Float.POSITIVE_INFINITY, a.floatValue(), 0.0f); a = new Apfloat("-1e100").floor(); assertEquals("-1e100 floatValue", Float.NEGATIVE_INFINITY, a.floatValue(), 0.0f); a = new Apfloat("1e1000").floor(); assertEquals("1e1000 doubleValue", Double.POSITIVE_INFINITY, a.doubleValue(), 0.0); a = new Apfloat("-1e1000").floor(); assertEquals("-1e1000 doubleValue", Double.NEGATIVE_INFINITY, a.doubleValue(), 0.0); } public static void testEqualDigits() { Apint a = new Apint(5), b = new Apint(6); assertEquals("5 eq 6", 0, a.equalDigits(b)); a = new Apint(10); b = new Apint(11); assertEquals("10 eq 11", 1, a.equalDigits(b)); a = new Apint(7); b = new Apint(7); assertEquals("7 eq 7", Apint.INFINITE, a.equalDigits(b)); } public static void testToBigInteger() { Apint a = new Apint("1234567"), b = new Apint("-12345678901234567890"); assertEquals("1234567", new BigInteger("1234567"), a.toBigInteger()); assertEquals("-12345678901234567890", new BigInteger("-12345678901234567890"), b.toBigInteger()); assertEquals("0", BigInteger.ZERO, Apint.ZERO.toBigInteger()); try { a = new Apfloat("1", Apfloat.INFINITE, 16).scale(1000000000000000L).truncate(); a.toBigInteger(); fail("Too big integer allowed"); } catch (IllegalArgumentException iae) { // OK, should be thrown } } @SuppressWarnings({ "rawtypes", "unchecked" }) public static void testCompareTo() { Apint a = new Apint(0), b = new Apint(1); assertEquals("0 cmp 1", -1, a.compareTo(b)); a = new Apint(6); b = new Apint(5); assertEquals("6 cmp 5", 1, a.compareTo(b)); a = new Apint(6); b = new Apint(6); assertEquals("6 cmp 6", 0, a.compareTo(b)); a = new Apint(12); Aprational r = new Aprational("12/1"); assertEquals("12 cmp rational 12", 0, a.compareTo(r)); assertEquals("rational 12 cmp 12", 0, r.compareTo(a)); r = new Apint(12); assertEquals("12 cmp rational int 12", 0, a.compareTo(r)); assertEquals("rational int 12 cmp 12", 0, r.compareTo(a)); a = new Apint(3); Apfloat f = new Apfloat("3.3"); assertEquals("3 cmp 3.3", -1, a.compareTo(f)); assertEquals("3.3 cmp 3", 1, f.compareTo(a)); f = new Aprational("10/3"); assertEquals("3 cmp float 10/3", -1, a.compareTo(f)); assertEquals("float 10/3 cmp 3", 1, f.compareTo(a)); Comparable obj1 = new Apint(3), obj2 = new Apint(4); assertEquals("obj 3 cmp 4", -1, obj1.compareTo(obj2)); assertEquals("obj 4 cmp 3", 1, obj2.compareTo(obj1)); obj1 = new Apint(3); obj2 = new Aprational("8/3"); assertEquals("obj 3 cmp 8/3", 1, obj1.compareTo(obj2)); assertEquals("obj 8/3 cmp 3", -1, obj2.compareTo(obj1)); obj1 = new Apint(3); obj2 = new Apfloat("3.3"); assertEquals("obj 3 cmp 3.3", -1, obj1.compareTo(obj2)); assertEquals("obj 3.3 cmp 3", 1, obj2.compareTo(obj1)); try { Comparable c = a; c.compareTo("bogus"); fail("Comparison to different class allowed"); } catch (ClassCastException cce) { // OK: class can't be cast to Apfloat } } public static void testEquals() { Apint a = new Apint(0), b = new Apint(1); assertEquals("0 == 1", false, a.equals(b)); a = new Apint(6); b = new Apint(5); assertEquals("6 == 5", false, a.equals(b)); a = new Apint(6); b = new Apint(6); assertEquals("6 == 6", true, a.equals(b)); assertEquals("6 == something else", false, a.equals("bogus")); a = new Apint(12); Aprational r = new Aprational("12/1"); assertEquals("12 == rational 12", true, a.equals(r)); assertEquals("rational 12 == 12", true, r.equals(a)); a = new Apint(3); Apfloat f = new Apfloat("3"); assertEquals("3 == float 3", true, a.equals(f)); assertEquals("float 3 == 3", true, f.equals(a)); Object obj1 = new Apint(3), obj2 = new Apint(4); assertEquals("obj 3 == 4", false, obj1.equals(obj2)); assertEquals("obj 4 == 3", false, obj2.equals(obj1)); obj1 = new Apint(3); obj2 = new Aprational("8/3"); assertEquals("obj 3 == 8/3", false, obj1.equals(obj2)); assertEquals("obj 8/3 == 3", false, obj2.equals(obj1)); obj1 = new Apint(3); obj2 = new Apfloat("3"); assertEquals("obj 3 == float 3", true, obj1.equals(obj2)); assertEquals("obj float 3 == 3", true, obj2.equals(obj1)); } public static void testTest() { Apint a = new Apint(0), b = new Apint(0); assertTrue("0 test 0", a.test(b)); a = new Apint(0); b = new Apint(1); assertFalse("0 test 1", a.test(b)); a = new Apint(-1); b = new Apint(1); assertFalse("-1 test 1", a.test(b)); a = new Apint(2); Aprational r = new Aprational("2"); assertTrue("2 test 2, type", a.test(r)); assertTrue("2 test 2, type reverse", r.test(a)); a = new Apint(2); r = new Aprational("2/3"); assertTrue("2 test 2/3, type", a.test(r)); assertTrue("2/3 test 2, type", r.test(a)); a = new Apint(2); r = new Aprational("2/13"); assertFalse("2 test 2/13, type", a.test(r)); assertFalse("2/13 test 2, type", r.test(a)); a = new Apint(2); Apfloat f = new Apfloat(2); assertTrue("2 test 2, type", a.test(f)); assertTrue("2 test 2, type reverse", f.test(a)); a = new Apint(2); f = new Apfloat(0.6); assertFalse("2 test 0.6, type", a.test(f)); assertFalse("0.6 test 2, type", f.test(a)); } public static void testHashCode() { Apint a = new Apint(0), b = new Apint(1); assertTrue("0 != 1", a.hashCode() != b.hashCode()); a = new Apint(6); b = new Apint(5); assertTrue("5 != 6", a.hashCode() != b.hashCode()); a = new Apint(6); b = new Apint(6); assertEquals("6 == 6", a.hashCode(), b.hashCode()); } public static void testToString() { Apint a = new Apint(0); assertEquals("0", "0", "" + a); a = new Apint(6); assertEquals("6", "6", "" + a); a = new Apint(123456789); assertEquals("123456789", "123456789", "" + a); assertEquals("123456789 unpretty", "1.23456789e8", a.toString(false)); } public static void testWriteTo() throws IOException { StringWriter out = new StringWriter(); Apint a = new Apint(0); a.writeTo(out); a = new Apint(6); a.writeTo(out); a = new Apint(123456789); a.writeTo(out); a.writeTo(out, false); assertEquals("string", "061234567891.23456789e8", out.toString()); } public static void testFormatTo() throws IOException { System.setProperty("java.locale.providers", "COMPAT,SPI"); // Required since Java 10 to have all locale providers available Locale locale = null; assertEquals("null %s", "123456789", String.format(locale, "%s", new Apint("123456789"))); assertEquals("null %S", "123456789A", String.format(locale, "%S", new Apint("123456789a", 11))); assertEquals("null %10s", " 123456789", String.format(locale, "%10s", new Apint("123456789"))); assertEquals("null %-10s", "123456789 ", String.format(locale, "%-10s", new Apint("123456789"))); locale = new Locale("hi", "IN"); assertEquals("hi_IN %s", "१२३४५६७८९", String.format(locale, "%s", new Apint("123456789"))); assertEquals("hi_IN %s radix 9", "१२३४५६७८", String.format(locale, "%s", new Apint("12345678", 9))); assertEquals("hi_IN %s radix 11", "123456789", String.format(locale, "%s", new Apint("123456789", 11))); try { String.format(locale, "%#s", new Apint("123456789")); fail("# flag allowed"); } catch (IllegalFormatException ife) { // OK: alternate format not allowed with integers } try { String.format(locale, "%.1s", new Apint("123456789")); fail("Precision allowed"); } catch (IllegalFormatException ife) { // OK: precision not allowed with integers } } public static void testSerialization() throws IOException, ClassNotFoundException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(buffer); Apint a = new Apint(5); out.writeObject(a); out.close(); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray())); Apint b = (Apint) in.readObject(); assertEquals("5 equals", a, b); assertNotSame("5 !=", a, b); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/AprationalMathTest.java000066400000000000000000001157561461767713300262220ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import java.util.Arrays; import java.util.Iterator; import java.util.NoSuchElementException; import junit.framework.TestSuite; /** * @version 1.14.0 * @author Mikko Tommila */ public class AprationalMathTest extends ApfloatTestCase { public AprationalMathTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new AprationalMathTest("testIntegerPow")); suite.addTest(new AprationalMathTest("testScale")); suite.addTest(new AprationalMathTest("testAbs")); suite.addTest(new AprationalMathTest("testRound")); suite.addTest(new AprationalMathTest("testRoundToPrecision")); suite.addTest(new AprationalMathTest("testRoundToInteger")); suite.addTest(new AprationalMathTest("testRoundToPlaces")); suite.addTest(new AprationalMathTest("testRoundToMultiple")); suite.addTest(new AprationalMathTest("testCopySign")); suite.addTest(new AprationalMathTest("testNegate")); suite.addTest(new AprationalMathTest("testProduct")); suite.addTest(new AprationalMathTest("testSum")); suite.addTest(new AprationalMathTest("testContinuedFraction")); suite.addTest(new AprationalMathTest("testConvergents")); suite.addTest(new AprationalMathTest("testMax")); suite.addTest(new AprationalMathTest("testMin")); suite.addTest(new AprationalMathTest("testBinomial")); suite.addTest(new AprationalMathTest("testPochhammer")); suite.addTest(new AprationalMathTest("testBernoulli")); suite.addTest(new AprationalMathTest("testHarmonicNumber")); suite.addTest(new AprationalMathTest("testHarmonicNumberGeneralized")); return suite; } public static void testIntegerPow() { Aprational x = new Aprational("2"); assertEquals("2^30", new Aprational(new Apint(1 << 30)), AprationalMath.pow(x, 30)); assertEquals("2^60", new Aprational(new Apint(1L << 60)), AprationalMath.pow(x, 60)); assertEquals("2^5", new Aprational(new Apint(1L << 5)), AprationalMath.pow(x, 5)); assertEquals("2^-1", new Aprational("1/2"), AprationalMath.pow(x, -1)); assertEquals("2^-3", new Aprational("1/8"), AprationalMath.pow(x, -3)); assertEquals("2^0", new Aprational("1"), AprationalMath.pow(x, 0)); try { AprationalMath.pow(new Aprational(new Apint(0)), 0); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } } public static void testScale() { Aprational x = AprationalMath.scale(new Aprational("3/7"), 5); assertEquals("1 string", "300000/7", x.toString()); x = AprationalMath.scale(new Aprational("-7/9"), -1); assertEquals("-1 string", "-7/90", x.toString()); x = AprationalMath.scale(new Apfloat("1e" + 0x4000000000000000L, 1, 2).truncate(), Long.MIN_VALUE); assertEquals("scale min", new Apfloat("1e-" + 0x4000000000000000L, 1, 2), x); } @SuppressWarnings("deprecation") public static void testRound() { Apfloat x = AprationalMath.round(new Aprational("3/2"), 1, RoundingMode.UP); assertEquals("3/2 UP", "2", x.toString()); x = AprationalMath.round(new Aprational("3/2"), 1, RoundingMode.DOWN); assertEquals("3/2 DOWN", "1", x.toString()); x = AprationalMath.round(new Aprational("10/2", 3), 1, RoundingMode.HALF_EVEN); assertEquals("3/2 base 3 EVEN", "2", x.toString()); x = AprationalMath.round(new Aprational("12/2", 3), 1, RoundingMode.HALF_EVEN); assertEquals("5/2 base 3 EVEN", "2", x.toString()); x = AprationalMath.round(new Aprational("-10/2", 3), 1, RoundingMode.HALF_EVEN); assertEquals("-3/2 base 3 EVEN", "-2", x.toString()); x = AprationalMath.round(new Aprational("-12/2", 3), 1, RoundingMode.HALF_EVEN); assertEquals("-5/2 base 3 EVEN", "-2", x.toString()); } public static void testRoundToPrecision() { Apfloat x = AprationalMath.roundToPrecision(new Aprational("7/3"), 3, RoundingMode.UP); assertEquals("7/3 UP", "2.34", x.toString()); x = AprationalMath.roundToPrecision(new Aprational("1/2"), 1, RoundingMode.UNNECESSARY); assertEquals("1/2 UNNECESSARY", "0.5", x.toString(true)); try { AprationalMath.roundToPrecision(new Aprational(1000), 0, RoundingMode.HALF_EVEN); fail("precision 0 accepted"); } catch (IllegalArgumentException iae) { // OK; invalid precision } try { AprationalMath.roundToPrecision(new Aprational("1/3"), 1000, RoundingMode.UNNECESSARY); fail("rounding accepted"); } catch (ArithmeticException ae) { // OK; rounding needed } } public static void testRoundToInteger() { Apint x = AprationalMath.roundToInteger(new Aprational("3/2"), RoundingMode.UP); assertEquals("3/2 UP", "2", x.toString()); x = AprationalMath.roundToInteger(new Aprational("3/2"), RoundingMode.DOWN); assertEquals("3/2 DOWN", "1", x.toString()); x = AprationalMath.roundToInteger(new Aprational("10/2", 3), RoundingMode.HALF_EVEN); assertEquals("3/2 base 3 EVEN", "2", x.toString()); x = AprationalMath.roundToInteger(new Aprational("12/2", 3), RoundingMode.HALF_EVEN); assertEquals("5/2 base 3 EVEN", "2", x.toString()); x = AprationalMath.roundToInteger(new Aprational("-10/2", 3), RoundingMode.HALF_EVEN); assertEquals("-3/2 base 3 EVEN", "-2", x.toString()); x = AprationalMath.roundToInteger(new Aprational("-12/2", 3), RoundingMode.HALF_EVEN); assertEquals("-5/2 base 3 EVEN", "-2", x.toString()); try { AprationalMath.roundToInteger(new Aprational("1/2"), RoundingMode.UNNECESSARY); fail("rounding accepted"); } catch (ArithmeticException ae) { // OK; rounding needed } } public static void testRoundToPlaces() { Apfloat x = AprationalMath.roundToPlaces(new Aprational("4/3"), 1, RoundingMode.UP); assertEquals("4/3 UP", "1.4", x.toString()); x = AprationalMath.roundToPlaces(new Aprational("4/3"), 1, RoundingMode.DOWN); assertEquals("4/3 DOWN", "1.3", x.toString()); x = AprationalMath.roundToPlaces(new Aprational("10/2", 3), 1, RoundingMode.HALF_EVEN); assertEquals("3/2 base 3 EVEN", "1.1", x.toString()); x = AprationalMath.roundToPlaces(new Aprational("12/2", 3), 1, RoundingMode.HALF_EVEN); assertEquals("5/2 base 3 EVEN", "2.2", x.toString()); x = AprationalMath.roundToPlaces(new Aprational("-10/2", 3), 1, RoundingMode.HALF_EVEN); assertEquals("-3/2 base 3 EVEN", "-1.1", x.toString()); x = AprationalMath.roundToPlaces(new Aprational("-12/2", 3), 1, RoundingMode.HALF_EVEN); assertEquals("-5/2 base 3 EVEN", "-2.2", x.toString()); x = AprationalMath.roundToPlaces(new Aprational("7/3"), 3, RoundingMode.UP); assertEquals("7/3 UP", "2.334", x.toString()); x = AprationalMath.roundToPlaces(new Aprational("16/3"), 0, RoundingMode.UP); assertEquals("16/3 UP integer", "6", x.toString()); x = AprationalMath.roundToPlaces(new Aprational("16/3"), -1, RoundingMode.UP); assertEquals("16/3 UP -1", "10", x.toString(true)); x = AprationalMath.roundToPlaces(new Aprational("16/3"), -2, RoundingMode.UP); assertEquals("16/3 UP -2", "100", x.toString(true)); x = AprationalMath.roundToPlaces(new Aprational("1/2"), 1, RoundingMode.UNNECESSARY); assertEquals("1/2 UNNECESSARY", "0.5", x.toString(true)); try { AprationalMath.roundToPlaces(new Aprational("4/3"), Long.MIN_VALUE, RoundingMode.DOWN); fail("no overflow"); } catch (OverflowException oe) { // OK; should overflow } try { AprationalMath.roundToPlaces(new Aprational("1/3"), 1000, RoundingMode.UNNECESSARY); fail("rounding accepted"); } catch (ArithmeticException ae) { // OK; rounding needed } } public static void testRoundToMultiple() { Aprational x = AprationalMath.roundToMultiple(new Aprational("4/3"), new Aprational("3/2"), RoundingMode.UP); assertEquals("4/3 3/2 UP", "3/2", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("5/3"), new Aprational("3/2"), RoundingMode.UP); assertEquals("5/3 3/2 UP", "3", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("5/3"), new Aprational("3/2"), RoundingMode.DOWN); assertEquals("5/3 3/2 DOWN", "3/2", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("3/4"), new Aprational("1/2"), RoundingMode.HALF_DOWN); assertEquals("3/4 1/2 HALF_DOWN", "1/2", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("3/4"), new Aprational("1/2"), RoundingMode.HALF_UP); assertEquals("3/4 1/2 HALF_UP", "1", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("-3/4"), new Aprational("1/2"), RoundingMode.HALF_DOWN); assertEquals("-3/4 1/2 HALF_DOWN", "-1/2", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("-3/4"), new Aprational("1/2"), RoundingMode.HALF_UP); assertEquals("-3/4 1/2 HALF_UP", "-1", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("-3/4"), new Aprational("-1/2"), RoundingMode.HALF_DOWN); assertEquals("-3/4 -1/2 HALF_DOWN", "-1/2", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("-3/4"), new Aprational("-1/2"), RoundingMode.HALF_UP); assertEquals("-3/4 -1/2 HALF_UP", "-1", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("1/3"), new Aprational("2/3"), RoundingMode.HALF_EVEN); assertEquals("1/3 2/3 HALF_EVEN", "0", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("1"), new Aprational("2/3"), RoundingMode.HALF_EVEN); assertEquals("1 2/3 HALF_EVEN", "4/3", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("-1"), new Aprational("2/3"), RoundingMode.HALF_EVEN); assertEquals("-1 2/3 HALF_EVEN", "-4/3", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("7/6"), new Aprational("5/6"), RoundingMode.CEILING); assertEquals("7/6 5/6 CEILING", "5/3", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("-7/6"), new Aprational("5/6"), RoundingMode.CEILING); assertEquals("-7/6 5/6 CEILING", "-5/6", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("7/6"), new Aprational("5/6"), RoundingMode.FLOOR); assertEquals("7/6 5/6 FLOOR", "5/6", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("-7/6"), new Aprational("5/6"), RoundingMode.FLOOR); assertEquals("-7/6 5/6 FLOOR", "-5/3", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("1/2"), new Aprational("1/4"), RoundingMode.UNNECESSARY); assertEquals("1/2 UNNECESSARY", "1/2", x.toString()); x = AprationalMath.roundToMultiple(new Aprational("0"), new Aprational("1/4"), RoundingMode.UNNECESSARY); assertEquals("0 UNNECESSARY", "0", x.toString()); try { AprationalMath.roundToMultiple(new Aprational("1/3"), new Aprational("1/2"), RoundingMode.UNNECESSARY); fail("rounding accepted"); } catch (ArithmeticException ae) { // OK; rounding needed } try { AprationalMath.roundToMultiple(new Aprational("1/3"), new Aprational("0"), RoundingMode.UP); fail("Non-zero as multiple of zero"); } catch (ArithmeticException ae) { // OK; impossible } } public static void testAbs() { Aprational x = new Aprational("2/3"); assertEquals("2/3", new Aprational("2/3"), AprationalMath.abs(x)); x = new Aprational("-2/3"); assertEquals("-2/3", new Aprational("2/3"), AprationalMath.abs(x)); x = new Aprational("0"); assertEquals("0", new Aprational("0"), AprationalMath.abs(x)); } public static void testCopySign() { assertEquals("2/3, 1/2", new Aprational("2/3"), AprationalMath.copySign(new Aprational("2/3"), new Aprational("1/2"))); assertEquals("2/3, -1/2", new Aprational("-2/3"), AprationalMath.copySign(new Aprational("2/3"), new Aprational("-1/2"))); assertEquals("-2/3, 1/2", new Aprational("2/3"), AprationalMath.copySign(new Aprational("-2/3"), new Aprational("1/2"))); assertEquals("-2/3, -1/2", new Aprational("-2/3"), AprationalMath.copySign(new Aprational("-2/3"), new Aprational("-1/2"))); assertEquals("0, 0", new Aprational("0"), AprationalMath.copySign(new Aprational("0"), new Aprational("0"))); assertEquals("0, 1/2", new Aprational("0"), AprationalMath.copySign(new Aprational("0"), new Aprational("1/2"))); assertEquals("0, -1/2", new Aprational("0"), AprationalMath.copySign(new Aprational("0"), new Aprational("-1/2"))); assertEquals("1/2, 0", new Aprational("0"), AprationalMath.copySign(new Aprational("1/2"), new Aprational("0"))); assertEquals("-1/2, 0", new Aprational("0"), AprationalMath.copySign(new Aprational("-1/2"), new Aprational("0"))); } @SuppressWarnings("deprecation") public static void testNegate() { Aprational x = new Aprational("2/3"); assertEquals("2/3", new Aprational("-2/3"), AprationalMath.negate(x)); x = new Aprational("-2/3"); assertEquals("-2/3", new Aprational("2/3"), AprationalMath.negate(x)); x = new Aprational("0"); assertEquals("0", new Aprational("0"), AprationalMath.negate(x)); } public static void testProduct() { Aprational a = AprationalMath.product(new Aprational("2/3"), new Aprational("4/5")); assertEquals("2/3,4/5 value", new Aprational("8/15"), a); a = AprationalMath.product(new Aprational("2"), new Aprational("3/5"), new Aprational("7/11")); assertEquals("2,3/5,7/9 value", new Aprational("42/55"), a); a = AprationalMath.product(Aprational.ZERO, new Aprational("12345")); assertEquals("0 value", new Aprational("0"), a); a = AprationalMath.product(new Apint(0, 12)); assertEquals("0 radix", 12, a.radix()); Aprational[] x = new Aprational[] { new Aprational("1000000000000"), new Aprational("1") }; AprationalMath.product(x); assertEquals("Array product 1 [0]", new Aprational("1000000000000"), x[0]); assertEquals("Array product 1 [1]", new Aprational("1"), x[1]); x = new Aprational[] { new Aprational("1"), new Aprational("1000000000000") }; AprationalMath.product(x); assertEquals("Array product 2 [0]", new Aprational("1"), x[0]); assertEquals("Array product 2 [1]", new Aprational("1000000000000"), x[1]); assertEquals("Empty product", new Aprational("1"), AprationalMath.product()); } public static void testSum() { Aprational a = AprationalMath.sum(new Aprational("1/2"), new Aprational("2/3")); assertEquals("1/2,2/3 value", new Aprational("7/6"), a); a = AprationalMath.sum(new Aprational("2/3"), new Aprational("3/4"), new Aprational("4/5")); assertEquals("2/3,3/4,4/5 value", new Aprational("133/60"), a); a = AprationalMath.sum(new Aprational("0"), new Aprational("12345")); assertEquals("0-0 value", new Aprational("12345"), a); a = AprationalMath.sum(new Aprational("2")); assertEquals("2 value", new Aprational("2"), a); a = AprationalMath.sum(new Aprational("2"), new Aprational("222"), new Aprational("22")); assertEquals("2 222 22 value", new Aprational("246"), a); Aprational[] x = new Aprational[] { new Aprational("1000000000000"), new Aprational("1") }; AprationalMath.sum(x); assertEquals("Array sum 1 [0]", new Aprational("1000000000000"), x[0]); assertEquals("Array sum 1 [1]", new Aprational("1"), x[1]); x = new Aprational[] { new Aprational("1"), new Aprational("1000000000000") }; AprationalMath.sum(x); assertEquals("Array sum 2 [0]", new Aprational("1"), x[0]); assertEquals("Array sum 2 [1]", new Aprational("1000000000000"), x[1]); assertEquals("Empty sum", new Aprational("0"), AprationalMath.sum()); } public static void testContinuedFraction() { Aprational a = new Aprational("104348/33215"); assertEquals("104348/33215, 3", Arrays.asList(new Apint(3), new Apint(7), new Apint(15)), Arrays.asList(AprationalMath.continuedFraction(a, 3))); assertEquals("104348/33215, 30", Arrays.asList(new Apint(3), new Apint(7), new Apint(15), new Apint(1), new Apint(293)), Arrays.asList(AprationalMath.continuedFraction(a, 30))); assertEquals("104348/33215, 1", Arrays.asList(new Apint(3)), Arrays.asList(AprationalMath.continuedFraction(a, 1))); a = new Aprational("-104348/33215"); assertEquals("-104348/33215, 3", Arrays.asList(new Apint(-3), new Apint(-7), new Apint(-15)), Arrays.asList(AprationalMath.continuedFraction(a, 3))); assertEquals("-104348/33215, 30", Arrays.asList(new Apint(-3), new Apint(-7), new Apint(-15), new Apint(-1), new Apint(-293)), Arrays.asList(AprationalMath.continuedFraction(a, 30))); a = new Aprational("7114a/22963", 11); assertEquals("7114a/22963, 3", Arrays.asList(new Apint(3, 11), new Apint(7, 11), new Apint(15, 11)), Arrays.asList(AprationalMath.continuedFraction(a, 3))); assertEquals("7114a/22963, 30", Arrays.asList(new Apint(3, 11), new Apint(7, 11), new Apint(15, 11), new Apint(1, 11), new Apint(292, 11)), Arrays.asList(AprationalMath.continuedFraction(a, 30))); try { AprationalMath.continuedFraction(new Aprational(2), 0); fail("Zero n allowed"); } catch (IllegalArgumentException iae) { // OK } try { AprationalMath.continuedFraction(new Aprational(2), Integer.MIN_VALUE); fail("Negative n allowed"); } catch (IllegalArgumentException iae) { // OK } } public static void testConvergents() { Aprational a = new Aprational("104348/33215"); assertEquals("104348/33215, 3", Arrays.asList(new Aprational(3), new Aprational("22/7"), new Aprational("333/106")), Arrays.asList(AprationalMath.convergents(a, 3))); assertEquals("104348/33215, 30", Arrays.asList(new Aprational(3), new Aprational("22/7"), new Aprational("333/106"), new Aprational("355/113"), new Aprational("104348/33215")), Arrays.asList(AprationalMath.convergents(a, 30))); assertEquals("104348/33215, 1", Arrays.asList(new Aprational(3)), Arrays.asList(AprationalMath.convergents(a, 1))); a = new Aprational("-104348/33215"); assertEquals("-104348/33215, 3", Arrays.asList(new Aprational(-3), new Aprational("-22/7"), new Aprational("-333/106")), Arrays.asList(AprationalMath.convergents(a, 3))); assertEquals("-104348/33215, 30", Arrays.asList(new Aprational(-3), new Aprational("-22/7"), new Aprational("-333/106"), new Aprational("-355/113"), new Aprational("-104348/33215")), Arrays.asList(AprationalMath.convergents(a, 30))); a = new Aprational("7114a/22963", 11); assertEquals("7114a/22963, 3", Arrays.asList(new Aprational("3", 11), new Aprational("20/7", 11), new Aprational("283/97", 11)), Arrays.asList(AprationalMath.convergents(a, 3))); assertEquals("7114a/22963, 30", Arrays.asList(new Aprational("3", 11), new Aprational("20/7", 11), new Aprational("283/97", 11), new Aprational("2a3/a3", 11), new Aprational("7114a/22963", 11)), Arrays.asList(AprationalMath.convergents(a, 30))); try { AprationalMath.convergents(new Aprational(2), 0); fail("Zero n allowed"); } catch (IllegalArgumentException iae) { // OK } try { AprationalMath.convergents(new Aprational(2), Integer.MIN_VALUE); fail("Negative n allowed"); } catch (IllegalArgumentException iae) { // OK } } public static void testMax() { assertEquals("max of 1/2 and 1/2", new Aprational("1/2"), AprationalMath.max(new Aprational("1/2"), new Aprational("1/2"))); assertEquals("max of 1/2 and 2/3", new Aprational("2/3"), AprationalMath.max(new Aprational("1/2"), new Aprational("2/3"))); assertEquals("max of 2/3 and 1/2", new Aprational("2/3"), AprationalMath.max(new Aprational("2/3"), new Aprational("1/2"))); } public static void testMin() { assertEquals("min of 1/2 and 1/2", new Aprational("1/2"), AprationalMath.min(new Aprational("1/2"), new Aprational("1/2"))); assertEquals("min of 1/2 and 2/3", new Aprational("1/2"), AprationalMath.min(new Aprational("1/2"), new Aprational("2/3"))); assertEquals("min of 2/3 and 1/2", new Aprational("1/2"), AprationalMath.min(new Aprational("2/3"), new Aprational("1/2"))); } public static void testBinomial() { Aprational a = AprationalMath.binomial(new Aprational("0"), new Aprational("0")); assertEquals("0,0 value", new Aprational("1"), a); a = AprationalMath.binomial(new Aprational("-9"), new Aprational("2")); assertEquals("-9,2 value", new Aprational("45"), a); a = AprationalMath.binomial(new Aprational("19/3"), new Aprational("3")); assertEquals("19/3,3 value", new Aprational("1976/81"), a); a = AprationalMath.binomial(new Aprational("-19/3"), new Aprational("3")); assertEquals("-19/3,3 value", new Aprational("-5225/81"), a); a = AprationalMath.binomial(new Aprational("19/3"), new Aprational("-3")); assertEquals("19/3,-3 value", new Aprational("0"), a); a = AprationalMath.binomial(new Aprational("-19/3"), new Aprational("-3")); assertEquals("-19/3,-3 value", new Aprational("0"), a); a = AprationalMath.binomial(new Aprational("7/3"), new Aprational("4")); assertEquals("7/3,4 value", new Aprational("-7/243"), a); a = AprationalMath.binomial(new Aprational("-7/3"), new Aprational("4")); assertEquals("-7/3,4 value", new Aprational("1820/243"), a); a = AprationalMath.binomial(new Aprational("7/3"), new Aprational("-4")); assertEquals("7/3,-4 value", new Aprational("0"), a); a = AprationalMath.binomial(new Aprational("-7/3"), new Aprational("-4")); assertEquals("-7/3,-4 value", new Aprational("0"), a); a = AprationalMath.binomial(new Aprational("19/3"), new Aprational("4/3")); assertEquals("19/3,4/3 value", new Aprational("6916/729"), a); a = AprationalMath.binomial(new Aprational("-19/3"), new Aprational("-4/3")); assertEquals("-19/3,-4/3 value", new Aprational("0"), a); a = AprationalMath.binomial(new Aprational("4/3"), new Aprational("19/3")); assertEquals("4/3,19/3 value", new Aprational("0"), a); a = AprationalMath.binomial(new Aprational("-4/3"), new Aprational("-19/3")); assertEquals("-4/3,-19/3 value", new Aprational("-1456/729"), a); try { AprationalMath.binomial(new Aprational("9"), new Aprational("4/3")); fail("9,4/3 accepted"); } catch (ArithmeticException ae) { // OK; result is not a rational number } try { AprationalMath.binomial(new Aprational("9"), new Aprational("-4/3")); fail("9,-4/3 accepted"); } catch (ArithmeticException ae) { // OK; result is not a rational number } try { AprationalMath.binomial(new Aprational("-9"), new Aprational("4/3")); fail("-9,4/3 accepted"); } catch (ArithmeticException ae) { // OK; result is infinite } try { AprationalMath.binomial(new Aprational("-9"), new Aprational("-4/3")); fail("-9,-4/3 accepted"); } catch (ArithmeticException ae) { // OK; result is infinite } try { AprationalMath.binomial(new Aprational("2"), new Aprational("19/3")); fail("2,19/3 accepted"); } catch (ArithmeticException ae) { // OK; result is not a rational number } try { AprationalMath.binomial(new Aprational("2"), new Aprational("-19/3")); fail("2,-19/3 accepted"); } catch (ArithmeticException ae) { // OK; result is not a rational number } try { AprationalMath.binomial(new Aprational("-2"), new Aprational("19/3")); fail("-2,19/3 accepted"); } catch (ArithmeticException ae) { // OK; result is infinite } try { AprationalMath.binomial(new Aprational("-2"), new Aprational("-19/3")); fail("-2,-19/3 accepted"); } catch (ArithmeticException ae) { // OK; result is infinite } try { AprationalMath.binomial(new Aprational("-19/3"), new Aprational("4/3")); fail("-19/3,4/3 accepted"); } catch (ArithmeticException ae) { // OK; result is not a rational number } try { AprationalMath.binomial(new Aprational("19/3"), new Aprational("-4/3")); fail("19/3,-4/3 accepted"); } catch (ArithmeticException ae) { // OK; result is not a rational number } try { AprationalMath.binomial(new Aprational("-4/3"), new Aprational("19/3")); fail("-4/3,19/3 accepted"); } catch (ArithmeticException ae) { // OK; result is not a rational number } try { AprationalMath.binomial(new Aprational("4/3"), new Aprational("-19/3")); fail("4/3,-19/3 accepted"); } catch (ArithmeticException ae) { // OK; result is not a rational number } try { AprationalMath.binomial(new Aprational("300000000000000000000/2"), new Aprational("100000000000000000000")); fail("Overflow allowed"); } catch (OverflowException oe) { // OK: overflow } } public static void testPochhammer() { Aprational a = AprationalMath.pochhammer(new Aprational("0"), new Apint("0")); assertEquals("0, 0 value", new Aprational("1"), a); a = AprationalMath.pochhammer(new Aprational("2"), new Apint("0")); assertEquals("2, 0 value", new Aprational("1"), a); a = AprationalMath.pochhammer(new Aprational("2"), new Apint("1")); assertEquals("2, 1 value", new Aprational("2"), a); a = AprationalMath.pochhammer(new Aprational("2/3"), new Apint("4")); assertEquals("2/3, 4 value", new Aprational("880/81"), a); a = AprationalMath.pochhammer(new Aprational("2/3"), new Apint("-4")); assertEquals("2/3, -4 value", new Aprational("81/280"), a); a = AprationalMath.pochhammer(new Aprational("2/3", 5), new Apint("-4", 5)); assertEquals("2/3, -4 radix 5 value", new Aprational("311/2110", 5), a); } public static void testBernoulli() { Aprational a = AprationalMath.bernoulli(0L); assertEquals("0 value", new Aprational("1"), a); a = AprationalMath.bernoulli(1L); assertEquals("1 value", new Aprational("-1/2"), a); a = AprationalMath.bernoulli(2L); assertEquals("2 value", new Aprational("1/6"), a); a = AprationalMath.bernoulli(3L); assertEquals("3 value", new Aprational("0"), a); a = AprationalMath.bernoulli(4L); assertEquals("4 value", new Aprational("-1/30"), a); a = AprationalMath.bernoulli(6, 7); assertEquals("6 value", new Aprational("1/60", 7), a); // This is *extremely* time-consuming //assertEquals("Big equals small", AprationalMath.bernoulliSmall(2001, 10), AprationalMath.bernoulli(2001)); Iterator iterator = AprationalMath.bernoullis(4, 10); assertEquals("iterator hasNext", true, iterator.hasNext()); assertEquals("iterator next 1", new Aprational("1"), iterator.next()); assertEquals("iterator next 2", new Aprational("-1/2"), iterator.next()); assertEquals("iterator next 3", new Aprational("1/6"), iterator.next()); assertEquals("iterator next 4", new Aprational("0"), iterator.next()); assertEquals("iterator next 5", new Aprational("-1/30"), iterator.next()); iterator = AprationalMath.bernoullisSmall(10); assertEquals("iteratorSmall hasNext", true, iterator.hasNext()); assertEquals("iteratorSmall next 1", new Aprational("1"), iterator.next()); assertEquals("iteratorSmall next 2", new Aprational("-1/2"), iterator.next()); assertEquals("iteratorSmall next 3", new Aprational("1/6"), iterator.next()); assertEquals("iteratorSmall next 4", new Aprational("0"), iterator.next()); assertEquals("iteratorSmall next 5", new Aprational("-1/30"), iterator.next()); assertEquals("iteratorSmall hasNext 2", true, iterator.hasNext()); iterator = AprationalMath.bernoullisBig(4, 10); assertEquals("iteratorBig hasNext", true, iterator.hasNext()); assertEquals("iteratorBig next 1", new Aprational("1"), iterator.next()); assertEquals("iteratorBig next 2", new Aprational("-1/2"), iterator.next()); assertEquals("iteratorBig next 3", new Aprational("1/6"), iterator.next()); assertEquals("iteratorBig next 4", new Aprational("0"), iterator.next()); assertEquals("iteratorBig next 5", new Aprational("-1/30"), iterator.next()); assertEquals("iteratorBig hasNext 2", false, iterator.hasNext()); try { iterator.next(); fail("iteratorBig allowed next"); } catch (NoSuchElementException nsee) { // OK } iterator = AprationalMath.bernoullisSmall(2); Iterator iterator2 = AprationalMath.bernoullisBig(100, 2); for (int i = 0; i <= 100; i++) { a = (i > 0 ? AprationalMath.bernoulliSmall(i, 2) : AprationalMath.bernoulli(i, 2)); assertEquals("directSmall vs iteratorSmall " + i, a, iterator.next()); assertEquals("directSmall vs iteratorBig " + i, a, iterator2.next()); if (i % 2 == 0 && i > 0) { assertEquals("directSmall vs directBig " + i, a, AprationalMath.bernoulliBig(i, 2)); } } iterator = AprationalMath.bernoullis(4, 15); assertEquals("iterator radix 15 next 1", new Aprational("1", 15), iterator.next()); assertEquals("iterator radix 15 next 2", new Aprational("-1/2", 15), iterator.next()); assertEquals("iterator radix 15 next 3", new Aprational("1/6", 15), iterator.next()); assertEquals("iterator radix 15 next 4", new Aprational("0", 15), iterator.next()); assertEquals("iterator radix 15 next 5", new Aprational("-1/20", 15), iterator.next()); iterator = AprationalMath.bernoullisSmall(15); assertEquals("iteratorSmall radix 15 next 1", new Aprational("1", 15), iterator.next()); assertEquals("iteratorSmall radix 15 next 2", new Aprational("-1/2", 15), iterator.next()); assertEquals("iteratorSmall radix 15 next 3", new Aprational("1/6", 15), iterator.next()); assertEquals("iteratorSmall radix 15 next 4", new Aprational("0", 15), iterator.next()); assertEquals("iteratorSmall radix 15 next 5", new Aprational("-1/20", 15), iterator.next()); iterator = AprationalMath.bernoullisBig(4, 15); assertEquals("iteratorBig radix 15 next 1", new Aprational("1", 15), iterator.next()); assertEquals("iteratorBig radix 15 next 2", new Aprational("-1/2", 15), iterator.next()); assertEquals("iteratorBig radix 15 next 3", new Aprational("1/6", 15), iterator.next()); assertEquals("iteratorBig radix 15 next 4", new Aprational("0", 15), iterator.next()); assertEquals("iteratorBig radix 15 next 5", new Aprational("-1/20", 15), iterator.next()); iterator = AprationalMath.bernoullis2(2, 10); assertEquals("iterator2 hasNext", true, iterator.hasNext()); assertEquals("iterator2 next 1", new Aprational("1/6"), iterator.next()); assertEquals("iterator2 next 2", new Aprational("-1/30"), iterator.next()); iterator = AprationalMath.bernoullis2Small(10); assertEquals("iterator2Small hasNext", true, iterator.hasNext()); assertEquals("iterator2Small next 1", new Aprational("1/6"), iterator.next()); assertEquals("iterator2Small next 2", new Aprational("-1/30"), iterator.next()); assertEquals("iterator2Small hasNext 2", true, iterator.hasNext()); iterator = AprationalMath.bernoullis2Big(2, 10); assertEquals("iterator2Big hasNext", true, iterator.hasNext()); assertEquals("iterator2Big next 1", new Aprational("1/6"), iterator.next()); assertEquals("iterator2Big next 2", new Aprational("-1/30"), iterator.next()); assertEquals("iterator2Big hasNext 2", false, iterator.hasNext()); try { iterator.next(); fail("iterator2Big allowed next"); } catch (NoSuchElementException nsee) { // OK } for (int radix = 2; radix <= 36; radix++) { iterator = AprationalMath.bernoullisSmall(radix); iterator2 = AprationalMath.bernoullisBig(50, radix); for (int i = 0; i <= 50; i++) { assertEquals("iteratorSmall vs iteratorBig " + i + " radix " + radix, iterator.next(), iterator2.next()); } } try { AprationalMath.bernoulli(-1); fail("-1 accepted"); } catch (IllegalArgumentException iae) { // OK } } public static void testHarmonicNumber() { Aprational a = AprationalMath.harmonicNumber(new Apint(4)); assertEquals("4 value", new Aprational("25/12"), a); a = AprationalMath.harmonicNumber(new Apint("3")); assertEquals("3 value", new Aprational("11/6"), a); a = AprationalMath.harmonicNumber(new Apint(0)); assertEquals("0 value", new Aprational("0"), a); a = AprationalMath.harmonicNumber(new Apint("6")); assertEquals("6 value", new Aprational("49/20"), a); a = AprationalMath.harmonicNumber(new Apint("6", 7)); assertEquals("6 radix", 7, a.radix()); assertEquals("6 value", new Aprational("100/26", 7), a); try { AprationalMath.harmonicNumber(new Apint(-1)); fail("-1 accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } public static void testHarmonicNumberGeneralized() { Aprational a = AprationalMath.harmonicNumber(new Apint(3), new Apint(4)); assertEquals("3, 4 value", new Aprational("1393/1296"), a); a = AprationalMath.harmonicNumber(new Apint("2"), new Apint("3")); assertEquals("2, 3 value", new Aprational("9/8"), a); a = AprationalMath.harmonicNumber(new Apint("7"), new Apint("-5")); assertEquals("7, -5 value", new Aprational("29008"), a); a = AprationalMath.harmonicNumber(new Apint(0), new Apint(0)); assertEquals("0, 0 value", new Aprational("0"), a); a = AprationalMath.harmonicNumber(new Apint(0), new Apint(1)); assertEquals("0, 1 value", new Aprational("0"), a); a = AprationalMath.harmonicNumber(new Apint("-1"), new Apint("0")); assertEquals("-1, 0 value", new Aprational("-1"), a); a = AprationalMath.harmonicNumber(new Apint("-3"), new Apint("-2")); assertEquals("-3, -2 value", new Aprational("-5"), a); a = AprationalMath.harmonicNumber(new Apint("-6"), new Apint("-4")); assertEquals("-6, -4 value", new Aprational("-979"), a); a = AprationalMath.harmonicNumber(new Apint("6", 7), new Apint("4", 7)); assertEquals("6, 4 radix", 7, a.radix()); assertEquals("6, 4 value", new Aprational("230044310/215105154", 7), a); try { AprationalMath.harmonicNumber(new Apint(-1), new Apint(2)); fail("-1, 2 accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/AprationalTest.java000066400000000000000000001306541461767713300254020ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.BigInteger; import java.io.PushbackReader; import java.io.StringReader; import java.io.StringWriter; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; import java.util.Locale; import java.util.IllegalFormatException; import junit.framework.TestSuite; /** * @version 1.10.0 * @author Mikko Tommila */ public class AprationalTest extends ApfloatTestCase { public AprationalTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new AprationalTest("testApintConstructor")); suite.addTest(new AprationalTest("testStringConstructor")); suite.addTest(new AprationalTest("testStreamConstructor")); suite.addTest(new AprationalTest("testBigIntegerConstructor")); suite.addTest(new AprationalTest("testRationalMethods")); suite.addTest(new AprationalTest("testIsShort")); suite.addTest(new AprationalTest("testRadix")); suite.addTest(new AprationalTest("testPrecision")); suite.addTest(new AprationalTest("testScale")); suite.addTest(new AprationalTest("testSize")); suite.addTest(new AprationalTest("testIsInteger")); suite.addTest(new AprationalTest("testNegate")); suite.addTest(new AprationalTest("testAdd")); suite.addTest(new AprationalTest("testSubtract")); suite.addTest(new AprationalTest("testMultiply")); suite.addTest(new AprationalTest("testDivide")); suite.addTest(new AprationalTest("testMod")); suite.addTest(new AprationalTest("testFloor")); suite.addTest(new AprationalTest("testCeil")); suite.addTest(new AprationalTest("testTruncate")); suite.addTest(new AprationalTest("testFrac")); suite.addTest(new AprationalTest("testRoundAway")); suite.addTest(new AprationalTest("testAbs")); suite.addTest(new AprationalTest("testCompareToHalf")); suite.addTest(new AprationalTest("testNumberValues")); suite.addTest(new AprationalTest("testEqualDigits")); suite.addTest(new AprationalTest("testCompareTo")); suite.addTest(new AprationalTest("testEquals")); suite.addTest(new AprationalTest("testTest")); suite.addTest(new AprationalTest("testHashCode")); suite.addTest(new AprationalTest("testToString")); suite.addTest(new AprationalTest("testWriteTo")); suite.addTest(new AprationalTest("testFormatTo")); suite.addTest(new AprationalTest("testSerialization")); return suite; } public static void testApintConstructor() { Aprational a = new Aprational(new Apint(5)); assertEquals("5 String", "5", a.toString()); a = new Aprational(new Apint(5), new Apint(6)); assertEquals("5/6 String", "5/6", a.toString()); a = new Aprational(new Apint(0), new Apint(6)); assertEquals("0/6 String", "0", a.toString()); assertEquals("0/6 denominator", new Apint(1), a.denominator()); a = new Aprational(new Apint(5), new Apint(-6)); assertEquals("5/-6 numerator", new Apint(-5), a.numerator()); assertEquals("5/-6 denominatoror", new Apint(6), a.denominator()); assertEquals("5/-6 String", "-5/6", a.toString()); a = new Aprational(new Apint(-5), new Apint(6)); assertEquals("-5/6 numerator", new Apint(-5), a.numerator()); assertEquals("-5/6 denominatoror", new Apint(6), a.denominator()); assertEquals("-5/6 String", "-5/6", a.toString()); a = new Aprational(new Apint(-5), new Apint(-6)); assertEquals("-5/-6 numerator", new Apint(5), a.numerator()); assertEquals("-5/-6 denominatoror", new Apint(6), a.denominator()); assertEquals("-5/-6 String", "5/6", a.toString()); a = new Aprational(new Apint(15), new Apint(-12)); assertEquals("15/-12 numerator", new Apint(-5), a.numerator()); assertEquals("15/-12 denominatoror", new Apint(4), a.denominator()); assertEquals("15/-12 String", "-5/4", a.toString()); a = new Aprational(new Apint(1, 10), new Apint(6, 12)); a = new Aprational(new Apint(6, 10), new Apint(1, 12)); try { a = new Aprational(new Apint(2), new Apint(0)); fail("2/0 accepted"); } catch (IllegalArgumentException iae) { // OK: result would be infinite } } public static void testStringConstructor() { Apfloat a = new Aprational("5"); assertEquals("5 radix", 10, a.radix()); assertEquals("5 String", "5", a.toString()); a = new Aprational("0/6"); assertEquals("0/6 String", "0", a.toString()); a = new Aprational("0/-6"); assertEquals("0/-6 String", "0", a.toString()); a = new Aprational("5/6"); assertEquals("5/6 String", "5/6", a.toString()); a = new Aprational("5 / 6"); assertEquals("5 / 6 String", "5/6", a.toString()); a = new Aprational("-5/6"); assertEquals("-5/6 String", "-5/6", a.toString()); a = new Aprational("5/-6"); assertEquals("5/-6 String", "-5/6", a.toString()); a = new Aprational("-5/-6"); assertEquals("-5/-6 String", "5/6", a.toString()); a = new Aprational("55/67"); assertEquals("55/67 String", "55/67", a.toString()); a = new Aprational("ab/-bc", 13); assertEquals("ab/-bc radix", 13, a.radix()); assertEquals("ab/-bc String", "-ab/bc", a.toString()); try { a = new Aprational("2/"); fail("2/ accepted"); } catch (NumberFormatException nfe) { // OK: illegal number } try { a = new Aprational("2/0"); fail("2/0 accepted"); } catch (IllegalArgumentException iae) { // OK: result would be infinite } } public static void testStreamConstructor() throws IOException { PushbackReader in = new PushbackReader(new StringReader("5")); Apfloat a = new Aprational(in); assertEquals("5 radix", 10, a.radix()); assertEquals("5 String", "5", a.toString()); in = new PushbackReader(new StringReader("5/6")); a = new Aprational(in); assertEquals("5/6 String", "5/6", a.toString()); in = new PushbackReader(new StringReader("5 / 6")); a = new Aprational(in); assertEquals("5 / 6 String", "5/6", a.toString()); in = new PushbackReader(new StringReader("55/67")); a = new Aprational(in); assertEquals("55/67 String", "55/67", a.toString()); in = new PushbackReader(new StringReader("ab/-bc")); a = new Aprational(in, 13); assertEquals("ab/-bc radix", 13, a.radix()); assertEquals("ab/-bc String", "-ab/bc", a.toString()); in = new PushbackReader(new StringReader("5*")); a = new Aprational(in); assertEquals("5* String", "5", a.toString()); assertEquals("5* next char", '*', in.read()); try { in = new PushbackReader(new StringReader("2/")); a = new Aprational(in); fail("2/ accepted"); } catch (NumberFormatException nfe) { // OK: illegal number } try { in = new PushbackReader(new StringReader("2/0")); a = new Aprational(in); fail("2/0 accepted"); } catch (IllegalArgumentException iae) { // OK: result would be infinite } } public static void testBigIntegerConstructor() { Aprational a = new Aprational(BigInteger.valueOf(5)); assertEquals("5 radix", 10, a.radix()); assertEquals("5 String", "5", a.toString()); a = new Aprational(BigInteger.valueOf(11), 12); assertEquals("11 radix", 12, a.radix()); assertEquals("11 String", "b", a.toString()); } public static void testDoubleConstructor() { Aprational a = new Aprational(0.1); assertEquals("0.1 radix", 10, a.radix()); assertEquals("0.1 String", "3602879701896397/36028797018963968", a.toString()); a = new Aprational(1.0, 12); assertEquals("1 radix", 12, a.radix()); assertEquals("1 String", "1", a.toString()); a = new Aprational(0.0, 5); assertEquals("0 radix", 5, a.radix()); assertEquals("0 String", "0", a.toString()); a = new Aprational(1.0 / 256.0); assertEquals("1/256 radix", 10, a.radix()); assertEquals("1/256 precision 6 String", "0.00390625", a.precision(6).toString(true)); a = new Aprational(-1.0 / 16.0, 35); assertEquals("-1/16 radix", 35, a.radix()); assertEquals("-1/16 String", "-1/g", a.toString()); a = new Aprational(32.0, 33); assertEquals("32 radix", 33, a.radix()); assertEquals("32 String", "w", a.toString()); a = new Aprational(Double.MAX_VALUE); assertEquals("max value radix", 10, a.radix()); assertEquals("max value String", "179769313486231570814527423731704356798070567525844996598917476803157260780028538760589558632766878171540458953514382464234321326889464182768467546703537516986049910576551282076245490090389328944075868508455133942304583236903222948165808559332123348274797826204144723168738177180919299881250404026184124858368", a.toString()); a = new Aprational(Double.MIN_VALUE); assertEquals("min value radix", 10, a.radix()); assertEquals("min value", AprationalMath.pow(new Aprational("2"), -1074), a); } public static void testRationalMethods() { Aprational a = new Aprational("5/8"); assertEquals("numerator", new Apint(5), a.numerator()); assertEquals("denominator", new Apint(8), a.denominator()); } public static void testIsShort() { Aprational a = new Aprational("5"); assertTrue("5", a.isShort()); a = new Aprational(new Apint(Long.MAX_VALUE)); assertFalse("MAX", a.isShort()); a = new Aprational("1/2"); assertFalse("1/2", a.isShort()); } public static void testRadix() { Aprational a = new Aprational("2", 5); assertEquals("radix", 5, a.radix()); a = new Aprational(Apint.ONE, new Apint(2, 3)); assertEquals("1/2", 3, a.radix()); a = new Aprational("16/255"); assertEquals("10 -> 16", new Aprational("10/FF", 16), a.toRadix(16)); } public static void testPrecision() { Aprational a = new Aprational("5"); assertEquals("precision", Aprational.INFINITE, a.precision()); a = new Aprational("2/3"); assertEquals("approx 50", new Apfloat("0.66666666666666666666666666666666666666666666666666"), a.precision(50)); assertEquals("approx 100", new Apfloat("0.6666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666"), a.precision(100)); assertEquals("approx 60", new Apfloat("0.666666666666666666666666666666666666666666666666666666666666"), a.precision(60)); a = new Aprational(new Apint(2), new Apint(Long.MAX_VALUE)); assertEquals("MAX approx 50 precision", 50, a.precision(50).precision()); } public static void testScale() { Aprational a = new Aprational("9"); assertEquals("9 scale", 1, a.scale()); assertEquals("9 scale cached", 1, a.scale()); a = new Aprational("10"); assertEquals("10 scale", 2, a.scale()); a = new Aprational("1/10"); assertEquals("1/10 scale", 0, a.scale()); a = new Aprational("9/10"); assertEquals("9/10 scale", 0, a.scale()); a = new Aprational("1/100"); assertEquals("1/100 scale", -1, a.scale()); a = new Aprational("9/100"); assertEquals("9/100 scale", -1, a.scale()); a = new Aprational("99/100"); assertEquals("99/100 scale", 0, a.scale()); a = new Aprational("1/101"); assertEquals("1/101 scale", -2, a.scale()); a = new Aprational("1/2"); assertEquals("1/2 scale", 0, a.scale()); a = new Aprational("1/3"); assertEquals("1/3 scale", 0, a.scale()); a = new Aprational("1/9"); assertEquals("1/9 scale", 0, a.scale()); a = new Aprational("1/11"); assertEquals("1/11 scale", -1, a.scale()); a = new Aprational("0"); assertEquals("0 scale", -Aprational.INFINITE, a.scale()); a = new Aprational("101010101010101010101010101010101010101010101/101010101010101010101010101010101010101010102"); assertEquals("101...101/101...102 scale", 0, a.scale()); a = new Aprational("101010101010101010101010101010101010101010102/101010101010101010101010101010101010101010101"); assertEquals("101...102/101...101 scale", 1, a.scale()); a = new Aprational("9"); assertEquals("9 scaled 1", new Aprational("90"), a.scale(1)); assertEquals("9 scaled -1", new Aprational("9/10"), a.scale(-1)); } public static void testSize() { Aprational a = new Aprational("9"); assertEquals("9 size", 1, a.size()); a = new Aprational("10"); assertEquals("10 size", 1, a.size()); a = new Aprational("1/10"); assertEquals("1/10 size", 1, a.size()); a = new Aprational("9/10"); assertEquals("9/10 size", 1, a.size()); a = new Aprational("-99/100"); assertEquals("-99/100 size", 2, a.size()); a = new Aprational("199/2"); assertEquals("199/2 size", 3, a.size()); a = new Aprational("1/2"); assertEquals("1/2 size", 1, a.size()); a = new Aprational("1/3"); assertEquals("1/3 size", Aprational.INFINITE, a.size()); a = new Aprational("1/18446744073709551616"); assertEquals("1/2^64 size", 45, a.size()); a = new Aprational("1/542101086242752217003726400434970855712890625"); assertEquals("1/5^64 size", 20, a.size()); a = new Aprational("1/7orp63sh4dphi", 34); assertEquals("1/2^64 radix 34 size", 52, a.size()); a = new Aprational("1/18446744073709551617"); assertEquals("1/(2^64+1) size", Aprational.INFINITE, a.size()); a = new Aprational("-1/18446744073709551617"); assertEquals("-1/(2^64+1) size", Aprational.INFINITE, a.size()); a = new Aprational("101010101010101010101010101010101010101010102/101010101010101010101010101010101010101010101"); assertEquals("101...102/101...101 size", Aprational.INFINITE, a.size()); a = new Aprational("-101010101010101010101010101010101010101010102/101010101010101010101010101010101010101010101"); assertEquals("-101...102/101...101 size", Aprational.INFINITE, a.size()); a = new Aprational("0"); assertEquals("0 size", 0, a.size()); } public static void testIsInteger() { Aprational a = new Aprational("1/2"); assertFalse("1/2", a.isInteger()); a = new Aprational("0"); assertTrue("0", a.isInteger()); a = new Aprational("0/2"); assertTrue("0/2", a.isInteger()); a = new Aprational("1"); assertTrue("1", a.isInteger()); a = new Aprational("-1/1"); assertTrue("-1/1", a.isInteger()); } public static void testNegate() { Aprational x = new Aprational("2/3"); assertEquals("2/3", new Aprational("-2/3"), x.negate()); x = new Aprational("-2/3"); assertEquals("-2/3", new Aprational("2/3"), x.negate()); x = new Aprational("0"); assertEquals("0", new Aprational("0"), x.negate()); Apfloat y = new Aprational("2/3"); assertEquals("-2", new Aprational("-2/3"), y.negate()); } public static void testAdd() { Aprational a = new Aprational("1/5"), b = new Aprational("2/5"); assertEquals("1/5 + 2/5", new Aprational("3/5"), a.add(b)); assertEquals("1/5 + 0", new Aprational("1/5"), a.add(new Aprational("0"))); assertEquals("0 + 1/5", new Aprational("1/5"), Aprational.ZERO.add(a)); a = new Aprational("1/3"); b = new Aprational("2/3"); assertEquals("1/3 + 2/3", new Aprational("1"), a.add(b)); a = new Aprational("1/3"); b = new Aprational("-1/3"); assertEquals("1/3 + -1/3", new Aprational("0"), a.add(b)); assertEquals("1/3 + -1/3 denominator", new Apint(1), a.add(b).denominator()); a = new Aprational("1/24"); b = new Aprational("5/24"); assertEquals("1/24 + 5/24", new Aprational("1/4"), a.add(b)); a = new Aprational("2", 12); b = new Aprational("3", 12); assertEquals("2 + 3", new Aprational("5", 12), a.add(b)); } public static void testSubtract() { Aprational a = new Aprational("1/5"), b = new Aprational("2/5"); assertEquals("1/5 - 2/5", new Aprational("-1/5"), a.subtract(b)); assertEquals("1/5 - 0", new Aprational("1/5"), a.subtract(new Aprational("0"))); assertEquals("0 - 1/5", new Aprational("-1/5"), Aprational.ZERO.subtract(a)); a = new Aprational("-1/3"); b = new Aprational("2/3"); assertEquals("-1/3 - 2/3", new Aprational("-1"), a.subtract(b)); a = new Aprational("1/3"); b = new Aprational("1/3"); assertEquals("1/3 - 1/3", new Aprational("0"), a.subtract(b)); assertEquals("1/3 - 1/3 denominator", new Apint(1), a.subtract(b).denominator()); a = new Aprational("7/24"); b = new Aprational("5/24"); assertEquals("7/24 - 5/24", new Aprational("1/12"), a.subtract(b)); a = new Aprational("2", 12); b = new Aprational("7", 12); assertEquals("2 - 7", new Aprational("-5", 12), a.subtract(b)); } public static void testMultiply() { Aprational a = new Aprational("1/5"), b = new Aprational("2/5"); assertEquals("1/5 * 2/5", new Aprational("2/25"), a.multiply(b)); assertEquals("1/5 * 0", new Aprational("0"), a.multiply(new Aprational("0"))); assertEquals("0 * 1/5", new Aprational("0"), Aprational.ZERO.multiply(a)); assertEquals("1/5 * 1", new Aprational("1/5"), a.multiply(new Aprational("1"))); assertEquals("1 * 1/5", new Aprational("1/5"), new Aprational("1").multiply(a)); assertEquals("1/5 * ONE", new Aprational("1/5", 12), new Aprational("1/5", 12).multiply(Aprational.ONE)); assertEquals("ONE * 1/5", new Aprational("1/5", 12), Aprational.ONE.multiply(new Aprational("1/5", 12))); a = new Aprational("1/3"); b = new Aprational("3/2"); assertEquals("1/3 * 3/2", new Aprational("1/2"), a.multiply(b)); a = new Aprational("1/3"); b = new Aprational("-3"); assertEquals("1/3 * -3", new Aprational("-1"), a.multiply(b)); } public static void testDivide() { Aprational a = new Aprational("1/5"), b = new Aprational("2/5"); assertEquals("1/5 / 2/5", new Aprational("1/2"), a.divide(b)); assertEquals("0 / 1/5", new Aprational("0"), Aprational.ZERO.divide(a)); assertEquals("1/5 / 1", new Aprational("1/5"), a.divide(new Aprational("1"))); assertEquals("1/5 / ONE", new Aprational("1/5", 12), new Aprational("1/5", 12).divide(Aprational.ONE)); a = new Aprational("1/3"); b = new Aprational("3/2"); assertEquals("1/3 / 3/2", new Aprational("2/9"), a.divide(b)); a = new Aprational("1/3"); b = new Aprational("-1/3"); assertEquals("1/3 / -1/3", new Aprational("-1"), a.divide(b)); try { a.divide(new Aprational("0")); fail("Division by zero allowed"); } catch (ArithmeticException ae) { // OK: division by zero } } public static void testMod() { assertEquals("0, 1", new Aprational("0"), new Aprational("0").mod(Aprational.ONE)); assertEquals("1, 0", new Aprational("0"), new Aprational("1").mod(Aprational.ZERO)); assertEquals("2, 3", new Aprational("2"), new Aprational("2").mod(new Aprational("3"))); assertEquals("2, -3", new Aprational("2"), new Aprational("2").mod(new Aprational("-3"))); assertEquals("-2, 3", new Aprational("-2"), new Aprational("-2").mod(new Aprational("3"))); assertEquals("-2, -3", new Aprational("-2"), new Aprational("-2").mod(new Aprational("-3"))); assertEquals("3, 2", new Aprational("1"), new Aprational("3").mod(new Aprational("2"))); assertEquals("3, -2", new Aprational("1"), new Aprational("3").mod(new Aprational("-2"))); assertEquals("-3, 2", new Aprational("-1"), new Aprational("-3").mod(new Aprational("2"))); assertEquals("-3, -2", new Aprational("-1"), new Aprational("-3").mod(new Aprational("-2"))); assertEquals("11/4, 2/3", new Aprational("1/12"), new Aprational("11/4").mod(new Aprational("2/3"))); assertEquals("11/4, -2/3", new Aprational("1/12"), new Aprational("11/4").mod(new Aprational("-2/3"))); assertEquals("-11/4, 2/3", new Aprational("-1/12"), new Aprational("-11/4").mod(new Aprational("2/3"))); assertEquals("-11/4, -2/3", new Aprational("-1/12"), new Aprational("-11/4").mod(new Aprational("-2/3"))); } public static void testFloor() { Aprational a = new Aprational("11/10"); assertEquals("11/10 floor", new Apint(1), a.floor()); assertEquals("11/10 floor reverse", a.floor(), new Apint(1)); a = new Aprational("1"); assertEquals("1 floor", new Apint(1), a.floor()); a = new Aprational("199999999999999/200000000000000"); assertEquals("199999999999999/200000000000000 floor", new Apint(0), a.floor()); a = new Aprational("-11/10"); assertEquals("-11/10 floor", new Apint(-2), a.floor()); a = new Aprational("0"); assertEquals("0 floor", new Apint(0), a.floor()); } public static void testCeil() { Aprational a = new Aprational("11/10"); assertEquals("11/10 ceil", new Apint(2), a.ceil()); assertEquals("11/10 ceil reverse", a.ceil(), new Apint(2)); a = new Aprational("1"); assertEquals("1 ceil", new Apint(1), a.ceil()); a = new Aprational("199999999999999/200000000000000"); assertEquals("199999999999999/200000000000000 ceil", new Apint(1), a.ceil()); a = new Aprational("200000000000001/200000000000000"); assertEquals("200000000000001/200000000000000 ceil", new Apint(2), a.ceil()); a = new Aprational("-11/10"); assertEquals("-11/10 ceil", new Apint(-1), a.ceil()); a = new Aprational("0"); assertEquals("0 ceil", new Apint(0), a.ceil()); } public static void testTruncate() { Aprational a = new Aprational("11/10"); assertEquals("11/10 truncate", new Apint(1), a.truncate()); assertEquals("11/10 truncate reverse", a.truncate(), new Apint(1)); a = new Aprational("1"); assertEquals("1 truncate", new Apint(1), a.truncate()); a = new Aprational("199999999999999/200000000000000"); assertEquals("199999999999999/200000000000000 truncate", new Apint(0), a.truncate()); a = new Aprational("200000000000001/200000000000000"); assertEquals("200000000000001/200000000000000 truncate", new Apint(1), a.truncate()); a = new Aprational("-11/10"); assertEquals("-11/10 truncate", new Apint(-1), a.truncate()); a = new Aprational("0"); assertEquals("0 truncate", new Apint(0), a.truncate()); } public static void testFrac() { Aprational a = new Aprational("11/10"); assertEquals("11/10 frac", new Aprational("1/10"), a.frac()); assertEquals("11/10 frac reverse", a.frac(), new Aprational("1/10")); a = new Aprational("1"); assertEquals("1 frac", new Apint(0), a.frac()); a = new Aprational("199999999999999/200000000000000"); assertEquals("199999999999999/200000000000000 frac", new Aprational("199999999999999/200000000000000"), a.frac()); a = new Aprational("200000000000001/200000000000000"); assertEquals("200000000000001/200000000000000 frac", new Aprational("1/200000000000000"), a.frac()); a = new Aprational("-11/10"); assertEquals("-11/10 frac", new Aprational("-1/10"), a.frac()); a = new Aprational("0"); assertEquals("0 frac", new Apint(0), a.frac()); } public static void testRoundAway() { Aprational a = new Aprational("11/10"); assertEquals("1.1 roundAway", new Apint(2), a.roundAway()); a = new Aprational("-11/10"); assertEquals("-1.1 roundAway", new Apint(-2), a.roundAway()); } public static void testAbs() { Aprational a = new Aprational("2"); assertEquals("2 abs", new Aprational("2"), a.abs()); a = new Aprational("0"); assertEquals("0 abs", new Aprational("0"), a.abs()); a = new Aprational("-2"); assertEquals("-2 abs", new Aprational("2"), a.abs()); } public static void testCompareToHalf() { Aprational a = new Aprational("4/10"); assertEquals("0.4 compareToHalf", -1, a.compareToHalf()); a = new Aprational("5/10"); assertEquals("0.5 compareToHalf", 0, a.compareToHalf()); a = new Aprational("6/10"); assertEquals("0.6 compareToHalf", 1, a.compareToHalf()); } public static void testNumberValues() { Aprational a = new Aprational("5"); assertEquals("5 longValue", 5, a.longValue()); assertEquals("5 intValue", 5, a.intValue()); assertEquals("5 shortValue", 5, a.shortValue()); assertEquals("5 byteValue", 5, a.byteValue()); assertEquals("5 floatValue", 5.0f, a.floatValue(), 0.0f); assertEquals("5 doubleValue", 5.0, a.doubleValue(), 0.0); a = new Aprational("1/3"); assertEquals("1/3 longValue", 0, a.longValue()); assertEquals("1/3 intValue", 0, a.intValue()); assertEquals("1/3 shortValue", 0, a.shortValue()); assertEquals("1/3 byteValue", 0, a.byteValue()); assertEquals("1/3 floatValue", 0.333333333333f, a.floatValue(), Math.ulp(0.333333333333f)); assertEquals("1/3 doubleValue", 0.33333333333333333333, a.doubleValue(), Math.ulp(0.33333333333333333333)); a = new Aprational("2000000000000000000000001/2000000000000000000000000"); assertEquals("2000000000000000000000001/2000000000000000000000000 longValue", 1, a.longValue()); assertEquals("2000000000000000000000001/2000000000000000000000000 intValue", 1, a.intValue()); assertEquals("2000000000000000000000001/2000000000000000000000000 shortValue", 1, a.shortValue()); assertEquals("2000000000000000000000001/2000000000000000000000000 byteValue", 1, a.byteValue()); assertEquals("2000000000000000000000001/2000000000000000000000000 floatValue", 1.0f, a.floatValue(), 0.0f); assertEquals("2000000000000000000000001/2000000000000000000000000 doubleValue", 1.0, a.doubleValue(), 0.0); } public static void testEqualDigits() { Aprational a = new Aprational("1/3"); Apfloat b = new Apfloat("0.3333333333"); assertEquals("1/3 eq 0.3333333333", 10, a.equalDigits(b)); } @SuppressWarnings({ "rawtypes", "unchecked" }) public static void testCompareTo() { Aprational a = new Aprational("0"), b = new Aprational("1"); assertEquals("0 cmp 1", -1, a.compareTo(b)); assertEquals("0 cmp 1 as apfloat", -1, a.compareTo((Apfloat) b)); a = new Aprational("6"); b = new Aprational("5"); assertEquals("6 cmp 5", 1, a.compareTo(b)); a = new Aprational("6"); b = new Aprational("6"); assertEquals("6 cmp 6", 0, a.compareTo(b)); a = new Aprational("1/6"); b = new Aprational("1/5"); assertEquals("1/6 cmp 1/5", -1, a.compareTo(b)); a = new Aprational("5/12"); b = new Aprational("-7/12"); assertEquals("5/12 cmp -7/12", 1, a.compareTo(b)); a = new Aprational("1/3"); Apfloat f = new Apfloat("0.3333333333"); assertEquals("1/3 cmp 0.3333333333", 1, a.compareTo(f)); assertEquals("0.3333333333 cmp 1/3", -1, f.compareTo(a)); a = new Aprational("1/7"); f = new Aprational("1/3"); assertEquals("1/7 cmp float 1/3", -1, a.compareTo(f)); assertEquals("float 1/3 cmp 1/7", 1, f.compareTo(a)); Comparable obj1 = new Aprational("1/3"), obj2 = new Aprational("1/4"); assertEquals("obj 1/3 cmp 1/4", 1, obj1.compareTo(obj2)); assertEquals("obj 1/4 cmp 1/3", -1, obj2.compareTo(obj1)); obj1 = new Aprational("1/3"); obj2 = new Apfloat("0.3333333333"); assertEquals("obj 1/3 cmp 0.3333333333", 1, obj1.compareTo(obj2)); assertEquals("obj 0.3333333333 cmp 1/3", -1, obj2.compareTo(obj1)); try { Comparable c = a; c.compareTo("bogus"); fail("Comparison to different class allowed"); } catch (ClassCastException cce) { // OK: class can't be cast to Apfloat } } public static void testEquals() { Aprational a = new Aprational("0"), b = new Aprational("1"); assertEquals("0 == 1", false, a.equals(b)); a = new Aprational("6"); b = new Aprational("5"); assertEquals("6 == 5", false, a.equals(b)); assertEquals("6 == something else", false, a.equals("bogus")); a = new Aprational("6"); b = new Aprational("6"); assertEquals("6 == 6", true, a.equals(b)); a = new Aprational("1/6"); b = new Aprational("1/5"); assertEquals("1/6 == 1/5", false, a.equals(b)); a = new Aprational("5/12"); b = new Aprational("-7/12"); assertEquals("5/12 == -7/12", false, a.equals(b)); assertEquals("a == a", true, a.equals(a)); a = new Aprational("1/3"); Apfloat f = new Apfloat("0.3333333333"); assertEquals("1/3 == 0.3333333333", false, a.equals(f)); assertEquals("0.3333333333 == 1/3", false, f.equals(a)); a = new Aprational("1/3"); f = new Aprational("1/7"); assertEquals("1/3 cmp float 1/7", false, a.equals(f)); assertEquals("float 1/7 cmp 1/3", false, f.equals(a)); a = new Aprational("1/2"); f = new Apfloat("0.5"); assertEquals("1/2 == 0.5", true, a.equals(f)); assertEquals("0.5 == 1/2", true, f.equals(a)); Object obj1 = new Aprational("1/3"), obj2 = new Aprational("1/4"); assertEquals("obj 1/3 == 1/4", false, obj1.equals(obj2)); assertEquals("obj 1/4 == 1/3", false, obj2.equals(obj1)); obj1 = new Aprational("1/3"); obj2 = new Apfloat("0.3333333333"); assertEquals("obj 1/3 == 0.3333333333", false, obj1.equals(obj2)); assertEquals("obj 0.3333333333 == 1/3", false, obj2.equals(obj1)); } public static void testTest() { Aprational a = new Aprational("0"), b = new Aprational("0"); assertTrue("0 test 0", a.test(b)); a = new Aprational("0"); b = new Aprational("1"); assertFalse("0 test 1", a.test(b)); a = new Aprational("-1"); b = new Aprational("1"); assertFalse("-1 test 1", a.test(b)); a = new Aprational("1"); b = new Aprational("1/10"); assertFalse("1 test 1/10", a.test(b)); a = new Aprational("2", 10); b = new Aprational("2", 11); assertTrue("2 test 2, radix", a.test(b)); a = new Aprational("2"); Apfloat f = new Apfloat(2); assertTrue("2 test 2, type", a.test(f)); assertTrue("2 test 2, type reverse", f.test(a)); a = new Aprational("2/3"); f = new Apfloat(0.07); assertTrue("2/3 test 0.07, type", a.test(f)); assertTrue("0.07 test 2/3, type", f.test(a)); a = new Aprational("3"); f = new Apfloat(0.07); assertFalse("3 test 0.07, type", a.test(f)); assertFalse("0.07 test 3, type", f.test(a)); } public static void testHashCode() { Aprational a = new Aprational("1/2"), b = new Aprational("2/1"); assertTrue("1/2 != 2/1", a.hashCode() != b.hashCode()); a = new Aprational("6"); b = new Aprational("5"); assertTrue("5 != 6", a.hashCode() != b.hashCode()); a = new Aprational("5/6"); b = new Aprational("5/6"); assertEquals("5/6 == 5/6", a.hashCode(), b.hashCode()); a = new Aprational("2/1", 12); b = new Aprational("2"); assertTrue("2/1 == 2", a.hashCode() == b.hashCode()); } public static void testToString() { Aprational a = new Aprational("0"); assertEquals("0", "0", "" + a); a = new Aprational("6"); assertEquals("6", "6", "" + a); a = new Aprational("123456789/555555555555557"); assertEquals("123456789/555555555555557", "123456789/555555555555557", "" + a); a = new Aprational("123456789/555555555555557"); assertEquals("123456789/555555555555557 unpretty", "1.23456789e8/5.55555555555557e14", a.toString(false)); } public static void testWriteTo() throws IOException { StringWriter out = new StringWriter(); Aprational a = new Aprational("0"); a.writeTo(out); a = new Aprational("6"); a.writeTo(out); a = new Aprational("123456789/555555555555557"); a.writeTo(out); a = new Aprational("123456789/555555555555557"); a.writeTo(out, false); assertEquals("string", "06123456789/5555555555555571.23456789e8/5.55555555555557e14", out.toString()); } public static void testFormatTo() throws IOException { System.setProperty("java.locale.providers", "COMPAT,SPI"); // Required since Java 10 to have all locale providers available Locale locale = null; assertEquals("null %s", "123456789/1234", String.format(locale, "%s", new Aprational("123456789/1234"))); assertEquals("null %S", "123456789/123A", String.format(locale, "%S", new Aprational("123456789/123a", 11))); assertEquals("null %15s", " 123456789/1234", String.format(locale, "%15s", new Aprational("123456789/1234"))); assertEquals("null %-15s", "123456789/1234 ", String.format(locale, "%-15s", new Aprational("123456789/1234"))); assertEquals("null %s apint", "123456789", String.format(locale, "%s", new Aprational("123456789"))); locale = new Locale("hi", "IN"); assertEquals("hi_IN %s", "१२३४५६७८९/१२३४", String.format(locale, "%s", new Aprational("123456789/1234"))); assertEquals("hi_IN %s radix 9", "१२३४५६७८/१२४", String.format(locale, "%s", new Aprational("12345678/124", 9))); assertEquals("hi_IN %s radix 11", "12345678/124", String.format(locale, "%s", new Aprational("12345678/124", 11))); try { String.format(locale, "%#s", new Aprational("123456789/1234")); fail("# flag allowed"); } catch (IllegalFormatException ife) { // OK: alternate format not allowed with integers } try { String.format(locale, "%.1s", new Aprational("123456789/1234")); fail("Precision allowed"); } catch (IllegalFormatException ife) { // OK: precision not allowed with integers } } private static String getString(char character, int length) { StringBuilder buffer = new StringBuilder(length); for (int i = 0; i < length; i++) { buffer.append(character); } return buffer.toString(); } public static void testSerialization() throws IOException, ClassNotFoundException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(buffer); Aprational a = new Aprational("5/6"); out.writeObject(a); out.close(); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray())); Aprational b = (Aprational) in.readObject(); assertEquals("5/6 equals", a, b); assertNotSame("5/6 !=", a, b); a = new Aprational(getString('a', 1000000) + "/7", 12); a.precision(2000000); // Return value not used buffer.reset(); out = new ObjectOutputStream(buffer); out.writeObject(a); out.close(); assertTrue("Data has been used: " + buffer.size() + " > 400000", buffer.size() > 400000); assertTrue("Transient data is not written: " + buffer.size() + " < 700000", buffer.size() < 700000); // Serialization from legacy data // new Aprational("1/100") in apfloat 1.7.1 format byte[] bytes = { -84, -19, 0, 5, 115, 114, 0, 22, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 65, 112, 114, 97, 116, 105, 111, 110, 97, 108, -4, -29, -68, 72, -61, -95, -26, 23, 2, 0, 3, 74, 0, 5, 115, 99, 97, 108, 101, 76, 0, 11, 100, 101, 110, 111, 109, 105, 110, 97, 116, 111, 114, 116, 0, 19, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 65, 112, 105, 110, 116, 59, 76, 0, 9, 110, 117, 109, 101, 114, 97, 116, 111, 114, 113, 0, 126, 0, 1, 120, 114, 0, 19, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 65, 112, 102, 108, 111, 97, 116, -1, 125, -106, -56, -92, 28, 107, 73, 2, 0, 1, 76, 0, 4, 105, 109, 112, 108, 116, 0, 29, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 115, 112, 105, 47, 65, 112, 102, 108, 111, 97, 116, 73, 109, 112, 108, 59, 120, 114, 0, 21, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 65, 112, 99, 111, 109, 112, 108, 101, 120, 50, -114, 76, 62, -100, 91, -70, -73, 2, 0, 2, 76, 0, 4, 105, 109, 97, 103, 116, 0, 21, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 65, 112, 102, 108, 111, 97, 116, 59, 76, 0, 4, 114, 101, 97, 108, 113, 0, 126, 0, 5, 120, 114, 0, 16, 106, 97, 118, 97, 46, 108, 97, 110, 103, 46, 78, 117, 109, 98, 101, 114, -122, -84, -107, 29, 11, -108, -32, -117, 2, 0, 0, 120, 112, 112, 112, 112, -128, 0, 0, 0, 0, 0, 0, 0, 115, 114, 0, 17, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 65, 112, 105, 110, 116, 75, 19, 49, 114, 115, -59, -82, 83, 2, 0, 1, 76, 0, 5, 118, 97, 108, 117, 101, 113, 0, 126, 0, 5, 120, 113, 0, 126, 0, 0, 112, 112, 112, -128, 0, 0, 0, 0, 0, 0, 0, 112, 112, 115, 113, 0, 126, 0, 2, 112, 112, 115, 114, 0, 36, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 76, 111, 110, 103, 65, 112, 102, 108, 111, 97, 116, 73, 109, 112, 108, -30, 36, -29, 106, -22, 40, -77, 43, 2, 0, 8, 74, 0, 8, 101, 120, 112, 111, 110, 101, 110, 116, 73, 0, 8, 104, 97, 115, 104, 67, 111, 100, 101, 73, 0, 13, 105, 110, 105, 116, 105, 97, 108, 68, 105, 103, 105, 116, 115, 74, 0, 10, 108, 101, 97, 115, 116, 90, 101, 114, 111, 115, 74, 0, 9, 112, 114, 101, 99, 105, 115, 105, 111, 110, 73, 0, 5, 114, 97, 100, 105, 120, 73, 0, 4, 115, 105, 103, 110, 76, 0, 11, 100, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 116, 0, 29, 76, 111, 114, 103, 47, 97, 112, 102, 108, 111, 97, 116, 47, 115, 112, 105, 47, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 59, 120, 114, 0, 33, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 76, 111, 110, 103, 66, 97, 115, 101, 77, 97, 116, 104, -90, 56, -79, 77, -38, 28, -98, -104, 2, 0, 2, 68, 0, 11, 105, 110, 118, 101, 114, 115, 101, 66, 97, 115, 101, 73, 0, 5, 114, 97, 100, 105, 120, 120, 112, 60, 103, 14, -11, 70, 70, -44, -105, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, -128, 0, 0, 0, -1, -1, -1, -1, -128, 0, 0, 0, 127, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 10, 0, 0, 0, 1, 115, 114, 0, 42, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 105, 110, 116, 101, 114, 110, 97, 108, 46, 76, 111, 110, 103, 77, 101, 109, 111, 114, 121, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, -84, 74, -31, 104, 107, 113, 66, 75, 2, 0, 1, 91, 0, 4, 100, 97, 116, 97, 116, 0, 2, 91, 74, 120, 114, 0, 27, 111, 114, 103, 46, 97, 112, 102, 108, 111, 97, 116, 46, 115, 112, 105, 46, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 25, -41, 65, 37, -43, -67, -21, -93, 2, 0, 5, 90, 0, 10, 105, 115, 82, 101, 97, 100, 79, 110, 108, 121, 90, 0, 14, 105, 115, 83, 117, 98, 115, 101, 113, 117, 101, 110, 99, 101, 100, 74, 0, 6, 108, 101, 110, 103, 116, 104, 74, 0, 6, 111, 102, 102, 115, 101, 116, 76, 0, 19, 111, 114, 105, 103, 105, 110, 97, 108, 68, 97, 116, 97, 83, 116, 111, 114, 97, 103, 101, 113, 0, 126, 0, 12, 120, 112, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 112, 117, 114, 0, 2, 91, 74, 120, 32, 4, -75, 18, -79, 117, -109, 2, 0, 0, 120, 112, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 100, 115, 113, 0, 126, 0, 8, 112, 112, 112, -128, 0, 0, 0, 0, 0, 0, 0, 112, 112, 115, 113, 0, 126, 0, 2, 112, 112, 115, 113, 0, 126, 0, 11, 60, 103, 14, -11, 70, 70, -44, -105, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, -1, -1, -1, -1, -128, 0, 0, 0, 127, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 10, 0, 0, 0, 1, 115, 113, 0, 126, 0, 15, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 112, 117, 113, 0, 126, 0, 19, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }; in = new ObjectInputStream(new ByteArrayInputStream(bytes)); a = (Aprational) in.readObject(); assertEquals("Legacy scale", -1, a.scale()); assertEquals("Legacy size", 1, a.size()); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/BesselHelperTest.java000066400000000000000000000576421461767713300256720ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import junit.framework.TestSuite; /** * @version 1.14.0 * @author Mikko Tommila */ public class BesselHelperTest extends ApfloatTestCase { public BesselHelperTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new BesselHelperTest("testBesselJ")); suite.addTest(new BesselHelperTest("testBesselI")); suite.addTest(new BesselHelperTest("testBesselY")); suite.addTest(new BesselHelperTest("testBesselK")); return suite; } public static void testBesselJ() { Apcomplex a = BesselHelper.besselJ(new Apcomplex("(-3.00000,-4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-3 - 4i, 5 + 6i precision", 6, a.precision()); assertEquals("-3 - 4i, 5 + 6i value", new Apcomplex("(-99583.5,102827)"), a, new Apfloat("5e0")); a = BesselHelper.besselJ(new Apcomplex("0"), new Apcomplex("(5.000000,6.000000)")); assertEquals("0, 5 + 6i precision", 7, a.precision()); assertEquals("0, 5 + 6i value", new Apcomplex("(-4.14447,58.15938)"), a, new Apfloat("5e-5")); a = BesselHelper.besselJ(new Apcomplex("-1.000000"), new Apcomplex("(5.000000,6.000000)")); assertEquals("-1, 5 + 6i precision", 6, a.precision()); assertEquals("-1, 5 + 6i value", new Apcomplex("(55.4684,1.42477)"), a, new Apfloat("5e-4")); a = BesselHelper.besselJ(new Apcomplex("-0.999999"), new Apcomplex("(5.000000,6.000000)")); assertEquals("-0.999999, 5 + 6i precision", 6, a.precision()); assertEquals("-0.999999, 5 + 6i value", new Apcomplex("(55.4684,1.42486)"), a, new Apfloat("5e-4")); a = BesselHelper.besselJ(new Apcomplex("-1.00000"), new Apcomplex("(0,6.00000)")); assertEquals("-1, 6i precision", 6, a.precision()); assertEquals("-1, 6i value", new Apcomplex("(0,-61.3419)"), a, new Apfloat("5e-4")); a = BesselHelper.besselJ(new Apcomplex("-0.999999"), new Apcomplex("(0,6.000000)")); assertEquals("-0.999999, 6i precision", 6, a.precision()); assertEquals("-0.999999, 6i value", new Apcomplex("(0.0000963557,-61.3419)"), a, new Apfloat("5e-4")); a = BesselHelper.besselJ(new Apcomplex("-1.999999"), new Apcomplex("3.000000")); assertEquals("-1.999999, 3 precision", 6, a.precision()); assertEquals("-1.999999, 3 value", new Apcomplex("0.486087"), a, new Apfloat("5e-6")); a = BesselHelper.besselJ(new Apcomplex("-1.9999999999998"), new Apcomplex("3.0000000000000")); assertEquals("-1.9999999999998, 3 precision", 14, a.precision()); assertEquals("-1.9999999999998, 3 value", new Apcomplex("0.48609126058580"), a, new Apfloat("5e-14")); a = BesselHelper.besselJ(new Apcomplex("-1.9999999999998000"), new Apcomplex("3.0000000000000000")); assertEquals("-1.9999999999998, 3 precision", 17, a.precision()); assertEquals("-1.9999999999998, 3 value", new Apcomplex("0.48609126058580704"), a, new Apfloat("5e-17")); a = BesselHelper.besselJ(new Apcomplex("-10.5").precision(81), new Apcomplex("(55,66)").precision(81)); assertEquals("-10.5, 55 + 66i precision", 80, a.precision()); assertEquals("-10.5, 55 + 66i value", new Apcomplex("(-9.2819931358505770728585891284128300552494996683401153463605047231153352993126805e26,-7.7833255801252032004669340241374829748024004126014611117564912890382501825748791e26)"), a, new Apfloat("5e-53")); a = BesselHelper.besselJ(new Apcomplex("10.5").precision(81), new Apcomplex("(55,66)").precision(81)); assertEquals("10.5, 55 + 66i precision", 80, a.precision()); assertEquals("10.5, 55 + 66i value", new Apcomplex("(7.7833255801252032004669340241374829748024004126014611117870331911370690985938420e26,-9.2819931358505770728585891284128300552494996683401153463608216053422431060089578e26)"), a, new Apfloat("5e-53")); a = BesselHelper.besselJ(new Apcomplex("-10.5000000001"), new Apcomplex("(55,66)").precision(12)); assertEquals("-10.50000001, 55 + 66i precision", 10, a.precision()); assertEquals("-10.50000001, 55 + 66i value", new Apcomplex("(-9.281993137e26,-7.783325578e26)"), a, new Apfloat("5e17")); a = BesselHelper.besselJ(new Apcomplex("10.5000000001"), new Apcomplex("(55,66)").precision(12)); assertEquals("10.50000001, 55 + 66i precision", 10, a.precision()); assertEquals("10.50000001, 55 + 66i value", new Apcomplex("(7.783325581e26,-9.281993134e26)"), a, new Apfloat("5e17")); /* a = BesselHelper.besselJ(new Apcomplex("1e-1000000000000"), new Apcomplex("(5.000000,6.000000)")); assertEquals("1e-1000000000000, 5 + 6i precision", 7, a.precision()); assertEquals("1e-1000000000000, 5 + 6i value", new Apcomplex("(-4.14447,58.15938)"), a, new Apfloat("5e-5")); */ a = BesselHelper.besselJ(new Apcomplex("0"), new Apcomplex("5.52007811028631064959660411281")); assertEquals("0, 2nd zero precision", 30, a.precision()); assertEquals("0, 2nd zero value", new Apcomplex("0"), a, new Apfloat("5e-30")); a = BesselHelper.besselJ(new Apcomplex("-0.500000000000000000000000000000"), new Apcomplex("7.85398163397448309615660845821")); assertEquals("-1/2, 3rd zero precision", 30, a.precision()); assertEquals("-1/2, 3rd zero value", new Apcomplex("0"), a, new Apfloat("5e-30")); a = BesselHelper.besselJ(new Apcomplex("0"), new Apcomplex("0")); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 value", new Apcomplex("1"), a); a = BesselHelper.besselJ(new Apcomplex("-1.0"), new Apcomplex("0")); assertEquals("-1, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, 0 value", new Apcomplex("0"), a); a = BesselHelper.besselJ(new Apcomplex(new Apfloat(3, 20, 2), new Apfloat(-4, 20, 2)), new Apcomplex(new Apfloat(5, 20, 2), new Apfloat(-6, 20, 2))); assertEquals("3 - 4i, 5 - 6i precision", 17, a.precision()); assertEquals("3 - 4i, 5 - 6i radix", 2, a.radix()); assertEquals("3 - 4i, 5 - 6i value", new Apcomplex(new Apfloat("0.011001100101101100", 17, 2), new Apfloat("0.010111000001000100", 17, 2)), a, new Apfloat("1e-18", 1, 2)); a = BesselHelper.besselJ(new Apcomplex(new Apint(0, 2)), new Apcomplex(new Apint(0, 2))); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 radix", 2, a.radix()); assertEquals("0, 0 value", new Apcomplex("1"), a); a = BesselHelper.besselJ(new Apcomplex(new Apint(-1, 2)), new Apcomplex(new Apint(0, 2))); assertEquals("-1, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, 0 radix", 2, a.radix()); assertEquals("-1, 0 value", new Apcomplex("0"), a); try { BesselHelper.besselJ(new Apcomplex("-0.1"), new Apcomplex("0")); fail("-0.1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselJ(new Apcomplex("(0,0.1)"), new Apcomplex("0")); fail("0.1i, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselJ(new Apcomplex(Apfloat.ONE, new Apfloat(4)), new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testBesselI() { Apcomplex a = BesselHelper.besselI(new Apcomplex("(-3.00000,-4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-3 - 4i, 5 + 6i precision", 6, a.precision()); assertEquals("-3 - 4i, 5 + 6i value", new Apcomplex("(540.404,-264.967)"), a, new Apfloat("5e-3")); a = BesselHelper.besselI(new Apcomplex("0"), new Apcomplex("(5.000000,6.000000)")); assertEquals("0, 5 + 6i precision", 7, a.precision()); assertEquals("0, 5 + 6i value", new Apcomplex("(15.87945,-14.34085)"), a, new Apfloat("5e-5")); a = BesselHelper.besselI(new Apcomplex("-1.000000"), new Apcomplex("(5.000000,6.000000)")); assertEquals("-1, 5 + 6i precision", 6, a.precision()); assertEquals("-1, 5 + 6i value", new Apcomplex("(15.9742,-12.9498)"), a, new Apfloat("5e-4")); a = BesselHelper.besselI(new Apcomplex("-0.999999"), new Apcomplex("(5.000000,6.000000)")); assertEquals("-0.999999, 5 + 6i precision", 6, a.precision()); assertEquals("-0.999999, 5 + 6i value", new Apcomplex("(15.9742,-12.9498)"), a, new Apfloat("5e-4")); a = BesselHelper.besselI(new Apcomplex("-10.5").precision(81), new Apcomplex("(55,66)").precision(81)); assertEquals("-10.5, 55 + 66i precision", 80, a.precision()); assertEquals("-10.5, 55 + 66i value", new Apcomplex("(-2.1906070413418972181765049892474193969670206647027033324967515598596162984040629e22,-1.836307061247292980771203766871941919928103611186566955292861739783828791122258e21)"), a, new Apfloat("5e-57")); a = BesselHelper.besselI(new Apcomplex("10.5").precision(81), new Apcomplex("(55,66)").precision(81)); assertEquals("10.5, 55 + 66i precision", 80, a.precision()); assertEquals("10.5, 55 + 66i value", new Apcomplex("(-2.1906070413418972181765049892474193969670206646929190184727112005044694629164806e22,-1.836307061247292980771203766871941919928103611324068214270934127704834691844765e21)"), a, new Apfloat("5e-57")); a = BesselHelper.besselI(new Apcomplex("-10.5000000001"), new Apcomplex("(55,66)").precision(12)); assertEquals("-10.50000001, 55 + 66i precision", 10, a.precision()); assertEquals("-10.50000001, 55 + 66i value", new Apcomplex("(-2.190607041e22,-1.83630706e21)"), a, new Apfloat("5e13")); a = BesselHelper.besselI(new Apcomplex("10.5000000001"), new Apcomplex("(55,66)").precision(12)); assertEquals("10.50000001, 55 + 66i precision", 10, a.precision()); assertEquals("10.50000001, 55 + 66i value", new Apcomplex("(-2.190607041e22,-1.83630706e21)"), a, new Apfloat("5e13")); a = BesselHelper.besselI(new Apcomplex("0"), new Apcomplex("0")); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 value", new Apcomplex("1"), a); a = BesselHelper.besselI(new Apcomplex("-1.0"), new Apcomplex("0")); assertEquals("-1, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, 0 value", new Apcomplex("0"), a); a = BesselHelper.besselI(new Apcomplex(new Apfloat(3, 20, 2), new Apfloat(-4, 20, 2)), new Apcomplex(new Apfloat(5, 20, 2), new Apfloat(-6, 20, 2))); assertEquals("3 - 4i, 5 - 6i precision", 17, a.precision()); assertEquals("3 - 4i, 5 - 6i radix", 2, a.radix()); assertEquals("3 - 4i, 5 - 6i value", new Apcomplex(new Apfloat("-11.100010111001110001", 17, 2), new Apfloat("111.0101111110001111", 17, 2)), a, new Apfloat("1e-16", 1, 2)); a = BesselHelper.besselI(new Apcomplex(new Apint(0, 2)), new Apcomplex(new Apint(0, 2))); assertEquals("0, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 0 radix", 2, a.radix()); assertEquals("0, 0 value", new Apcomplex("1"), a); a = BesselHelper.besselI(new Apcomplex(new Apint(-1, 2)), new Apcomplex(new Apint(0, 2))); assertEquals("-1, 0 precision", Apfloat.INFINITE, a.precision()); assertEquals("-1, 0 radix", 2, a.radix()); assertEquals("-1, 0 value", new Apcomplex("0"), a); try { BesselHelper.besselI(new Apcomplex("-0.1"), new Apcomplex("0")); fail("-0.1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselI(new Apcomplex("(0,0.1)"), new Apcomplex("0")); fail("0.1i, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselI(new Apcomplex(Apfloat.ONE, new Apfloat(4)), new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testBesselY() { Apcomplex a = BesselHelper.besselY(new Apcomplex("(-3.00000,-4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-3 - 4i, 5 + 6i precision", 6, a.precision()); assertEquals("-3 - 4i, 5 + 6i value", new Apcomplex("(-102827,-99583.5)"), a, new Apfloat("5e-0")); a = BesselHelper.besselY(new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)")); assertEquals("0, 5 + 6i precision", 6, a.precision()); assertEquals("0, 5 + 6i value", new Apcomplex("(-58.1598,-4.1439)"), a, new Apfloat("5e-4")); a = BesselHelper.besselY(new Apcomplex("-1.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-1, 5 + 6i precision", 6, a.precision()); assertEquals("-1, 5 + 6i value", new Apcomplex("(-1.4253,55.4679)"), a, new Apfloat("5e-4")); a = BesselHelper.besselY(new Apcomplex("-10").precision(30), new Apcomplex("(5,6)").precision(30)); assertEquals("-10, 5 + 6i precision", 30, a.precision()); assertEquals("-10, 5 + 6i value", new Apcomplex("(-0.341222371369833270387557564868,0.198626104551143979520413812554)"), a, new Apfloat("5e-30")); a = BesselHelper.besselY(new Apcomplex("-10.50000001"), new Apcomplex("(55,66)").precision(10)); assertEquals("-10.50000001, 55 + 66i precision", 10, a.precision()); assertEquals("-10.50000001, 55 + 66i value", new Apcomplex("(7.783325420e26,-9.281993255e26)"), a, new Apfloat("5e17")); a = BesselHelper.besselY(new Apcomplex("10.50000001"), new Apcomplex("(55,66)").precision(10)); assertEquals("10.50000001, 55 + 66i precision", 10, a.precision()); assertEquals("10.50000001, 55 + 66i value", new Apcomplex("(9.281993011e26,7.783325711e26)"), a, new Apfloat("5e17")); a = BesselHelper.besselY(new Apcomplex("-0.999999"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-0.999999, 5 + 6i precision", 6, a.precision()); assertEquals("-0.999999, 5 + 6i value", new Apcomplex("(-1.42544,55.4679)"), a, new Apfloat("5e-4")); a = BesselHelper.besselY(new Apcomplex("-1.00000"), new Apcomplex("(0,6.00000)")); assertEquals("-1, 6i precision", 6, a.precision()); assertEquals("-1, 6i value", new Apcomplex("(61.3419,-0.000855566)"), a, new Apfloat("5e-4")); a = BesselHelper.besselY(new Apcomplex("0"), new Apcomplex("13.3610974738727634782676945857")); assertEquals("0, 5th zero precision", 30, a.precision()); assertEquals("0, 5th zero value", new Apcomplex("0"), a, new Apfloat("5e-30")); a = BesselHelper.besselY(new Apcomplex("0.500000000000000000000000000000"), new Apcomplex("7.85398163397448309615660845821")); assertEquals("1/2, 3rd zero precision", 30, a.precision()); assertEquals("1/2, 3rd zero value", new Apcomplex("0"), a, new Apfloat("5e-30")); a = BesselHelper.besselY(new Apcomplex("0"), new Apcomplex("(0.444223,0.938874)")); assertEquals("Root of i precision", 6, a.precision()); assertEquals("Root of i value", new Apcomplex("(0,1.00000)"), a, new Apfloat("5e-5")); a = BesselHelper.besselY(new Apcomplex(new Apfloat(3, 17, 2), new Apfloat(-4, 17, 2)), new Apcomplex(new Apfloat(5, 17, 2), new Apfloat(-6, 17, 2))); assertEquals("3 - 4i, 5 - 6i precision", 17, a.precision()); assertEquals("3 - 4i, 5 - 6i radix", 2, a.radix()); assertEquals("3 - 4i, 5 - 6i value", new Apcomplex(new Apfloat("0.010110111000100010010000", 17, 2), new Apfloat("-0.01001011011100111100111", 17, 2)), a, new Apfloat("1e-18", 1, 2)); try { BesselHelper.besselY(new Apcomplex("0"), new Apcomplex("0")); fail("0, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselY(new Apcomplex("1"), new Apcomplex("0")); fail("1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselY(new Apcomplex("-0.1"), new Apcomplex("0")); fail("-0.1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselY(new Apcomplex("(0,0.1)"), new Apcomplex("0")); fail("0.1i, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselY(new Apcomplex(Apfloat.ONE, new Apfloat(4)), new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } public static void testBesselK() { Apcomplex a = BesselHelper.besselK(new Apcomplex("(-3.00000,-4.00000)"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-3 - 4i, 5 + 6i precision", 6, a.precision()); assertEquals("-3 - 4i, 5 + 6i value", new Apcomplex("(0.00282215,0.00595941)"), a, new Apfloat("5e-8")); a = BesselHelper.besselK(new Apcomplex("0"), new Apcomplex("(5.00000,6.00000)")); assertEquals("0, 5 + 6i precision", 6, a.precision()); assertEquals("0, 5 + 6i value", new Apcomplex("(0.002959927,-0.000427643)"), a, new Apfloat("5e-8")); a = BesselHelper.besselK(new Apcomplex("-1.00000"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-1, 5 + 6i precision", 6, a.precision()); assertEquals("-1, 5 + 6i value", new Apcomplex("(0.003061552,-0.000585260)"), a, new Apfloat("5e-8")); a = BesselHelper.besselK(new Apcomplex("-10").precision(30), new Apcomplex("(5,6)").precision(30)); assertEquals("-10, 5 + 6i precision", 30, a.precision()); assertEquals("-10, 5 + 6i value", new Apcomplex("(-0.132997176584901416563825674362,0.213283091988362072925433855996)"), a, new Apfloat("5e-30")); a = BesselHelper.besselK(new Apcomplex("-10").precision(80), new Apcomplex("(55,66)").precision(80)); assertEquals("-10, 55 + 66i precision", 80, a.precision()); assertEquals("-10, 55 + 66i value", new Apcomplex("(-1.5719094597421395108616812345047338321057046833258331013509253459689034972880344e-25,2.0092743303288327194242050334753362614508403182704960004658632494871048350086773e-25)"), a, new Apfloat("5e-104")); a = BesselHelper.besselK(new Apcomplex("-10.5").precision(80), new Apcomplex("(55,66)").precision(80)); assertEquals("-10.5, 55 + 66i precision", 80, a.precision()); assertEquals("-10.5, 55 + 66i value", new Apcomplex("(-1.5369164529170390289991668816947511880267698317380630910340781008262577658960406e-25,2.1598647253242990741008300720430290145040468009670286009550948504677373835871566e-25)"), a, new Apfloat("5e-104")); a = BesselHelper.besselK(new Apcomplex("-10.50000001"), new Apcomplex("(55,66)").precision(10)); assertEquals("-10.50000001, 55 + 66i precision", 10, a.precision()); assertEquals("-10.50000001, 55 + 66i value", new Apcomplex("(-1.536916452e-25,2.159864728e-25)"), a, new Apfloat("5e-34")); a = BesselHelper.besselK(new Apcomplex("10.50000001"), new Apcomplex("(55,66)").precision(10)); assertEquals("10.50000001, 55 + 66i precision", 10, a.precision()); assertEquals("10.50000001, 55 + 66i value", new Apcomplex("(-1.536916452e-25,2.159864728e-25)"), a, new Apfloat("5e-34")); a = BesselHelper.besselK(new Apcomplex("-0.999999"), new Apcomplex("(5.00000,6.00000)")); assertEquals("-0.999999, 5 + 6i precision", 6, a.precision()); assertEquals("-0.999999, 5 + 6i value", new Apcomplex("(0.00306155,-0.00058526)"), a, new Apfloat("5e-8")); a = BesselHelper.besselK(new Apcomplex("-1.00000"), new Apcomplex("(0,6.00000)")); assertEquals("-1, 6i precision", 6, a.precision()); assertEquals("-1, 6i value", new Apcomplex("(0.434614,-0.274906)"), a, new Apfloat("5e-4")); a = BesselHelper.besselK(new Apcomplex("0"), new Apcomplex("(-0.458343,3.90004)")); assertEquals("Root of i precision", 6, a.precision()); assertEquals("Root of i value", new Apcomplex("(0,1.00000)"), a, new Apfloat("5e-5")); a = BesselHelper.besselK(new Apcomplex(new Apfloat(3, 17, 2), new Apfloat(-4, 17, 2)), new Apcomplex(new Apfloat(5, 17, 2), new Apfloat(-6, 17, 2))); assertEquals("3 - 4i, 5 - 6i precision", 17, a.precision()); assertEquals("3 - 4i, 5 - 6i radix", 2, a.radix()); assertEquals("3 - 4i, 5 - 6i value", new Apcomplex(new Apfloat("1.011100011110011110010e-9", 17, 2), new Apfloat("-1.1000011010001110010000e-8", 17, 2)), a, new Apfloat("1e-18", 1, 2)); try { BesselHelper.besselK(new Apcomplex("0"), new Apcomplex("0")); fail("0, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselK(new Apcomplex("1"), new Apcomplex("0")); fail("1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselK(new Apcomplex("-0.1"), new Apcomplex("0")); fail("-0.1, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselK(new Apcomplex("(0,0.1)"), new Apcomplex("0")); fail("0.1i, 0 accepted"); } catch (ArithmeticException ae) { // OK, result is infinite } try { BesselHelper.besselK(new Apcomplex(Apfloat.ONE, new Apfloat(4)), new Apcomplex(Apfloat.ONE, new Apfloat(4))); fail("Infinite expansion"); } catch (InfiniteExpansionException iee) { // OK } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ConcurrentSoftHashMapTest.java000066400000000000000000000056211461767713300275230ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.List; import java.util.ArrayList; import java.util.Map; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @since 1.6 * @version 1.9.0 * @author Mikko Tommila */ public class ConcurrentSoftHashMapTest extends TestCase { public ConcurrentSoftHashMapTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ConcurrentSoftHashMapTest("testSoft")); return suite; } public static void testSoft() { Map map = new ConcurrentSoftHashMap<>(); final int SIZE = 1000000; byte[] value = new byte[4 * SIZE]; map.put(1, value); assertEquals("Size after put", 1, map.size()); assertNotNull("Value", map.get(1)); value = null; // Force out of memory try { List dummy = new ArrayList<>(); for (int i = 2; i < 1000000000 && map.get(1) != null; i++) { dummy.add(new byte[SIZE]); } } catch (OutOfMemoryError oome) { // Should happen eventually } assertNull("Cleared", map.get(1)); map.put(1, value); map.clear(); assertNull("Explicitly cleared", map.get(1)); assertNull("Removed", map.remove(1)); try { map.entrySet(); } catch (UnsupportedOperationException uoe) { // Ignore } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ConcurrentWeakHashMapTest.java000066400000000000000000000056031461767713300274770ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.Map; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.9.0 * @author Mikko Tommila */ public class ConcurrentWeakHashMapTest extends TestCase { public ConcurrentWeakHashMapTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ConcurrentWeakHashMapTest("testWeak")); return suite; } public static void testWeak() throws Exception { Map map = new ConcurrentWeakHashMap<>(); Thread thread = new Thread(); assertTrue("Initially empty", map.isEmpty()); map.put(thread, "First"); assertEquals("Size after put", 1, map.size()); assertFalse("Not empty after put empty", map.isEmpty()); assertEquals("Value after put", "First", map.get(thread)); thread = null; System.gc(); Thread.sleep(1000); // Expunging garbage collected entries may happen only with put() for (int i = 0; i < 1000; i++) { map.put(new Thread(), "Dummy"); } assertEquals("Size after GC", 1000, map.size()); thread = new Thread(); map.put(thread, "Bogus"); map.clear(); assertNull("Explicitly cleared", map.get(thread)); assertNull("Removed", map.remove(thread)); try { map.entrySet(); } catch (UnsupportedOperationException uoe) { // Ignore } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/FixedPrecisionApcomplexHelperTest.java000066400000000000000000002244661461767713300312410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import junit.framework.TestSuite; /** * @version 1.14.0 * @author Mikko Tommila */ public class FixedPrecisionApcomplexHelperTest extends ApfloatTestCase { public FixedPrecisionApcomplexHelperTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new FixedPrecisionApcomplexHelperTest("testValue")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAdd")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testSubtract")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testMultiply")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testDivide")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testReal")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testImag")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testConj")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testArg")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testNegate")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAbs")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testNorm")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testScale")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testIntegerPow")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testInverseRoot")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testRoot")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testSqrt")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testCbrt")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAllRoots")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAgm")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLog")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLogBase")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testExp")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testPow")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAcosh")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAsinh")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAtanh")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testCosh")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testSinh")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testTanh")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAcos")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAsin")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAtan")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testCos")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testSin")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testTan")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testSinc")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testW")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testProduct")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testSum")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testGamma")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testGammaIncomplete")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testGammaIncompleteGeneralized")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLogGamma")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testDigamma")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testPolygamma")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testBeta")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testBetaIncomplete")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testBetaIncompleteGeneralized")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testPochhammer")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testBinomial")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testZeta")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testZetaHurwitz")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHypergeometric0F1")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHypergeometric1F1")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHypergeometric2F1")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHypergeometric0F1Regularized")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHypergeometric1F1Regularized")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHypergeometric2F1Regularized")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHypergeometricU")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testErf")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testErfc")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testErfi")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testFresnelS")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testFresnelC")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testExpIntegralE")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testExpIntegralEi")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLogIntegral")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testSinIntegral")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testCosIntegral")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testSinhIntegral")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testCoshIntegral")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAiryAi")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAiryAiPrime")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAiryBi")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testAiryBiPrime")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testBesselJ")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testBesselI")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testBesselY")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testBesselK")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testEllipticK")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testEllipticE")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHermiteH")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLaguerreL")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLaguerreLGeneralized")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLegendreP")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLegendrePAssociated")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLegendreQ")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLegendreQAssociated")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testSphericalHarmonicY")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testChebyshevT")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testChebyshevU")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testGegenbauerCRenormalized")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testGegenbauerC")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testJacobiP")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testFibonacci")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testEulerE")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testBernoulliB")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHarmonicNumber")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testHarmonicNumberGeneralized")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testPolylog")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testLogisticSigmoid")); suite.addTest(new FixedPrecisionApcomplexHelperTest("testUlp")); return suite; } public static void testValue() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("(2,3)"); Apcomplex result = helper.valueOf(z); assertEquals("value", new Apcomplex("(2,3)"), result); assertEquals("precision", 20, result.precision()); } public static void testAdd() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex(new Apfloat(2), new Apfloat(3)); Apcomplex w = new Apcomplex(new Apfloat(4), new Apfloat(5)); Apcomplex result = helper.add(z, w); assertEquals("value", new Apcomplex("(6, 8)"), result); assertEquals("precision", 20, result.precision()); } public static void testSubtract() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex(new Apfloat(2), new Apfloat(3)); Apcomplex w = new Apcomplex(new Apfloat(4), new Apfloat(7)); Apcomplex result = helper.subtract(z, w); assertEquals("value", new Apcomplex(new Apfloat(-2), new Apfloat(-4)), result); assertEquals("precision", 20, result.precision()); } public static void testMultiply() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("(1.0,1.0)"); Apcomplex w = new Apcomplex("(2.0,2.0)"); Apcomplex result = helper.multiply(z, w); assertEquals("value", new Apcomplex("(0,4.000)"), result); assertEquals("precision", 20, result.precision()); } public static void testDivide() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(30); Apcomplex z = new Apcomplex("(0,4.0)"); Apcomplex w = new Apcomplex("(2.0,2.0)"); Apcomplex result = helper.divide(z, w); assertEquals("value", helper.valueOf(new Apcomplex("(1,1)")), result); assertEquals("precision", 30, result.precision()); } public static void testReal() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(10); Apcomplex z = new Apcomplex("(2.0,3.0)"); Apfloat result = helper.real(z); assertEquals("value", new Apfloat(2), result); assertEquals("precision", 10, result.precision()); } public static void testImag() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(10); Apcomplex z = new Apcomplex("(2.0,3.0)"); Apfloat result = helper.imag(z); assertEquals("value", new Apfloat(3), result); assertEquals("precision", 10, result.precision()); } public static void testConj() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(10); Apcomplex z = new Apcomplex("(2.0,3.0)"); Apcomplex result = helper.conj(z); assertEquals("value", new Apcomplex("(2.00,-3.00)"), result); assertEquals("precision", 10, result.precision()); } public static void testArg() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(10); Apcomplex z = new Apcomplex("(2,-2)"); Apfloat result = helper.arg(z); assertEquals("value", new Apfloat("-0.7853981634"), result, new Apfloat("1e-9")); assertEquals("precision", 10, result.precision()); } public static void testNegate() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(50); Apcomplex z = new Apcomplex("(2.0,3.0)"); Apcomplex result = helper.negate(z); assertEquals("value", new Apcomplex("(-2.0,-3.0)"), result); assertEquals("precision", 50, result.precision()); } public static void testAbs() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("(4.0,3.0)"); Apfloat result = helper.abs(z); assertEquals("value", new Apfloat(5), result, new Apfloat("1e-4")); assertEquals("precision", 20, result.precision()); } public static void testNorm() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("(4.0,3.0)"); Apcomplex result = helper.norm(z); assertEquals("value", new Apfloat(25), result, new Apfloat("1e-4")); assertEquals("precision", 20, result.precision()); } public static void testScale() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("(4.0,3.0)"); Apcomplex result = helper.scale(z, 1); assertEquals("value", new Apcomplex(new Apfloat(40), new Apfloat(30)), result); assertEquals("precision", 20, result.precision()); } public static void testIntegerPow() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("(1.0,1.0)"); Apcomplex result = helper.pow(z, 4); assertEquals("value", new Apfloat(-4), result); assertEquals("precision", 20, result.precision()); } public static void testInverseRoot() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("-4.0"); Apcomplex result = helper.inverseRoot(z, 4); assertEquals("value", new Apcomplex("(0.50,-0.50)"), result, new Apfloat("1e-20")); assertEquals("precision", 20, result.precision()); result = helper.inverseRoot(z, 4, 1); assertEquals("value", new Apcomplex("(-0.50,-0.50)"), result, new Apfloat("1e-20")); assertEquals("precision", 20, result.precision()); } public static void testRoot() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("-4.0"); Apcomplex result = helper.root(z, 4); assertEquals("value", helper.valueOf(new Apcomplex("(1.0,1.0)")), result, new Apfloat("1e-19")); assertEquals("precision", 20, result.precision()); result = helper.root(z, 4, 1); assertEquals("value", helper.valueOf(new Apcomplex("(-1.0,1.0)")), result, new Apfloat("1e-19")); assertEquals("precision", 20, result.precision()); } public static void testSqrt() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("-4.0"); Apcomplex result = helper.sqrt(z); assertEquals("value", helper.valueOf(new Apcomplex("(0,2)")), result, new Apfloat("1e-19")); assertEquals("precision", 20, result.precision()); } public static void testCbrt() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("(-16,16)"); Apcomplex result = helper.cbrt(z); assertEquals("value", helper.valueOf(new Apcomplex("(2,2)")), result, new Apfloat("1e-19")); assertEquals("precision", 20, result.precision()); } public static void testAllRoots() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex("-4.0"); Apcomplex[] results = helper.allRoots(z, 4); assertEquals("results", 4, results.length); assertEquals("value 0", helper.valueOf(new Apcomplex("(1.0,1.0)")), results[0], new Apfloat("1e-19")); assertEquals("precision 0", 20, results[0].precision()); assertEquals("value 1", helper.valueOf(new Apcomplex("(-1.0,1.0)")), results[1], new Apfloat("1e-19")); assertEquals("precision 1", 20, results[1].precision()); assertEquals("value 2", helper.valueOf(new Apcomplex("(-1.0,-1.0)")), results[2], new Apfloat("1e-19")); assertEquals("precision 2", 20, results[2].precision()); assertEquals("value 3", helper.valueOf(new Apcomplex("(1.0,-1.0)")), results[3], new Apfloat("1e-19")); assertEquals("precision 3", 20, results[3].precision()); } public static void testAgm() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex a = new Apcomplex(new Apfloat(2), new Apfloat(3)); Apcomplex b = new Apcomplex(new Apfloat(4), new Apfloat(5)); Apcomplex result = helper.agm(a, b); assertEquals("value", new Apcomplex("(2.917544260525786263696583078746606829791948283056476178719125080604001346981059514497122989501231285,3.939113046692836869408348425071199799284873423064425353396384561367021573926690156072311985300901402)"), result, new Apfloat("5e-99")); assertEquals("precision", 100, result.precision()); } public static void testLog() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(40); Apcomplex z = new Apcomplex("-1"); Apcomplex result = helper.log(z); assertEquals("value", new Apcomplex("(0,3.141592653589793238462643383279502884197)"), result, new Apfloat("1e-39")); assertEquals("precision", 40, result.precision()); z = new Apcomplex("-1.000000000000000000000000000000001"); result = helper.log(z); assertEquals("close to 1 value", new Apcomplex("(9.999999999999999999999999999999995000000e-34,3.141592653589793238462643383279502884197)"), result, new Apfloat("1e-39")); assertEquals("close to 1 precision", 40, result.precision()); } public static void testLogBase() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(40); Apcomplex z = new Apcomplex("(0,1)"); Apcomplex w = new Apcomplex("-1"); Apcomplex result = helper.log(z, w); assertEquals("value", helper.valueOf(new Apcomplex("0.5")), result, new Apfloat("1e-39")); assertEquals("precision", 40, result.precision()); } public static void testExp() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(40); Apcomplex z = new Apcomplex(new Apfloat(0, 1L, 17)); Apcomplex result = helper.exp(z); assertEquals("value", Apfloat.ONE, result); assertEquals("precision", 40, result.precision()); assertEquals("radix", 17, result.radix()); z = new Apcomplex(new Apfloat(5000000000000L)); result = helper.exp(z); assertEquals("big value", new Apcomplex("1.816093715813449977121047779023089136641e2171472409516"), result, new Apfloat("5e2171472409477")); assertEquals("big precision", 40, result.precision()); z = new Apcomplex("(5000000000000,3.141592653589793238462643383279502884197)"); result = helper.exp(z); assertEquals("big value", new Apcomplex("-1.816093715813449977121047779023089136641e2171472409516"), result, new Apfloat("5e2171472409477")); assertEquals("big precision", 40, result.precision()); z = new Apcomplex(new Apfloat("1e-1000000000000000")); result = helper.exp(z); assertEquals("small value", new Apcomplex("1"), result, new Apfloat("5e-39")); assertEquals("small precision", 40, result.precision()); } public static void testPow() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(5), new Apfloat(4)); Apcomplex w = new Apcomplex(new Apfloat(3), new Apfloat(2)); Apcomplex result = helper.pow(z, w); assertEquals("value", new Apcomplex("(58.21450097059152465652652712230313017748868340728034764752454732020721827721557252703139305798831592,-35.32343693485837533012378741846981988609521878485308616153729164456178404672985609549591376583171254)"), result, new Apfloat("15e-98")); assertEquals("precision", 100, result.precision()); z = new Apcomplex(new Apfloat(5), new Apfloat(6)); w = Apcomplex.ZERO; result = helper.pow(z, w); assertEquals("value z^0", Apcomplex.ONE, result); assertEquals("precision z^0", 100, result.precision()); z = new Apcomplex(new Apfloat(5), new Apfloat(6)); w = Apcomplex.ONE; result = helper.pow(z, w); assertEquals("value z^1", new Apcomplex(new Apfloat(5), new Apfloat(6)), result); assertEquals("precision z^1", 100, result.precision()); z = Apcomplex.ONE; w = new Apcomplex(new Apfloat(5), new Apfloat(6)); result = helper.pow(z, w); assertEquals("value 1^z", Apcomplex.ONE, result); assertEquals("precision 1^z", 100, result.precision()); try { helper.pow(new Apcomplex(new Apfloat(0)), new Apcomplex(new Apfloat(0))); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { helper.pow(new Apcomplex(new Apfloat(100), new Apfloat(100)), new Apcomplex(new Apfloat(5000000000000000000L), new Apfloat(5000000000000000000L))); fail("Overflow should have occurred"); } catch (OverflowException oe) { // OK; result would overflow } } public static void testAcosh() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.acosh(z); assertEquals("value", new Apcomplex("(2.30550903124347694204183593813343089732908234612766434427244403789502387715767721380519816885689075,0.9368124611557199029125245765756089164871812290143448233044479241680079302681295000053794681278219233)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); z = Apcomplex.ZERO; result = helper.acosh(z); assertEquals("zero value", new Apcomplex(Apfloat.ZERO, new Apfloat("1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534")), result, new Apfloat("1e-98")); assertEquals("zero precision", 100, result.precision()); z = new Apint(0, 12); result = helper.acosh(z); assertEquals("zero real radix", 12, result.real().radix()); } public static void testAsinh() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.asinh(z); assertEquals("value", new Apcomplex("(2.299914040879269649955789630663175555365313484764636466611830082402437121311729696004733902877606405,0.9176168533514786557598627486701745415899523820362300027773647609161124445462833451286169894870273957)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); } public static void testAtanh() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.atanh(z); assertEquals("value", new Apcomplex("(0.1175009073114338884127342577870855161752247622030620101123480342515004695503565955468640257240191129,1.409921049596575522530619384460420782588207051908724814771070766475530084440199227135813201495737847)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); try { helper.atanh(new Apcomplex("1")); fail("atanh(1) accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } try { helper.atanh(new Apcomplex("-1")); fail("atanh(-1) accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } public static void testCosh() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.cosh(z); assertEquals("value", new Apcomplex("(-6.580663040551156432560744126538803616711267345515897773220218329756121215365251384163430874396326777,-7.581552742746544353716345286538426009387527590948852812949363456244614022672964969341075109130625439)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); } public static void testSinh() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.sinh(z); assertEquals("value", new Apcomplex("(-6.548120040911001647766811018835324740820888396888583499736134313039666841835229556393917343956455199,-7.619231720321410208487135736804311796557265472675575619426852074665542955161180340917983240028178743)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); z = new Apcomplex("(3e-1000000000000,4e-1000000000000)"); result = helper.sinh(z); assertEquals("small value", new Apcomplex("(3e-1000000000000,4e-1000000000000)").precision(100), result, new Apfloat("1e-1000000000099")); assertEquals("small precision", 100, result.precision()); } public static void testTanh() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.tanh(z); assertEquals("value", new Apcomplex("(1.000709536067232939329585472404172746215320905146760218019260729904286640361616955165037427906522640,0.004908258067496060259078786929932766843374215579355506974895511342674738432081043949327359968992711)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); z = new Apcomplex(new Apfloat(5000000000000L), new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068")); result = helper.tanh(z); assertEquals("big value", new Apcomplex(new Apfloat(1)), result, new Apfloat("1e-99")); assertEquals("big precision", 100, result.precision()); z = new Apcomplex(new Apfloat(-5000000000000L), new Apfloat("3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068")); result = helper.tanh(z); assertEquals("big negative value", new Apcomplex(new Apfloat(-1)), result, new Apfloat("1e-99")); assertEquals("big negative precision", 100, result.precision()); z = new Apcomplex("(3e-1000000000000,4e-1000000000000)"); result = helper.tanh(z); assertEquals("small value", new Apcomplex("(3e-1000000000000,4e-1000000000000)").precision(100), result, new Apfloat("1e-1000000000099")); assertEquals("small precision", 100, result.precision()); } public static void testAcos() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.acos(z); assertEquals("value", new Apcomplex("(0.9368124611557199029125245765756089164871812290143448233044479241680079302681295000053794681278219233,-2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); z = Apcomplex.ZERO; result = helper.acos(z); assertEquals("value", new Apfloat("1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); } public static void testAsin() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.asin(z); assertEquals("value", new Apcomplex("(0.6339838656391767163187971150641425256114034706732080871830243719859002728749749993086379445432366107,2.305509031243476942041835938133430897329082346127664344272444037895023877157677213805198168856890747)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); } public static void testAtan() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.atan(z); assertEquals("value", new Apcomplex("(1.448306995231464542145280451034113536641512650496960876923784338820230643349283451026750333836707538,0.1589971916799991743647610360070187815733054742350614709569622676518259973409283367912158396025096925)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); } public static void testCos() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.cos(z); assertEquals("value", new Apcomplex("(-27.03494560307422464769480266827091348467753695567661661019265514673434246483988229429946831870519301,-3.851153334811777536563337123053124569704160846091637003157728595256494186490481089994453362578315815)"), result, new Apfloat("1e-97")); assertEquals("precision", 100, result.precision()); // Loss of precision helper.cos(new Apcomplex(new Apfloat("1e1000", 3), new Apfloat("1.5"))); } public static void testSin() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.sin(z); assertEquals("value", new Apcomplex("(3.853738037919377321617528940463730667068274946989034956763346803317838585207899050385464301460315524,-27.01681325800393448809754375499215226336386568976518470594798897425063415478434990691671779691472675)"), result, new Apfloat("1e-97")); assertEquals("precision", 100, result.precision()); z = new Apcomplex("(3e-1000000000000,4e-1000000000000)"); result = helper.sin(z); assertEquals("small value", new Apcomplex("(3e-1000000000000,4e-1000000000000)").precision(100), result, new Apfloat("1e-1000000000099")); assertEquals("small precision", 100, result.precision()); // Loss of precision helper.sin(new Apcomplex(new Apfloat("1e1000", 3), new Apfloat("1.5"))); } public static void testTan() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(100); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.tan(z); assertEquals("value", new Apcomplex("(-0.0001873462046294784262242556377282181042124242427296606263580802232052224832174311687842725259181727521,0.9993559873814731413916496303201330615648885028135384928319757364498179348866065958722698773248799920)"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); z = new Apcomplex(Apfloat.ZERO, new Apfloat(5000000000000L)); result = helper.tan(z); assertEquals("big value", new Apcomplex(Apfloat.ZERO, new Apfloat(1)), result, new Apfloat("1e-99")); assertEquals("big precision", 100, result.precision()); z = new Apcomplex(Apfloat.ZERO, new Apfloat(-5000000000000L)); result = helper.tan(z); assertEquals("big negative value", new Apcomplex(Apfloat.ZERO, new Apfloat(-1)), result, new Apfloat("1e-99")); assertEquals("big negative precision", 100, result.precision()); z = new Apcomplex("(3e-1000000000000,4e-1000000000000)"); result = helper.tan(z); assertEquals("small value", new Apcomplex("(3e-1000000000000,4e-1000000000000)").precision(100), result, new Apfloat("1e-1000000000099")); assertEquals("small precision", 100, result.precision()); // Loss of precision helper.tan(new Apcomplex(new Apfloat("1e1000", 3), new Apfloat("1.5"))); } public static void testSinc() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex z = new Apcomplex(new Apfloat(2), new Apfloat(3)); Apcomplex result = helper.sinc(z); assertEquals("value", new Apcomplex("(0.446329031840243546,-2.753947027743647494)"), result, new Apfloat("1e-19")); assertEquals("precision", 20, result.precision()); z = new Apcomplex("(3e-1000000000000,4e-1000000000000)"); result = helper.sinc(z); assertEquals("small value", new Apcomplex("1").precision(20), result, new Apfloat("1e-19")); assertEquals("small precision", 20, result.precision()); // Loss of precision helper.sinc(new Apcomplex(new Apfloat("1e1000", 3), new Apfloat("1.5"))); } public static void testW() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(10); Apcomplex z = new Apcomplex(new Apfloat(3), new Apfloat(4)); Apcomplex result = helper.w(z); assertEquals("value", new Apcomplex("(1.2815618061,0.5330952220)"), result, new Apfloat("5e-9")); assertEquals("precision", 10, result.precision()); result = helper.w(z, -1); assertEquals("value -1", new Apcomplex("(0.2585674069,-3.8521166862)"), result, new Apfloat("5e-9")); assertEquals("precision -1", 10, result.precision()); } public static void testProduct() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex[] z = { new Apcomplex("(1,1)"), new Apcomplex("(10.1,10.1)"), new Apcomplex(new Apfloat(4), new Apfloat(4)) }; Apcomplex result = helper.product(z); assertEquals("value", new Apcomplex("(-80.8,80.8)"), result); assertEquals("precision", 20, result.precision()); } public static void testSum() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(20); Apcomplex[] z = { new Apcomplex("(12345,1e10)"), new Apcomplex("(0.6789,1)") }; Apcomplex result = helper.sum(z); assertEquals("value", new Apcomplex("(12345.6789,10000000001)"), result); assertEquals("precision", 20, result.precision()); } public static void testGamma() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(26); Apcomplex z = new Apcomplex("(1,1000000000000.1)"); Apcomplex result = helper.gamma(z); assertEquals("value", new Apcomplex("(2.2799397381057012808806415e-682188176916,2.56143734228029034694359025e-682188176915)"), result, new Apfloat("5e-682188176941")); assertEquals("precision", 26, result.precision()); z = new Apcomplex("(-99.99999999999999999999999999,0.00000000000000000000000001)"); result = helper.gamma(z); assertEquals("-99.99999999999999999999999999+0.00000000000000000000000001i value", new Apcomplex("(5.357551440627334615917734e-133,-5.357551440627334615917734e-133)"), result, new Apfloat("5e-158")); assertEquals("-99.99999999999999999999999999+0.00000000000000000000000001i precision", 26, result.precision()); } public static void testGammaIncomplete() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(5); Apcomplex a = new Apcomplex("(1,2)"); Apcomplex z = new Apcomplex("(3,4)"); Apcomplex result = helper.gamma(a, z); assertEquals("value", new Apcomplex("(0.0087875,-0.0046329)"), result, new Apfloat("5e-7")); assertEquals("precision", 5, result.precision()); } public static void testGammaIncompleteGeneralized() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex a = new Apcomplex("(1,2)"); Apcomplex z0 = new Apcomplex("(3,4)"); Apcomplex z1 = new Apcomplex("(5,6)"); Apcomplex result = helper.gamma(a, z0, z1); assertEquals("value", new Apcomplex("(0.00896428,-0.00326815)"), result, new Apfloat("5e-8")); assertEquals("precision", 6, result.precision()); } public static void testLogGamma() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(-2.5,1.3)"); Apcomplex result = helper.logGamma(z); assertEquals("value", new Apcomplex("(-3.17613,-7.9530)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); try { helper.logGamma(new Apcomplex("0")); fail("logGamma(0) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testDigamma() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(-2.5,1.3)"); Apcomplex result = helper.digamma(z); assertEquals("value", new Apcomplex("(1.18732,2.73369)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); try { helper.digamma(new Apcomplex("0")); fail("digamma(0) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testPolygamma() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.polygamma(2, z); assertEquals("value", new Apcomplex("(0.0144551,0.0206851)"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); try { helper.polygamma(1, new Apcomplex("0")); fail("polygamma(1, 0) accepted"); } catch (ArithmeticException ae) { // OK } try { helper.polygamma(-1, new Apcomplex("1")); fail("polygamma(-1, 1) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testBeta() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex a = new Apcomplex("(1.2,3.4)"), b = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.beta(a, b); assertEquals("value", new Apcomplex("(0.0133876,-0.0507409)"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); try { helper.beta(new Apcomplex("0"), new Apcomplex("0")); fail("beta(0, 0) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testBetaIncomplete() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(1.2,3.4)"), a = new Apcomplex("(3.4,5.6)"), b = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.beta(z, a, b); assertEquals("value", new Apcomplex("(464507,2794.79)"), result, new Apfloat("5e0")); assertEquals("precision", 6, result.precision()); try { helper.beta(new Apcomplex("0"), new Apcomplex("0"), new Apcomplex("0")); fail("beta(0, 0, 0) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testBetaIncompleteGeneralized() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z1 = new Apcomplex("(1.2,3.4)"), z2 = new Apcomplex("(2.3,3.4)"), a = new Apcomplex("(3.4,5.6)"), b = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.beta(z1, z2, a, b); assertEquals("value", new Apcomplex("(2.07486e7,-3.71971e7)"), result, new Apfloat("5e2")); assertEquals("precision", 6, result.precision()); try { helper.beta(new Apcomplex("0"), new Apcomplex("1"), new Apcomplex("0"), new Apcomplex("0")); fail("beta(0, 1, 0, 0) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testPochhammer() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(1.2,3.4)"), n = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.pochhammer(z, n); assertEquals("value", new Apcomplex("(-0.220154,0.555530)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); try { helper.pochhammer(new Apcomplex("-0.5"), new Apcomplex("0.5")); fail("pochhammer(-0.5, 0.5) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testBinomial() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(2.5,3.5)"); Apcomplex y = new Apcomplex("(1.2,2.3)"); Apcomplex result = helper.binomial(z, y); assertEquals("value", new Apcomplex("(-0.819659,2.18133)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); try { helper.binomial(new Apcomplex("-3"), new Apcomplex("(0,1)")); fail("binomial(-3,i) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testZeta() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex s = new Apcomplex("(1.5,2.5)"); Apcomplex result = helper.zeta(s); assertEquals("value", new Apcomplex("(0.725036,-0.213363)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); s = new Apcomplex("(0.5,10000)"); result = helper.zeta(s); assertEquals("value", new Apcomplex("(-0.339374,-0.0370915)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); s = new Apcomplex("(0.5,51000)"); result = helper.zeta(s); assertEquals("value", new Apcomplex("(0.00408268,0.00102467)"), result, new Apfloat("5e-8")); assertEquals("precision", 6, result.precision()); } public static void testZetaHurwitz() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex s = new Apcomplex("(-1.5,-2.5)"), a = new Apcomplex("(1.5,2.5)"); Apcomplex result = helper.zeta(s, a); assertEquals("value", new Apcomplex("(0.00199905,0.163402)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); try { helper = new FixedPrecisionApcomplexHelper(17); s = new Apcomplex("(-8.384883669867978e17, 0.0)"); a = new Apcomplex("(-8e-1, 1.199999999999999)"); helper.zeta(s, a); fail("No overflow"); } catch (OverflowException oe) { // OK } } public static void testHypergeometric0F1() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex a = new Apcomplex("(-1.5,-2.5)"), z = new Apcomplex("(1.5,2.5)"); Apcomplex result = helper.hypergeometric0F1(a, z); assertEquals("value", new Apcomplex("(0.414184,-0.0472966)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric1F1() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex a = new Apcomplex("(-1.5,-2.5)"), b = new Apcomplex("(-2.5,-3.5)"), z = new Apcomplex("(1.5,2.5)"); Apcomplex result = helper.hypergeometric1F1(a, b, z); assertEquals("value", new Apcomplex("(0.0471755,1.98433)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric2F1() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex a = new Apcomplex("(-1.5,-2.5)"), b = new Apcomplex("(-2.5,-3.5)"), c = new Apcomplex("(-4.5,-5.5)"), z = new Apcomplex("(1.5,2.5)"); Apcomplex result = helper.hypergeometric2F1(a, b, c, z); assertEquals("value", new Apcomplex("(27.9682,-33.1208)"), result, new Apfloat("5e-3")); // Note that result isn't that accurate assertEquals("precision", 6, result.precision()); } public static void testHypergeometric0F1Regularized() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex a = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.hypergeometric0F1Regularized(a, z); assertEquals("value", new Apcomplex("(-146.586,-325.487)"), result, new Apfloat("5e-3")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric1F1Regularized() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex a = new Apcomplex("(1.2,3.4)"), b = new Apcomplex("(3.4,5.6)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.hypergeometric1F1Regularized(a, b, z); assertEquals("value", new Apcomplex("(-166.217,-313.204)"), result, new Apfloat("5e-3")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric2F1Regularized() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex a = new Apcomplex("(1.2,3.4)"), b = new Apcomplex("(2.3,4.5)"), c = new Apcomplex("(3.4,5.6)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.hypergeometric2F1Regularized(a, b, c, z); assertEquals("value", new Apcomplex("(0.00228989,0.00227117)"), result, new Apfloat("5e-8")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometricU() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex a = new Apcomplex("(1.2,3.4)"), b = new Apcomplex("(3.4,5.6)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.hypergeometricU(a, b, z); assertEquals("value", new Apcomplex("(-0.27912,-1.99355)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); try { helper.hypergeometricU(new Apcomplex("1"), new Apcomplex("2"), new Apcomplex("0")); fail("U(1, 2, 0) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testErf() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(1.2,3.4)"); Apcomplex result = helper.erf(z); assertEquals("value", new Apcomplex("(3998.48,246.877)"), result, new Apfloat("5e-2")); assertEquals("precision", 6, result.precision()); z = new Apcomplex("1e6"); result = helper.erf(z); assertEquals("1000000 value", new Apcomplex("1.00000"), result, new Apfloat("5e-5")); assertEquals("1000000 precision", 6, result.precision()); z = new Apcomplex("(1000000,0.100000)"); result = helper.erf(z); assertEquals("1000000+01.i value", new Apcomplex("1.00000"), result, new Apfloat("5e-5")); assertEquals("1000000+01.i precision", 6, result.precision()); z = new Apcomplex("(0.100000,1000000)"); result = helper.erf(z); assertEquals("0.1+1000000i value", new Apcomplex("(-7.12728e434294481895,9.94943e434294481896)"), result, new Apfloat("5e434294481891")); assertEquals("0.1+1000000i precision", 6, result.precision()); z = new Apcomplex("(-0.1,-0.2)"); result = helper.erf(z); assertEquals("-0.1-0.2i value", new Apcomplex("(-0.117021,-0.226384)"), result, new Apfloat("5e-6")); assertEquals("-0.1-0.2i precision", 6, result.precision()); z = new Apcomplex("0"); result = helper.erf(z); assertEquals("0 value", new Apfloat("0"), result); assertEquals("0 precision", Apfloat.INFINITE, result.precision()); } public static void testErfc() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(1.2,3.4)"); Apcomplex result = helper.erfc(z); assertEquals("value", new Apcomplex("(-3997.48,-246.877)"), result, new Apfloat("5e-2")); assertEquals("precision", 6, result.precision()); z = new Apcomplex("1e6"); result = helper.erfc(z); assertEquals("1000000 value", new Apcomplex("3.15934e-434294481910"), result, new Apfloat("5e-434294481915")); assertEquals("1000000 precision", 6, result.precision()); z = new Apcomplex("-1e6"); result = helper.erfc(z); assertEquals("-1000000 value", new Apcomplex("2.00000"), result, new Apfloat("5e-5")); assertEquals("-1000000 precision", 6, result.precision()); z = new Apcomplex("(1000000,0.100000)"); result = helper.erfc(z); assertEquals("1000000+01.i value", new Apcomplex("(3.18294e-434294481910,2.28009e-434294481911)"), result, new Apfloat("5e-434294481915")); assertEquals("1000000+01.i precision", 6, result.precision()); z = new Apcomplex("(-1000000,0.100000)"); result = helper.erfc(z); assertEquals("-1000000+01.i value", new Apcomplex("2.00000"), result, new Apfloat("5e-5")); assertEquals("-1000000+01.i precision", 6, result.precision()); z = new Apcomplex("(0.100000,1000000)"); result = helper.erfc(z); assertEquals("0.1+1000000i value", new Apcomplex("(7.12728e434294481895,-9.94943e434294481896)"), result, new Apfloat("5e434294481891")); assertEquals("0.1+1000000i precision", 6, result.precision()); z = new Apcomplex("(-0.100000,1000000)"); result = helper.erfc(z); assertEquals("-0.1+1000000i value", new Apcomplex("(-7.12728e434294481895,-9.94943e434294481896)"), result, new Apfloat("5e434294481891")); assertEquals("-0.1+1000000i precision", 6, result.precision()); z = new Apcomplex("(-0.1,-0.2)"); result = helper.erfc(z); assertEquals("-0.1-0.2i value", new Apcomplex("(1.11702,0.226384)"), result, new Apfloat("5e-5")); assertEquals("-0.1-0.2i precision", 6, result.precision()); helper = new FixedPrecisionApcomplexHelper(30); z = new Apcomplex("3.53553390593273762200422181052e34"); result = helper.erfc(z); assertEquals("3.53553390593273762200422181052e34 value", new Apcomplex("0"), result); assertEquals("3.53553390593273762200422181052e34 precision", Apfloat.INFINITE, result.precision()); } public static void testErfi() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(4.3,2.1)"); Apcomplex result = helper.erfi(z); assertEquals("value", new Apcomplex("(47249.6,-148255)"), result, new Apfloat("5e0")); assertEquals("precision", 6, result.precision()); z = new Apcomplex("1e6"); result = helper.erfi(z); assertEquals("1000000 value", new Apcomplex("1.00751e434294481897"), result, new Apfloat("5e434294481892")); assertEquals("1000000 precision", 6, result.precision()); z = new Apcomplex("(1000000,0.100000)"); result = helper.erfi(z); assertEquals("1000000+01.i value", new Apcomplex("(9.94943e434294481896,-7.12728e434294481895)"), result, new Apfloat("5e434294481891")); assertEquals("1000000+01.i precision", 6, result.precision()); z = new Apcomplex("(0.100000,1000000)"); result = helper.erfi(z); assertEquals("0.1+1000000i value", new Apcomplex("(-2.28002e-434294481911,1.00000)"), result, new Apfloat("5e-5")); assertEquals("0.1+1000000i precision", 6, result.precision()); z = new Apcomplex("(-0.1,-0.2)"); result = helper.erfi(z); assertEquals("-0.1-0.2i value", new Apcomplex("(-0.108747,-0.224881)"), result, new Apfloat("5e-6")); assertEquals("-0.1-0.2i precision", 6, result.precision()); } public static void testFresnelS() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.fresnelS(z); assertEquals("value", new Apcomplex("(-5.2504e23,2.26321e24)"), result, new Apfloat("5e19")); assertEquals("precision", 6, result.precision()); } public static void testFresnelC() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.fresnelC(z); assertEquals("value", new Apcomplex("(2.26321e24,5.2504e23)"), result, new Apfloat("5e19")); assertEquals("precision", 6, result.precision()); } public static void testExpIntegralE() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.expIntegralE(ν, z); assertEquals("value", new Apcomplex("(-0.000238621,-0.000158482)"), result, new Apfloat("5e-9")); assertEquals("precision", 6, result.precision()); } public static void testExpIntegralEi() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.expIntegralEi(z); assertEquals("value", new Apcomplex("(-1.37581,-1.4625)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testLogIntegral() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.logIntegral(z); assertEquals("value", new Apcomplex("(3.69954,3.27594)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testSinIntegral() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.sinIntegral(z); assertEquals("value", new Apcomplex("(11.0328,-21.5511)"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testCosIntegral() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.cosIntegral(z); assertEquals("value", new Apcomplex("(-21.5507,-9.46169)"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testSinhIntegral() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.sinhIntegral(z); assertEquals("value", new Apcomplex("(-0.685633,-0.731803)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testCoshIntegral() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.coshIntegral(z); assertEquals("value", new Apcomplex("(-0.690179,-0.730699)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testAiryAi() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.airyAi(z); assertEquals("value", new Apcomplex("(0.0504756,0.110807)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); z = new Apcomplex("0"); result = helper.airyAi(z); assertEquals("0 value", new Apcomplex("0.355028"), result, new Apfloat("5e-6")); assertEquals("0 precision", 6, result.precision()); } public static void testAiryAiPrime() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.airyAiPrime(z); assertEquals("value", new Apcomplex("(0.0219253,-0.311242)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); z = new Apcomplex("0"); result = helper.airyAiPrime(z); assertEquals("0 value", new Apcomplex("-0.258819"), result, new Apfloat("5e-6")); assertEquals("0 precision", 6, result.precision()); } public static void testAiryBi() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.airyBi(z); assertEquals("value", new Apcomplex("(-0.154222,-0.458070)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); z = new Apcomplex("0"); result = helper.airyBi(z); assertEquals("0 value", new Apcomplex("0.614927"), result, new Apfloat("5e-6")); assertEquals("0 precision", 6, result.precision()); } public static void testAiryBiPrime() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.airyBiPrime(z); assertEquals("value", new Apcomplex("(0.870487,-1.15895)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); z = new Apcomplex("0"); result = helper.airyBiPrime(z); assertEquals("0 value", new Apcomplex("0.448288"), result, new Apfloat("5e-6")); assertEquals("0 precision", 6, result.precision()); } public static void testBesselJ() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.besselJ(ν, z); assertEquals("value", new Apcomplex("(-3.00868,0.804693)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testBesselI() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.besselI(ν, z); assertEquals("value", new Apcomplex("(30.6487,11.1050)"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testBesselY() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.besselY(ν, z); assertEquals("value", new Apcomplex("(-0.79791,-2.99960)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testBesselK() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.besselK(ν, z); assertEquals("value", new Apcomplex("(0.000359807,-0.00146406)"), result, new Apfloat("5e-8")); assertEquals("precision", 6, result.precision()); } public static void testEllipticK() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.ellipticK(z); assertEquals("value", new Apcomplex("(0.825751,0.572097)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); z = new Apcomplex("0"); result = helper.ellipticK(z); assertEquals("0 value", new Apcomplex("1.57080"), result, new Apfloat("5e-5")); assertEquals("0 precision", 6, result.precision()); } public static void testEllipticE() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(3.4,5.6)"); Apcomplex result = helper.ellipticE(z); assertEquals("value", new Apcomplex("(1.71210,-1.85499)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); z = new Apcomplex("0"); result = helper.ellipticE(z); assertEquals("0 value", new Apcomplex("1.57080"), result, new Apfloat("5e-5")); assertEquals("0 precision", 6, result.precision()); } public static void testHermiteH() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.hermiteH(ν, z); assertEquals("value", new Apcomplex("(0.220764,-1.33163)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testLaguerreL() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.laguerreL(ν, z); assertEquals("value", new Apcomplex("(9314.19,-22921.5)"), result, new Apfloat("5e-1")); assertEquals("precision", 6, result.precision()); } public static void testLaguerreLGeneralized() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), λ = new Apcomplex("(2.3,4.5)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.laguerreL(ν, λ, z); assertEquals("value", new Apcomplex("(282.914,-228.484)"), result, new Apfloat("5e-3")); assertEquals("precision", 6, result.precision()); } public static void testLegendreP() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.legendreP(ν, z); assertEquals("value", new Apcomplex("(-0.151267,-0.361369)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testLegendrePAssociated() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), μ = new Apcomplex("(2.3,4.5)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.legendreP(ν, μ, z); assertEquals("value", new Apcomplex("(-3.80093,4.47466)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testLegendreQ() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.legendreQ(ν, z); assertEquals("value", new Apcomplex("(0.601469,-0.241036)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testLegendreQAssociated() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), μ = new Apcomplex("(2.3,4.5)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.legendreQ(ν, μ, z); assertEquals("value", new Apcomplex("(7.02866,5.97026)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testSphericalHarmonicY() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex λ = new Apcomplex("(1.2,3.4)"), μ = new Apcomplex("(2.3,4.5)"), ϑ = new Apcomplex("(2.3,5.6)"), ϕ = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.sphericalHarmonicY(λ, μ, ϑ, ϕ); assertEquals("value", new Apcomplex("(-2.32719e-11,-7.09847e-11)"), result, new Apfloat("5e-16")); assertEquals("precision", 6, result.precision()); } public static void testChebyshevT() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.chebyshevT(ν, z); assertEquals("value", new Apcomplex("(0.204132,-0.313985)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testChebyshevU() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.chebyshevU(ν, z); assertEquals("value", new Apcomplex("(0.260989,-1.34243)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testGegenbauerCRenormalized() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.gegenbauerC(ν, z); assertEquals("value", new Apcomplex("(-0.126552,-0.164743)"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testGegenbauerC() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), λ = new Apcomplex("(2.3,4.5)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.gegenbauerC(ν, λ, z); assertEquals("value", new Apcomplex("(-2.08751,-0.60583)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testJacobiP() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), a = new Apcomplex("(2.3,4.5)"), b = new Apcomplex("(3.4,5.6)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.jacobiP(ν, a, b, z); assertEquals("value", new Apcomplex("(-0.497781,1.7976)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testFibonacci() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.fibonacci(ν, z); assertEquals("value", new Apcomplex("(-2183.84,2962.55)"), result, new Apfloat("5e-2")); assertEquals("precision", 6, result.precision()); } public static void testEulerE() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex result = helper.eulerE(4, new Apcomplex("(5.6,7.8)")); assertEquals("value", new Apcomplex("(-5064.11,-5661.49)"), result, new Apfloat("5e-2")); assertEquals("precision", 6, result.precision()); result = helper.eulerE(15, new Apcomplex("0")); assertEquals("0 value", new Apcomplex("(58098.1)"), result, new Apfloat("5e-1")); assertEquals("0 precision", 6, result.precision()); } public static void testBernoulliB() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex result = helper.bernoulliB(4, new Apcomplex("(5.6,7.8)")); assertEquals("value", new Apcomplex("(-5099.22,-5581.93)"), result, new Apfloat("5e-2")); assertEquals("precision", 6, result.precision()); result = helper.bernoulliB(18, new Apcomplex("0")); assertEquals("0 value", new Apcomplex("(54.9712)"), result, new Apfloat("5e-4")); assertEquals("0 precision", 6, result.precision()); } public static void testHarmonicNumber() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex result = helper.harmonicNumber(new Apcomplex("(5.6,7.8)")); assertEquals("value", new Apcomplex("(2.86985,0.906683)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testHarmonicNumberGeneralized() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(1.2,3.4)"), r = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.harmonicNumber(z, r); assertEquals("value", new Apcomplex("(1.74953,-0.747868)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testPolylog() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex ν = new Apcomplex("(1.2,3.4)"), z = new Apcomplex("(5.6,7.8)"); Apcomplex result = helper.polylog(ν, z); assertEquals("value", new Apcomplex("(-64.9686,18.3633)"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testLogisticSigmoid() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(6); Apcomplex z = new Apcomplex("(2.3,4.5)"); Apcomplex result = helper.logisticSigmoid(z); assertEquals("value", new Apcomplex("(1.01145,-0.101269)"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testUlp() { FixedPrecisionApcomplexHelper helper = new FixedPrecisionApcomplexHelper(5); Apfloat result = helper.ulp(new Apcomplex("(10,2)")); assertEquals("(10,2) value", new Apfloat("0.001"), result); assertEquals("(10,2) precision", 5, result.precision()); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/FixedPrecisionApfloatHelperTest.java000066400000000000000000002613741461767713300306760ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import junit.framework.TestSuite; /** * @version 1.14.0 * @author Mikko Tommila */ public class FixedPrecisionApfloatHelperTest extends ApfloatTestCase { public FixedPrecisionApfloatHelperTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new FixedPrecisionApfloatHelperTest("testValue")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAdd")); suite.addTest(new FixedPrecisionApfloatHelperTest("testSubtract")); suite.addTest(new FixedPrecisionApfloatHelperTest("testMultiply")); suite.addTest(new FixedPrecisionApfloatHelperTest("testDivide")); suite.addTest(new FixedPrecisionApfloatHelperTest("testIntegerPow")); suite.addTest(new FixedPrecisionApfloatHelperTest("testScale")); suite.addTest(new FixedPrecisionApfloatHelperTest("testInverseRoot")); suite.addTest(new FixedPrecisionApfloatHelperTest("testRoot")); suite.addTest(new FixedPrecisionApfloatHelperTest("testSqrt")); suite.addTest(new FixedPrecisionApfloatHelperTest("testCbrt")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAbs")); suite.addTest(new FixedPrecisionApfloatHelperTest("testCopySign")); suite.addTest(new FixedPrecisionApfloatHelperTest("testFloor")); suite.addTest(new FixedPrecisionApfloatHelperTest("testCeil")); suite.addTest(new FixedPrecisionApfloatHelperTest("testTruncate")); suite.addTest(new FixedPrecisionApfloatHelperTest("testFrac")); suite.addTest(new FixedPrecisionApfloatHelperTest("testRound")); suite.addTest(new FixedPrecisionApfloatHelperTest("testRoundToPrecision")); suite.addTest(new FixedPrecisionApfloatHelperTest("testRoundToInteger")); suite.addTest(new FixedPrecisionApfloatHelperTest("testRoundToPlaces")); suite.addTest(new FixedPrecisionApfloatHelperTest("testRoundToMultiple")); suite.addTest(new FixedPrecisionApfloatHelperTest("testNegate")); suite.addTest(new FixedPrecisionApfloatHelperTest("testModf")); suite.addTest(new FixedPrecisionApfloatHelperTest("testMod")); suite.addTest(new FixedPrecisionApfloatHelperTest("testFmod")); suite.addTest(new FixedPrecisionApfloatHelperTest("testMultiplyAdd")); suite.addTest(new FixedPrecisionApfloatHelperTest("testMultiplySubtract")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAgm")); suite.addTest(new FixedPrecisionApfloatHelperTest("testFactorial")); suite.addTest(new FixedPrecisionApfloatHelperTest("testDoubleFactorial")); suite.addTest(new FixedPrecisionApfloatHelperTest("testPi")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLogRadix")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLog")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLogBase")); suite.addTest(new FixedPrecisionApfloatHelperTest("testExp")); suite.addTest(new FixedPrecisionApfloatHelperTest("testPow")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAcosh")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAsinh")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAtanh")); suite.addTest(new FixedPrecisionApfloatHelperTest("testCosh")); suite.addTest(new FixedPrecisionApfloatHelperTest("testSinh")); suite.addTest(new FixedPrecisionApfloatHelperTest("testTanh")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAcos")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAsin")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAtan")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAtan2")); suite.addTest(new FixedPrecisionApfloatHelperTest("testCos")); suite.addTest(new FixedPrecisionApfloatHelperTest("testSin")); suite.addTest(new FixedPrecisionApfloatHelperTest("testTan")); suite.addTest(new FixedPrecisionApfloatHelperTest("testSinc")); suite.addTest(new FixedPrecisionApfloatHelperTest("testW")); suite.addTest(new FixedPrecisionApfloatHelperTest("testToDegrees")); suite.addTest(new FixedPrecisionApfloatHelperTest("testToRadians")); suite.addTest(new FixedPrecisionApfloatHelperTest("testProduct")); suite.addTest(new FixedPrecisionApfloatHelperTest("testSum")); suite.addTest(new FixedPrecisionApfloatHelperTest("testE")); suite.addTest(new FixedPrecisionApfloatHelperTest("testEuler")); suite.addTest(new FixedPrecisionApfloatHelperTest("testCatalan")); suite.addTest(new FixedPrecisionApfloatHelperTest("testGlaisher")); suite.addTest(new FixedPrecisionApfloatHelperTest("testKhinchin")); suite.addTest(new FixedPrecisionApfloatHelperTest("testGamma")); suite.addTest(new FixedPrecisionApfloatHelperTest("testGammaIncomplete")); suite.addTest(new FixedPrecisionApfloatHelperTest("testGammaIncompleteGeneralized")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLogGamma")); suite.addTest(new FixedPrecisionApfloatHelperTest("testDigamma")); suite.addTest(new FixedPrecisionApfloatHelperTest("testPolygamma")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBeta")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBetaIncomplete")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBetaIncompleteGeneralized")); suite.addTest(new FixedPrecisionApfloatHelperTest("testPochhammer")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBinomial")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBernoulli")); suite.addTest(new FixedPrecisionApfloatHelperTest("testZeta")); suite.addTest(new FixedPrecisionApfloatHelperTest("testZetaHurwitz")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHypergeometric0F1")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHypergeometric1F1")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHypergeometric2F1")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHypergeometric0F1Regularized")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHypergeometric1F1Regularized")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHypergeometric2F1Regularized")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHypergeometricU")); suite.addTest(new FixedPrecisionApfloatHelperTest("testErf")); suite.addTest(new FixedPrecisionApfloatHelperTest("testErfc")); suite.addTest(new FixedPrecisionApfloatHelperTest("testErfi")); suite.addTest(new FixedPrecisionApfloatHelperTest("testInverseErf")); suite.addTest(new FixedPrecisionApfloatHelperTest("testInverseErfc")); suite.addTest(new FixedPrecisionApfloatHelperTest("testFresnelS")); suite.addTest(new FixedPrecisionApfloatHelperTest("testFresnelC")); suite.addTest(new FixedPrecisionApfloatHelperTest("testExpIntegralE")); suite.addTest(new FixedPrecisionApfloatHelperTest("testExpIntegralEi")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLogIntegral")); suite.addTest(new FixedPrecisionApfloatHelperTest("testSinIntegral")); suite.addTest(new FixedPrecisionApfloatHelperTest("testCosIntegral")); suite.addTest(new FixedPrecisionApfloatHelperTest("testSinhIntegral")); suite.addTest(new FixedPrecisionApfloatHelperTest("testCoshIntegral")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAiryAi")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAiryAiPrime")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAiryBi")); suite.addTest(new FixedPrecisionApfloatHelperTest("testAiryBiPrime")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBesselJ")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBesselI")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBesselY")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBesselK")); suite.addTest(new FixedPrecisionApfloatHelperTest("testEllipticK")); suite.addTest(new FixedPrecisionApfloatHelperTest("testEllipticE")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHermiteH")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLaguerreL")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLaguerreLGeneralized")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLegendreP")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLegendrePAssociated")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLegendreQ")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLegendreQAssociated")); suite.addTest(new FixedPrecisionApfloatHelperTest("testChebyshevT")); suite.addTest(new FixedPrecisionApfloatHelperTest("testChebyshevU")); suite.addTest(new FixedPrecisionApfloatHelperTest("testGegenbauerCRenormalized")); suite.addTest(new FixedPrecisionApfloatHelperTest("testGegenbauerC")); suite.addTest(new FixedPrecisionApfloatHelperTest("testJacobiP")); suite.addTest(new FixedPrecisionApfloatHelperTest("testFibonacci")); suite.addTest(new FixedPrecisionApfloatHelperTest("testEulerE")); suite.addTest(new FixedPrecisionApfloatHelperTest("testBernoulliB")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHarmonicNumber")); suite.addTest(new FixedPrecisionApfloatHelperTest("testHarmonicNumberGeneralized")); suite.addTest(new FixedPrecisionApfloatHelperTest("testPolylog")); suite.addTest(new FixedPrecisionApfloatHelperTest("testLogisticSigmoid")); suite.addTest(new FixedPrecisionApfloatHelperTest("testRandom")); suite.addTest(new FixedPrecisionApfloatHelperTest("testRandomGaussian")); suite.addTest(new FixedPrecisionApfloatHelperTest("testContinuedFraction")); suite.addTest(new FixedPrecisionApfloatHelperTest("testConvergents")); suite.addTest(new FixedPrecisionApfloatHelperTest("testMax")); suite.addTest(new FixedPrecisionApfloatHelperTest("testMin")); suite.addTest(new FixedPrecisionApfloatHelperTest("testNextAfter")); suite.addTest(new FixedPrecisionApfloatHelperTest("testNextDown")); suite.addTest(new FixedPrecisionApfloatHelperTest("testNextUp")); suite.addTest(new FixedPrecisionApfloatHelperTest("testUlp")); return suite; } public static void testValue() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(20); Apfloat x = new Apfloat(2); Apfloat result = helper.valueOf(x); assertEquals("value", new Apfloat(2), result); assertEquals("precision", 20, result.precision()); } public static void testAdd() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(20); Apfloat x = new Apfloat(2); Apfloat y = new Apfloat(3); Apfloat result = helper.add(x, y); assertEquals("value", new Apfloat(5), result); assertEquals("precision", 20, result.precision()); } public static void testSubtract() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(20); Apfloat x = new Apfloat(3); Apfloat y = new Apfloat(5); Apfloat result = helper.subtract(x, y); assertEquals("value", new Apfloat(-2), result); assertEquals("precision", 20, result.precision()); } public static void testMultiply() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(20); Apfloat x = new Apfloat("2"); Apfloat y = new Apfloat("4"); Apfloat result = helper.multiply(x, y); assertEquals("value", new Apfloat("8"), result); assertEquals("precision", 20, result.precision()); } public static void testDivide() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("15"); Apfloat y = new Apfloat("3.0"); Apfloat result = helper.divide(x, y); assertEquals("value", new Apfloat(5), result); assertEquals("precision", 30, result.precision()); } public static void testIntegerPow() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("2"); Apfloat result = helper.pow(x, 60); assertEquals("value", new Apfloat(1L << 60), result); assertEquals("precision", 30, result.precision()); try { helper.pow(new Apfloat(0), 0); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } } public static void testScale() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("2"); Apfloat result = helper.scale(x, 60); assertEquals("value", new Apfloat("2e60"), result); assertEquals("precision", 30, result.precision()); } public static void testInverseRoot() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("1.2345678901234567890123456789"); Apfloat result = helper.inverseRoot(x, 1); assertEquals("value", new Apfloat("0.810000007290000066339000603685715"), result, new Apfloat(1e-30)); assertEquals("precision", 30, result.precision()); try { helper.inverseRoot(x, 0); fail("inverse zeroth root accepted"); } catch (ArithmeticException ae) { // OK: inverse zeroth root } try { helper.inverseRoot(new Apfloat(-2), 2); fail("inverse sqrt of -2 accepted"); } catch (ArithmeticException ae) { // OK: result would be imaginary } try { helper.inverseRoot(new Apfloat(0), 2); fail("inverse sqrt of 0 accepted"); } catch (ArithmeticException ae) { // OK: result would be infinite } } public static void testRoot() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat(2); Apfloat result = helper.root(x, 2); assertEquals("value", new Apfloat("1.4142135623730950488016887242097"), result, new Apfloat(1e-29)); assertEquals("precision", 30, result.precision()); try { helper.root(x, 0); fail("zeroth root accepted"); } catch (ArithmeticException ae) { // OK: zeroth root } try { helper.root(new Apfloat(-2), 2); fail("sqrt of -2 accepted"); } catch (ArithmeticException ae) { // OK: result would be imaginary } try { helper.root(new Apfloat(0), 0); fail("0th root of 0 accepted"); } catch (ArithmeticException ae) { // OK: result would be undefined } } public static void testSqrt() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat(2); Apfloat result = helper.sqrt(x); assertEquals("value", new Apfloat("1.4142135623730950488016887242097"), result, new Apfloat(1e-29)); assertEquals("precision", 30, result.precision()); } public static void testCbrt() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat(-2); Apfloat result = helper.cbrt(x); assertEquals("value", new Apfloat("-1.2599210498948731647672106072782"), result, new Apfloat(1e-29)); assertEquals("precision", 30, result.precision()); } public static void testAbs() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("-5"); Apfloat result = helper.abs(x); assertEquals("value", new Apfloat(5), result); assertEquals("precision", 30, result.precision()); } public static void testCopySign() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("2"); Apfloat y = new Apfloat(-1); Apfloat result = helper.copySign(x, y); assertEquals("value", new Apfloat(-2), result); assertEquals("precision", 30, result.precision()); } public static void testFloor() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("1.1"); Apfloat result = helper.floor(x); assertEquals("value", new Apfloat(1), result); assertEquals("precision", 30, result.precision()); } public static void testCeil() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("1.1"); Apfloat result = helper.ceil(x); assertEquals("value", new Apfloat(2), result); assertEquals("precision", 30, result.precision()); } public static void testTruncate() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("-1.1"); Apfloat result = helper.truncate(x); assertEquals("value", new Apfloat(-1), result); assertEquals("precision", 30, result.precision()); } public static void testFrac() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("-1.1"); Apfloat result = helper.frac(x); assertEquals("value", new Apfloat("-0.1"), result); assertEquals("precision", 30, result.precision()); } @SuppressWarnings("deprecation") public static void testRound() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(1); Apfloat x = new Apfloat("1.1"); Apfloat result = helper.round(x, RoundingMode.DOWN); assertEquals("value", new Apfloat("1.0"), result); assertEquals("precision", 1, result.precision()); } public static void testRoundToPrecision() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(1); Apfloat x = new Apfloat("1.1"); Apfloat result = helper.roundToPrecision(x, RoundingMode.DOWN); assertEquals("value", new Apfloat("1.0"), result); assertEquals("precision", 1, result.precision()); } public static void testRoundToInteger() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(1); Apfloat x = new Apfloat("1.1"); Apfloat result = helper.roundToInteger(x, RoundingMode.DOWN); assertEquals("value", new Apfloat("1.0"), result); assertEquals("precision", 1, result.precision()); } public static void testRoundToPlaces() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("1.19"); Apfloat result = helper.roundToPlaces(x, 1, RoundingMode.DOWN); assertEquals("value", new Apfloat("1.1"), result); assertEquals("precision", 6, result.precision()); } public static void testRoundToMultiple() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(5); Apfloat x = new Apfloat("3.1"), y = new Apfloat("1.1"); Apfloat result = helper.roundToMultiple(x, y, RoundingMode.DOWN); assertEquals("value", new Apfloat("2.2"), result); assertEquals("precision", 5, result.precision()); } public static void testNegate() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat(2); Apfloat result = helper.negate(x); assertEquals("value", new Apfloat(-2), result); assertEquals("precision", 30, result.precision()); } public static void testModf() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat("1.5"); Apfloat[] result = helper.modf(x); assertEquals("value 1", new Apfloat(1), result[0]); assertEquals("precision 1", 30, result[0].precision()); assertEquals("value 2", new Apfloat("0.5"), result[1]); assertEquals("precision 2", 30, result[1].precision()); x = new Apfloat("0.3"); result = helper.modf(x); assertEquals("0 value 1", new Apfloat(0), result[0]); assertEquals("0 value 2", new Apfloat("0.3"), result[1]); assertEquals("0 precision 2", 30, result[1].precision()); } public static void testMod() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat(-5); Apfloat y = new Apfloat(3); Apfloat result = helper.mod(x, y); assertEquals("value", new Apfloat(-2), result); assertEquals("precision", 30, result.precision()); } public static void testFmod() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat x = new Apfloat(-5); Apfloat y = new Apfloat(3); Apfloat result = helper.fmod(x, y); assertEquals("value", new Apfloat(-2), result); assertEquals("precision", 30, result.precision()); } public static void testMultiplyAdd() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat a = new Apfloat(2); Apfloat b = new Apfloat(3); Apfloat c = new Apfloat(4); Apfloat d = new Apfloat(5); Apfloat result = helper.multiplyAdd(a, b, c, d); assertEquals("value", new Apfloat(26), result); assertEquals("precision", 30, result.precision()); } public static void testMultiplySubtract() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(30); Apfloat a = new Apfloat(2); Apfloat b = new Apfloat(3); Apfloat c = new Apfloat(4); Apfloat d = new Apfloat(5); Apfloat result = helper.multiplySubtract(a, b, c, d); assertEquals("value", new Apfloat(-14), result); assertEquals("precision", 30, result.precision()); } public static void testAgm() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat a = new Apfloat("2"); Apfloat b = new Apfloat("1"); Apfloat result = helper.agm(a, b); assertEquals("value", new Apfloat("1.4567910310469068691864323832650819749738639432213055907941723832679264545802509002574737128184484443281894"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); } public static void testFactorial() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(10); Apfloat result = helper.factorial(100); assertEquals("value", new Apfloat(9.332621544e157), result, new Apfloat("5e148")); assertEquals("precision", 10, result.precision()); result = helper.factorial(10, 16); assertEquals("value 16", new Apfloat(0x375F00, Apfloat.DEFAULT, 16), result); assertEquals("precision 16", 10, result.precision()); try { helper.factorial(7, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testDoubleFactorial() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(10); Apfloat result = helper.doubleFactorial(100); assertEquals("value", new Apfloat(3.424322470e79), result, new Apfloat("5e70")); assertEquals("precision", 10, result.precision()); result = helper.doubleFactorial(10, 16); assertEquals("value 16", new Apfloat(0xF00, Apfloat.DEFAULT, 16), result); assertEquals("precision 16", 10, result.precision()); try { helper.doubleFactorial(7, 1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testPi() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(10); Apfloat result = helper.pi(); assertEquals("value", new Apfloat(3.141592653), result, new Apfloat("1e-9")); assertEquals("precision", 10, result.precision()); result = helper.pi(16); assertEquals("value 16", new Apfloat("3.243F6A888", Apfloat.DEFAULT, 16), result, new Apfloat(1e-9, 1, 16)); assertEquals("precision 16", 10, result.precision()); try { helper.pi(1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testLogRadix() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(10); Apfloat result = helper.logRadix(2); assertEquals("value", new Apfloat(0.69314718055994530941723212145818, Apfloat.DEFAULT, 2), result, new Apfloat("1e-10", Apfloat.DEFAULT, 2)); assertEquals("precision", 10, result.precision()); try { helper.logRadix(1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testLog() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat("2"); Apfloat result = helper.log(x); assertEquals("value", new Apfloat("0.693147180559945309417232121458176568075500134360255254120680009493393621969694715605863326996418687"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); x = new Apfloat("1.000000000000000000000000000000001"); result = helper.log(x); assertEquals("close to 1 value", new Apfloat("9.999999999999999999999999999999995000000000000000000000000000000003333333333333333333333333333333331e-34"), result, new Apfloat("1e-134")); assertEquals("close to 1 precision", 100, result.precision()); try { helper.log(new Apfloat(0)); fail("log of zero accepted"); } catch (ArithmeticException ae) { // OK; result would be -infinite } try { helper.log(new Apfloat(-1)); fail("log of -1 accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } } public static void testLogBase() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat("4"); Apfloat b = new Apfloat("2"); Apfloat result = helper.log(x, b); assertEquals("value", new Apfloat(2), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); } public static void testExp() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(2); Apfloat result = helper.exp(x); assertEquals("value", new Apfloat("7.389056098930650227230427460575007813180315570551847324087127822522573796079057763384312485079121794"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); x = new Apfloat(0, Apfloat.DEFAULT, 7); result = helper.exp(x); assertEquals("value 7", Apfloat.ONE, result); assertEquals("precision 7", 100, result.precision()); assertEquals("radix", 7, result.radix()); x = new Apfloat("0.0001"); result = helper.exp(x); assertEquals("value limited", new Apfloat("1.000100005000166670833416668055575397073415454172178381034635390972311235972781757573430475110294393"), result); assertEquals("precision limited", 100, result.precision()); x = new Apfloat(5000000000000L); result = helper.exp(x); assertEquals("big value", new Apfloat("1.816093715813449977121047779023089136640518780204394932476747172911899687306423540158950650025496032e2171472409516"), result, new Apfloat("5e2171472409417")); assertEquals("big precision", 100, result.precision()); try { helper.exp(new Apfloat("50000000000000000000")); fail("Overflow should have occurred"); } catch (OverflowException oe) { // OK; result would overflow } } public static void testPow() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(2); Apfloat y = new Apfloat(3); Apfloat result = helper.pow(x, y); assertEquals("value", new Apfloat(8), result, new Apfloat("5e-99")); assertEquals("precision", 100, result.precision()); x = new Apfloat(1); y = new Apfloat(1); result = helper.pow(x, y); assertEquals("value", new Apfloat(1), result, new Apfloat("5e-99")); assertEquals("precision", 100, result.precision()); result = helper.pow(new Apfloat("1.5"), new Apfloat("2.5")); assertEquals("1.5^2.5 value", new Apfloat("2.755675960631075360471944584044127815961690915738753894486779138157330424639479404857341862242720264"), result, new Apfloat("5e-99")); assertEquals("1.5^2.5 precision", 100, result.precision()); result = helper.pow(new Apfloat(-4), new Apfloat(-2)); assertEquals("-4^-2 value", new Apfloat("0.0625"), result, new Apfloat("5e-101")); assertEquals("-4^-2 precision", 100, result.precision()); result = helper.pow(new Apfloat("-1.00000000000000000000000000001"), new Apfloat("1e20")); assertEquals("-1.00000000000000000000000000001^1e20 value", new Apfloat("1.0000000010000000005000000001666666667033333333366666666655555555549539682538306"), result, new Apfloat("5e-79")); assertEquals("-1.00000000000000000000000000001^1e20 precision", 100, result.precision()); try { helper.pow(new Apfloat(0), new Apfloat(0)); fail("0^0 accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } try { helper.pow(new Apfloat(100), new Apfloat(5000000000000000000L)); fail("Overflow should have occurred"); } catch (OverflowException oe) { // OK; result would overflow } try { helper.pow(new Apfloat(-2), new Apfloat("1.3")); fail("pow of negative number accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } } public static void testAcosh() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(2); Apfloat result = helper.acosh(x); assertEquals("value", new Apfloat("1.316957896924816708625046347307968444026981971467516479768472256920460185416443976074219013450101783"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); try { helper.acosh(new Apfloat("0.9")); fail("acosh(0.9) accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } try { helper.acosh(new Apfloat("-0.5")); fail("acosh(-0.5) accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } } public static void testAsinh() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat("2"); Apfloat result = helper.asinh(x); assertEquals("value", new Apfloat("1.443635475178810342493276740273105269405553003156981558983054506520491602824665323236028287368170425"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); } public static void testAtanh() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat("0.5"); Apfloat result = helper.atanh(x); assertEquals("value", new Apfloat("0.5493061443340548456976226184612628523237452789113747258673471668187471466093044834368078774068660444"), result, new Apfloat("5e-100")); assertEquals("precision", 100, result.precision()); try { helper.atanh(new Apfloat("1")); fail("atanh(1) accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } try { helper.atanh(new Apfloat("-1")); fail("atanh(-1) accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } public static void testCosh() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(2); Apfloat result = helper.cosh(x); assertEquals("value", new Apfloat("3.7621956910836314595622134777737461082939735582307116027776433475883235850902727266607053037848894217"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); } public static void testSinh() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(2); Apfloat result = helper.sinh(x); assertEquals("value", new Apfloat("3.626860407847018767668213982801261704886342012321135721309484474934250210988785036723607181294232373"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); x = new Apfloat("2e-1000000000000"); result = helper.sinh(x); assertEquals("small value", new Apfloat("2e-1000000000000", 100), result, new Apfloat("1e-1000000000099")); assertEquals("small precision", 100, result.precision()); } public static void testTanh() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(2); Apfloat result = helper.tanh(x); assertEquals("value", new Apfloat("0.96402758007581688394641372410092315025502997624093477604826321741310794631761020255947485004520768915"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); x = new Apfloat(5000000000000L); result = helper.tanh(x); assertEquals("big value", new Apfloat(1), result, new Apfloat("1e-99")); assertEquals("big precision", 100, result.precision()); x = new Apfloat("2e-1000000000000"); result = helper.tanh(x); assertEquals("small value", new Apfloat("2e-1000000000000", 100), result, new Apfloat("1e-1000000000099")); assertEquals("small precision", 100, result.precision()); } public static void testAcos() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat("0.5"); Apfloat result = helper.acos(x); assertEquals("value", new Apfloat("1.04719755119659774615421446109316762806572313312503527365831486410260546876206966620934494178070569"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); result = helper.acos(new Apfloat(0)); assertEquals("value 0", new Apfloat("1.570796326794896619231321691639751442098584699687552910487472296153908203143104499314017412671058534"), result, new Apfloat("1e-99")); assertEquals("precision 0", 100, result.precision()); try { helper.acos(new Apfloat("1.1")); fail("acos(1.1) accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } } public static void testAsin() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = Apfloat.ONE.divide(new Apfloat(2)); Apfloat result = helper.asin(x); assertEquals("value", new Apfloat("0.5235987755982988730771072305465838140328615665625176368291574320513027343810348331046724708903528447"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); try { helper.asin(new Apfloat("1.1")); fail("asin(1.1) accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } } public static void testAtan() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat("0.5"); Apfloat result = helper.atan(x); assertEquals("value", new Apfloat("0.4636476090008061162142562314612144020285370542861202638109330887201978641657417053006002839848878926"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); } public static void testAtan2() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(2); Apfloat result = helper.atan2(x, x); assertEquals("value", new Apfloat("0.7853981633974483096156608458198757210492923498437764552437361480769541015715522496570087063355292670"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); try { helper.atan2(new Apfloat(0), new Apfloat(0)); fail("atan2(0,0) accepted"); } catch (ArithmeticException ae) { // OK; result would be undefined } } public static void testCos() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(1); Apfloat result = helper.cos(x); assertEquals("value", new Apfloat("0.5403023058681397174009366074429766037323104206179222276700972553811003947744717645179518560871830893"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); x = new Apfloat(1).add(ApfloatMath.scale(ApfloatMath.pi(200), 100)); result = helper.cos(x); assertEquals("value 100", new Apfloat("0.5403023058681397174009366074429766037323104206179222276700972553811003947744717645179518560871830893"), result, new Apfloat("1e-99")); assertEquals("precision 100", 100, result.precision()); // Loss of precision helper.cos(new Apfloat("1e1000")); } public static void testSin() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(1); Apfloat result = helper.sin(x); assertEquals("value", new Apfloat("0.8414709848078965066525023216302989996225630607983710656727517099919104043912396689486397435430526959"), result, new Apfloat("1e-99")); assertEquals("precision", 100, result.precision()); x = new Apfloat(1).add(ApfloatMath.scale(ApfloatMath.pi(200), 100)); result = helper.sin(x); assertEquals("value 100", new Apfloat("0.8414709848078965066525023216302989996225630607983710656727517099919104043912396689486397435430526959"), result, new Apfloat("1e-99")); assertEquals("precision 100", 100, result.precision()); result = helper.sin(new Apfloat(0)); assertEquals("value 0", new Apfloat(0), result); x = new Apfloat("2e-1000000000000"); result = helper.sin(x); assertEquals("small value", new Apfloat("2e-1000000000000", 100), result, new Apfloat("1e-1000000000099")); assertEquals("small precision", 100, result.precision()); // Loss of precision helper.sin(new Apfloat("1e1000")); } public static void testTan() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(1); Apfloat result = helper.tan(x); assertEquals("value", new Apfloat("1.55740772465490223050697480745836017308725077238152003838394660569886139715172728955509996520224298"), result, new Apfloat("1e-98")); assertEquals("precision", 100, result.precision()); result = helper.tan(new Apfloat(0)); assertEquals("value 0", new Apfloat(0), result); x = new Apfloat("2e-1000000000000"); result = helper.tan(x); assertEquals("small value", new Apfloat("2e-1000000000000", 100), result, new Apfloat("1e-1000000000099")); assertEquals("small precision", 100, result.precision()); // Loss of precision helper.tan(new Apfloat("1e1000")); } public static void testSinc() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat x = new Apfloat(2); Apfloat result = helper.sinc(x); assertEquals("value", new Apfloat("0.4546487134128408476980099329558724213511274857239451341894865057654836507703917723100633444624796902"), result, new Apfloat("1e-100")); assertEquals("precision", 100, result.precision()); x = new Apfloat(3).add(ApfloatMath.scale(ApfloatMath.pi(200), 100)); result = helper.sinc(x); assertEquals("value 100", new Apfloat("4.491989370379195769076292132633729542441923579269675954842294682403756171256157205040164432640257852e-102"), result, new Apfloat("1e-201")); assertEquals("precision 100", 100, result.precision()); result = helper.sinc(new Apfloat(0)); assertEquals("value 0", new Apfloat(1), result); x = new Apfloat("2e-1000000000000"); result = helper.sinc(x); assertEquals("small value", new Apfloat(1, 100), result, new Apfloat("1e-99")); assertEquals("small precision", 100, result.precision()); // Loss of precision helper.sinc(new Apfloat("1e1000")); } public static void testW() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(10); Apfloat x = new Apfloat(3); Apfloat result = helper.w(x); assertEquals("value", new Apfloat("1.049908895"), result, new Apfloat("5e-9")); assertEquals("precision", 10, result.precision()); } public static void testToDegrees() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(10); Apfloat x = new Apfloat(2.0 * Math.PI); Apfloat result = helper.toDegrees(x); assertEquals("value", new Apfloat(360), result, new Apfloat("5e-7")); assertEquals("precision", 10, result.precision()); } public static void testToRadians() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(10); Apfloat x = new Apfloat(-720); Apfloat result = helper.toRadians(x); assertEquals("value", new Apfloat(-4.0 * Math.PI), result, new Apfloat("5e-7")); assertEquals("precision", 10, result.precision()); } public static void testProduct() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(10); Apfloat[] x = { new Apfloat(1), new Apfloat("2.0"), new Apfloat("3.00000000000000000000000") }; Apfloat result = helper.product(x); assertEquals("value", new Apfloat(6), result); assertEquals("precision", 10, result.precision()); } public static void testSum() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(10); Apfloat[] x = { new Apfloat("1234567891.1"), new Apfloat("1.1"), new Apfloat("8.000000000000000000000001") }; Apfloat result = helper.sum(x); assertEquals("value", new Apfloat(1234567900), result); assertEquals("precision", 10, result.precision()); } public static void testE() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat result = helper.e(); assertEquals("value", new Apfloat("2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427"), result, new Apfloat("5e-99")); assertEquals("precision", 100, result.precision()); result = helper.e(16); assertEquals("value 16", new Apfloat("2.b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfef324e7738926cfbe5f4bf8d8d8c31d763da0", Apfloat.DEFAULT, 16), result, new Apfloat(4e-121, 1, 16)); assertEquals("precision 16", 100, result.precision()); try { helper.euler(1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testEuler() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat result = helper.euler(); assertEquals("value", new Apfloat("0.5772156649015328606065120900824024310421593359399235988057672348848677267776646709369470632917467495"), result, new Apfloat("5e-100")); assertEquals("precision", 100, result.precision()); result = helper.euler(16); assertEquals("value 16", new Apfloat("0.93c467e37db0c7a4d1be3f810152cb56a1cecc3af65cc0190c03df34709affbd8e4b59fa03a9f0eed0649ccb621057d11057", Apfloat.DEFAULT, 16), result, new Apfloat(4e-121, 1, 16)); assertEquals("precision 16", 100, result.precision()); try { helper.euler(1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testCatalan() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat result = helper.catalan(); assertEquals("value", new Apfloat("0.9159655941772190150546035149323841107741493742816721342664981196217630197762547694793565129261151062"), result, new Apfloat("5e-100")); assertEquals("precision", 100, result.precision()); result = helper.catalan(16); assertEquals("value 16", new Apfloat("0.ea7cb89f409ae845215822e37d32d0c63ec43e1381c2ff8094a263e5a3ccd76f94dc058a46eec5858f924d663f739c42ec96", Apfloat.DEFAULT, 16), result, new Apfloat(4e-121, 1, 16)); assertEquals("precision 16", 100, result.precision()); try { helper.catalan(1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testGlaisher() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat result = helper.glaisher(); assertEquals("value", new Apfloat("1.282427129100622636875342568869791727767688927325001192063740021740406308858826461129736491958202374"), result, new Apfloat("5e-99")); assertEquals("precision", 100, result.precision()); result = helper.glaisher(16); assertEquals("value 16", new Apfloat("1.484d24f2fd8731313ed56e343da775794768e0cabd1a57f64185e87606793b86ed92e2208eddc71810d323a0fb6eced612d8", Apfloat.DEFAULT, 16), result, new Apfloat(7e-120, 1, 16)); assertEquals("precision 16", 100, result.precision()); try { helper.glaisher(1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testKhinchin() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat result = helper.khinchin(); assertEquals("value", new Apfloat("2.685452001065306445309714835481795693820382293994462953051152345557218859537152002801141174931847698"), result, new Apfloat("5e-99")); assertEquals("precision", 100, result.precision()); result = helper.khinchin(16); assertEquals("value 16", new Apfloat("2.af79c8478da1aef2fdf3e394667f9c3392e021e61829ddfa4d87063b39522441a3b8f9696bfe8c1fd5ea06533d2dbf594d55", Apfloat.DEFAULT, 16), result, new Apfloat(7e-120, 1, 16)); assertEquals("precision 16", 100, result.precision()); try { helper.khinchin(1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testGamma() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(27); Apfloat x = new Apfloat("1000000000000.1"); Apfloat result = helper.gamma(x); assertEquals("value", new Apfloat("2.22465301759833318396785103e11565705518092"), result, new Apfloat("5e11565705518066")); assertEquals("precision", 27, result.precision()); x = new Apfloat("-99.99999999999999999999999999"); result = helper.gamma(x); assertEquals("-99.99999999999999999999999999 value", new Apfloat("1.07151028812546692318354681e-132"), result, new Apfloat("5e-158")); assertEquals("-99.99999999999999999999999999 precision", 27, result.precision()); } public static void testGammaIncomplete() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(5); Apfloat a = new Apfloat("1.5"); Apfloat x = new Apfloat("3.5"); Apfloat result = helper.gamma(a, x); assertEquals("value", new Apfloat("0.063718"), result, new Apfloat("5e-6")); assertEquals("precision", 5, result.precision()); } public static void testGammaIncompleteGeneralized() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat a = new Apfloat("1.5"); Apfloat x0 = new Apfloat("2.5"); Apfloat x1 = new Apfloat("3.5"); Apfloat result = helper.gamma(a, x0, x1); assertEquals("value", new Apfloat("0.0885335"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); } public static void testLogGamma() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("2.5"); Apfloat result = helper.logGamma(x); assertEquals("value", new Apfloat("0.284683"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); try { helper.logGamma(new Apfloat(0)); fail("logGamma(0) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testDigamma() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("2.5"); Apfloat result = helper.digamma(x); assertEquals("value", new Apfloat("0.703157"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); try { helper.digamma(new Apfloat(0)); fail("digamma(0) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testPolygamma() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("2.5"); Apfloat result = helper.polygamma(2, x); assertEquals("value", new Apfloat("-0.236204"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testBeta() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat a = new Apfloat("-1.5"), b = new Apfloat("2.5"); Apfloat result = helper.beta(a, b); assertEquals("value", new Apfloat("3.14159"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testBetaIncomplete() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("0.5"), a = new Apfloat("-1.5"), b = new Apfloat("2.5"); Apfloat result = helper.beta(x, a, b); assertEquals("value", new Apfloat("2.90413"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); try { helper.beta(new Apfloat("1.5"), new Apfloat("-1.5"), new Apfloat("2.5")); fail("beta(1.5, -1.5, 2.5) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testBetaIncompleteGeneralized() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x1 = new Apfloat("0.5"), x2 = new Apfloat("0.6"), a = new Apfloat("1.5"), b = new Apfloat("2.5"); Apfloat result = helper.beta(x1, x2, a, b); assertEquals("value", new Apfloat("0.0223574"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); } public static void testPochhammer() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"), n = new Apfloat("2.5"); Apfloat result = helper.pochhammer(x, n); assertEquals("value", new Apfloat("0.423142"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testBinomial() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("2.5"); Apfloat y = new Apfloat("1.2"); Apfloat result = helper.binomial(x, y); assertEquals("value", new Apfloat("2.58529"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); result = helper.binomial(10, 2); assertEquals("long value", new Apfloat(45), result); assertEquals("long precision", 6, result.precision()); result = helper.binomial(9, 3, 12); assertEquals("radix 12 value", new Apint(84, 12), result); assertEquals("radix 12 precision", 6, result.precision()); try { helper.binomial(new Apfloat(-1), new Apfloat("-1.1")); fail("binomial(-1,-1.1) accepted"); } catch (ArithmeticException ae) { // OK } } public static void testBernoulli() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat result = helper.bernoulli(10); assertEquals("value", new Apfloat("0.0757576"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); try { helper.bernoulli(-1); fail("bernoulli(-1) accepted"); } catch (IllegalArgumentException iae) { // OK } } public static void testZeta() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat s = new Apfloat("1.5"); Apfloat result = helper.zeta(s); assertEquals("value", new Apfloat("2.61238"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); s = new Apfloat("1e8"); result = helper.zeta(s); assertEquals("value", new Apfloat("1.00000"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); s = new Apfloat(-1001); result = helper.zeta(s); assertEquals("value", new Apfloat("-1.34859e1771"), result, new Apfloat("5e1766")); assertEquals("precision", 6, result.precision()); } public static void testZetaHurwitz() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat s = new Apfloat("-1.5"), a = new Apfloat("1.5"); Apfloat result = helper.zeta(s, a); assertEquals("value", new Apfloat("-0.337079"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric0F1() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat a = new Apfloat("-1.5"), x = new Apfloat("1.5"); Apfloat result = helper.hypergeometric0F1(a, x); assertEquals("value", new Apfloat("3.42337"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric1F1() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat a = new Apfloat("-1.5"), b = new Apfloat("-2.5"), x = new Apfloat("1.5"); Apfloat result = helper.hypergeometric1F1(a, b, x); assertEquals("value", new Apfloat("1.79268"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric2F1() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat a = new Apfloat("-1.5"), b = new Apfloat("-2.5"), c = new Apfloat("-4.5"), x = new Apfloat("0.5"); Apfloat result = helper.hypergeometric2F1(a, b, c, x); assertEquals("value", new Apfloat("0.606092"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric0F1Regularized() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat a = new Apfloat("-3"), x = new Apfloat("1.5"); Apfloat result = helper.hypergeometric0F1Regularized(a, x); assertEquals("value", new Apfloat("0.28272"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric1F1Regularized() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat a = new Apfloat("-1.5"), b = new Apfloat("-3"), x = new Apfloat("1.5"); Apfloat result = helper.hypergeometric1F1Regularized(a, b, x); assertEquals("value", new Apfloat("0.263170"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometric2F1Regularized() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat a = new Apfloat("-1.5"), b = new Apfloat("-2.5"), c = new Apfloat("-4"), x = new Apfloat("0.5"); Apfloat result = helper.hypergeometric2F1Regularized(a, b, c, x); assertEquals("value", new Apfloat("-0.00131556"), result, new Apfloat("5e-8")); assertEquals("precision", 6, result.precision()); } public static void testHypergeometricU() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat a = new Apfloat("-1.5"), b = new Apfloat("-3"), x = new Apfloat("1.5"); Apfloat result = helper.hypergeometricU(a, b, x); assertEquals("value", new Apfloat("8.44588"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testErf() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.erf(x); assertEquals("value", new Apfloat("-0.966105"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); x = new Apfloat("-0.5"); result = helper.erf(x); assertEquals("-0.5 value", new Apfloat("-0.520499"), result, new Apfloat("5e-6")); assertEquals("-0.5 precision", 6, result.precision()); x = new Apfloat("0"); result = helper.erf(x); assertEquals("0 value", new Apfloat("0"), result); assertEquals("0 precision", Apfloat.INFINITE, result.precision()); } public static void testErfc() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.erfc(x); assertEquals("value", new Apfloat("1.96611"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); x = new Apfloat("-0.5"); result = helper.erfc(x); assertEquals("-0.5 value", new Apfloat("1.52049"), result, new Apfloat("5e-5")); assertEquals("-0.5 precision", 6, result.precision()); } public static void testErfi() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.erfi(x); assertEquals("value", new Apfloat("-4.58473"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); x = new Apfloat("-0.5"); result = helper.erfi(x); assertEquals("-0.5 value", new Apfloat("-0.614952"), result, new Apfloat("5e-6")); assertEquals("-0.5 precision", 6, result.precision()); } public static void testInverseErf() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-0.5"); Apfloat result = helper.inverseErf(x); assertEquals("value", new Apfloat("-0.476936"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); x = new Apfloat("0.999999"); result = helper.inverseErf(x); assertEquals("value", new Apfloat("3.45891"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); helper = new FixedPrecisionApfloatHelper(40); x = new Apfloat("0.9999999999999999999999999999999999999999"); result = helper.inverseErf(x); assertEquals("value", new Apfloat("9.448789766720858262503185054107090039066"), result, new Apfloat("5e-39")); assertEquals("precision", 40, result.precision()); x = new Apfloat("-0.9999999999999999999999999999999999999999"); result = helper.inverseErf(x); assertEquals("value", new Apfloat("-9.448789766720858262503185054107090039066"), result, new Apfloat("5e-39")); assertEquals("precision", 40, result.precision()); x = new Apfloat("0.1111111111111111111111111111111111111111", Apfloat.DEFAULT, 2); result = helper.inverseErf(x); assertEquals("0.1111111111111111111111111111111111111111 radix 2 value", new Apfloat("101.0000110100011110111111001101101111101", 40, 2), result, new Apfloat("1e-37", 1, 2)); assertEquals("0.1111111111111111111111111111111111111111 radix 2 precision", 40, result.precision()); } public static void testInverseErfc() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("0.5"); Apfloat result = helper.inverseErfc(x); assertEquals("value", new Apfloat("0.476936"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); x = new Apfloat("1.99999"); result = helper.inverseErfc(x); assertEquals("value", new Apfloat("-3.12341"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); x = new Apfloat("1e-1000"); result = helper.inverseErfc(x); assertEquals("1e-1000 value", new Apfloat("47.9389"), result, new Apfloat("5e-4")); assertEquals("1e-1000 precision", 6, result.precision()); helper = new FixedPrecisionApfloatHelper(40); x = new Apfloat("1.9999999999999999999999999999999999999999"); result = helper.inverseErfc(x); assertEquals("value", new Apfloat("-9.448789766720858262503185054107090039065"), result, new Apfloat("5e-39")); assertEquals("precision", 40, result.precision()); x = new Apfloat("1.111111111111111111111111111111111111111", Apfloat.DEFAULT, 2); result = helper.inverseErfc(x); assertEquals("1.111111111111111111111111111111111111111 radix 2 value", new Apfloat("-100.1111101111000101001000000001001100101", 40, 2), result, new Apfloat("1e-37", 1, 2)); assertEquals("1.111111111111111111111111111111111111111 radix 2 precision", 40, result.precision()); } public static void testFresnelS() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.fresnelS(x); assertEquals("value", new Apfloat("-0.697505"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); } public static void testFresnelC() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.fresnelC(x); assertEquals("value", new Apfloat("-0.445261"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testExpIntegralE() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.expIntegralE(ν, x); assertEquals("value", new Apfloat("0.0559441"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); } public static void testExpIntegralEi() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.expIntegralEi(x); assertEquals("value", new Apfloat("-0.100020"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testLogIntegral() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("1.5"); Apfloat result = helper.logIntegral(x); assertEquals("value", new Apfloat("0.125065"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testSinIntegral() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.sinIntegral(x); assertEquals("value", new Apfloat("-1.32468"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testCosIntegral() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("1.5"); Apfloat result = helper.cosIntegral(x); assertEquals("value", new Apfloat("0.470356"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testSinhIntegral() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.sinhIntegral(x); assertEquals("value", new Apfloat("-1.70065"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testCoshIntegral() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("1.5"); Apfloat result = helper.coshIntegral(x); assertEquals("value", new Apfloat("1.60063"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testAiryAi() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.airyAi(x); assertEquals("value", new Apfloat("0.464257"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); x = new Apfloat("0"); result = helper.airyAi(x); assertEquals("0 value", new Apfloat("0.355028"), result, new Apfloat("5e-6")); assertEquals("0 precision", 6, result.precision()); } public static void testAiryAiPrime() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.airyAiPrime(x); assertEquals("value", new Apfloat("0.309187"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); x = new Apfloat("0"); result = helper.airyAiPrime(x); assertEquals("0 value", new Apfloat("-0.258819"), result, new Apfloat("5e-6")); assertEquals("0 precision", 6, result.precision()); } public static void testAiryBi() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.airyBi(x); assertEquals("value", new Apfloat("-0.191785"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); x = new Apfloat("0"); result = helper.airyBi(x); assertEquals("0 value", new Apfloat("0.614927"), result, new Apfloat("5e-6")); assertEquals("0 precision", 6, result.precision()); } public static void testAiryBiPrime() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.airyBiPrime(x); assertEquals("value", new Apfloat("0.557908"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); x = new Apfloat("0"); result = helper.airyBiPrime(x); assertEquals("0 value", new Apfloat("0.448288"), result, new Apfloat("5e-6")); assertEquals("0 precision", 6, result.precision()); } public static void testBesselJ() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.besselJ(ν, x); assertEquals("value", new Apfloat("-0.140294"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testBesselI() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.besselI(ν, x); assertEquals("value", new Apfloat("1.81529"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testBesselY() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.besselY(ν, x); assertEquals("value", new Apfloat("-0.525080"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testBesselK() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.besselK(ν, x); assertEquals("value", new Apfloat("0.0910923"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); } public static void testEllipticK() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.ellipticK(x); assertEquals("value", new Apfloat("1.23301"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); x = new Apfloat("0"); result = helper.ellipticK(x); assertEquals("0 value", new Apfloat("1.57080"), result, new Apfloat("5e-5")); assertEquals("0 precision", 6, result.precision()); } public static void testEllipticE() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("-1.5"); Apfloat result = helper.ellipticE(x); assertEquals("value", new Apfloat("2.05299"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); x = new Apfloat("0"); result = helper.ellipticE(x); assertEquals("0 value", new Apfloat("1.57080"), result, new Apfloat("5e-5")); assertEquals("0 precision", 6, result.precision()); } public static void testHermiteH() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.hermiteH(ν, x); assertEquals("value", new Apfloat("0.0789789"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); } public static void testLaguerreL() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.laguerreL(ν, x); assertEquals("value", new Apfloat("24.0654"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testLaguerreLGeneralized() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), λ = new Apfloat("-2.3"), x = new Apfloat("2.5"); Apfloat result = helper.laguerreL(ν, λ, x); assertEquals("value", new Apfloat("84.8071"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testLegendreP() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.legendreP(ν, x); assertEquals("value", new Apfloat("1.46890"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testLegendrePAssociated() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), μ = new Apfloat("-2.3"), x = new Apfloat("0.9"); Apfloat result = helper.legendreP(ν, μ, x); assertEquals("value", new Apfloat("0.0124664"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); } public static void testLegendreQ() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("0.9"); Apfloat result = helper.legendreQ(ν, x); assertEquals("value", new Apfloat("0.787390"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testLegendreQAssociated() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), μ = new Apfloat("-2.3"), x = new Apfloat("0.9"); Apfloat result = helper.legendreQ(ν, μ, x); assertEquals("value", new Apfloat("-21.6240"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testChebyshevT() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.chebyshevT(ν, x); assertEquals("value", new Apfloat("5.29150"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testChebyshevU() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.chebyshevU(ν, x); assertEquals("value", new Apfloat("-0.377964"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testGegenbauerCRenormalized() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.gegenbauerC(ν, x); assertEquals("value", new Apfloat("-7.05534"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testGegenbauerC() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), λ = new Apfloat("-2.3"), x = new Apfloat("2.5"); Apfloat result = helper.gegenbauerC(ν, λ, x); assertEquals("value", new Apfloat("-136.555"), result, new Apfloat("5e-3")); assertEquals("precision", 6, result.precision()); } public static void testJacobiP() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), a = new Apfloat("-1.9"), b = new Apfloat("-2.3"), x = new Apfloat("2.5"); Apfloat result = helper.jacobiP(ν, a, b, x); assertEquals("value", new Apfloat("29.5169"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testFibonacci() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("2.5"); Apfloat result = helper.fibonacci(ν, x); assertEquals("value", new Apfloat("0.0648922"), result, new Apfloat("5e-7")); assertEquals("precision", 6, result.precision()); } public static void testEulerE() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat result = helper.eulerE(4, new Apfloat("2.5")); assertEquals("value", new Apfloat("10.3125"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testBernoulliB() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat result = helper.bernoulliB(4, new Apfloat("2.5")); assertEquals("value", new Apfloat("14.0292"), result, new Apfloat("5e-4")); assertEquals("precision", 6, result.precision()); } public static void testHarmonicNumber() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat result = helper.harmonicNumber(new Apfloat("2.5")); assertEquals("value", new Apfloat("1.68037"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testHarmonicNumberGeneralized() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("1.5"), r = new Apfloat("2.5"); Apfloat result = helper.harmonicNumber(x, r); assertEquals("value", new Apfloat("1.11412"), result, new Apfloat("5e-5")); assertEquals("precision", 6, result.precision()); } public static void testPolylog() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat ν = new Apfloat("-1.5"), x = new Apfloat("0.9"); Apfloat result = helper.polylog(ν, x); assertEquals("value", new Apfloat("368.902"), result, new Apfloat("5e-3")); assertEquals("precision", 6, result.precision()); } public static void testLogisticSigmoid() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat x = new Apfloat("0.9"); Apfloat result = helper.logisticSigmoid(x); assertEquals("value", new Apfloat("0.710950"), result, new Apfloat("5e-6")); assertEquals("precision", 6, result.precision()); } public static void testRandom() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); for (int i = 0; i < 100; i++) { Apfloat result = helper.random(); assertEquals("value", new Apfloat("0.5"), result, new Apfloat("0.5")); assertEquals("precision", 100, result.precision()); result = helper.random(16); assertEquals("value 16", new Apfloat("0.8", Apfloat.DEFAULT, 16), result, new Apfloat("0.8", 1, 16)); assertEquals("precision 16", 100, result.precision()); } try { helper.random(1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testRandomGaussian() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); for (int i = 0; i < 100; i++) { Apfloat result = helper.randomGaussian(); assertEquals("value", new Apfloat("0"), result, new Apfloat("5")); assertEquals("precision", 100, result.precision()); result = helper.randomGaussian(16); assertEquals("value 16", new Apfloat("0", Apfloat.DEFAULT, 16), result, new Apfloat("5", 1, 16)); assertEquals("radix 16", 16, result.radix()); assertEquals("precision 16", 100, result.precision()); } try { helper.randomGaussian(1); fail("Radix 1 accepted"); } catch (NumberFormatException nfe) { // OK; invalid radix } } public static void testContinuedFraction() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat[] result = helper.continuedFraction(new Apfloat("3.14159265358979323846264338328"), 3); assertEquals("values", 3, result.length); assertEquals("value[0]", new Apfloat(3), result[0]); assertEquals("precision[0]", 6, result[0].precision()); assertEquals("value[1]", new Apfloat(7), result[1]); assertEquals("precision[1]", 6, result[1].precision()); assertEquals("value[2]", new Apfloat(15), result[2]); assertEquals("precision[2]", 6, result[2].precision()); } public static void testConvergents() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(6); Apfloat[] result = helper.convergents(new Apfloat("3.14159265358979323846264338328"), 3); assertEquals("values", 3, result.length); assertEquals("value[0]", new Apfloat("3.00000"), result[0]); assertEquals("precision[0]", 6, result[0].precision()); assertEquals("value[1]", new Apfloat("3.14286"), result[1], new Apfloat("0.00005")); assertEquals("precision[1]", 6, result[1].precision()); assertEquals("value[2]", new Apfloat("3.14151"), result[2], new Apfloat("0.00005")); assertEquals("precision[2]", 6, result[2].precision()); } public static void testMax() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat result = helper.max(new Apfloat(1), new Apfloat(2)); assertEquals("1,2 value", new Apfloat("2"), result); assertEquals("1,2 precision", 100, result.precision()); result = helper.max(new Apfloat(2), new Apfloat(1)); assertEquals("2,1 value", new Apfloat("2"), result); assertEquals("2,1 precision", 100, result.precision()); } public static void testMin() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(100); Apfloat result = helper.min(new Apfloat(1), new Apfloat(2)); assertEquals("1,2 value", new Apfloat("1"), result); assertEquals("1,2 precision", 100, result.precision()); result = helper.min(new Apfloat(2), new Apfloat(1)); assertEquals("2,1 value", new Apfloat("1"), result); assertEquals("2,1 precision", 100, result.precision()); } public static void testNextAfter() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(5); Apfloat result = helper.nextAfter(new Apfloat(1), new Apfloat(2)); assertEquals("1,2 value", new Apfloat("1.0001"), result); assertEquals("1,2 precision", 5, result.precision()); } public static void testNextDown() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(5); Apfloat result = helper.nextDown(new Apfloat(1)); assertEquals("1 value", new Apfloat("0.9999"), result); assertEquals("1 precision", 5, result.precision()); } public static void testNextUp() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(5); Apfloat result = helper.nextUp(new Apfloat(1)); assertEquals("1 value", new Apfloat("1.0001"), result); assertEquals("1 precision", 5, result.precision()); } public static void testUlp() { FixedPrecisionApfloatHelper helper = new FixedPrecisionApfloatHelper(5); Apfloat result = helper.ulp(new Apfloat(1)); assertEquals("1 value", new Apfloat("0.0001"), result); assertEquals("1 precision", 5, result.precision()); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/GCDHelperTest.java000066400000000000000000000053611461767713300250410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.Random; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @since 1.6 * @version 1.6 * @author Mikko Tommila */ public class GCDHelperTest extends TestCase { public GCDHelperTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new GCDHelperTest("testGcd")); return suite; } public static void testGcd() { Random random = new Random(); for (int i = 0; i < 5; i++) { Apint a = new Apint(getString(random)); Apint b = new Apint(getString(random)); Apint c = elementaryGcd(a, b); Apint d = ApintMath.gcd(a, b); assertEquals("GCD", c, d); } } private static String getString(Random random) { int length = random.nextInt(65000) + 35000; StringBuilder buffer = new StringBuilder(length); for (int i = 0; i < length; i++) { buffer.append((char) (random.nextInt(10) + (int) '0')); } return buffer.toString(); } private static Apint elementaryGcd(Apint a, Apint b) throws ApfloatRuntimeException { while (b.signum() != 0) { Apint r = a.mod(b); a = b; b = r; } return ApintMath.abs(a); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/HypergeometricHelperTest.java000066400000000000000000000237331461767713300274350ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import junit.framework.TestSuite; /** * @version 1.13.0 * @author Mikko Tommila */ public class HypergeometricHelperTest extends ApfloatTestCase { public HypergeometricHelperTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new HypergeometricHelperTest("testHypergeometricPFQ")); suite.addTest(new HypergeometricHelperTest("testHypergeometricPFQRegularized")); return suite; } public static void testHypergeometricPFQ() { // 3F2 Apcomplex a = HypergeometricHelper.hypergeometricPFQ(new Apcomplex[] { new Apcomplex("1.00000"), new Apcomplex("1.00000"), new Apcomplex("1.00000") }, new Apcomplex[] { new Apcomplex("2.00000"), new Apcomplex("2.00000") }, new Apcomplex("0.100000")); // p = q + 1, this is actually Li_2(z) / z assertEquals("1, 1, 1; 2, 2; 0.1 precision", 6, a.precision()); assertEquals("1, 1, 1; 2, 2; 0.1 value", new Apcomplex("1.02618"), a, new Apfloat("5e-5")); // z = 0 a = HypergeometricHelper.hypergeometricPFQ(new Apcomplex[] { new Apcomplex("(2,3)"), new Apcomplex("(4,5)"), new Apcomplex("(6,7)") }, new Apcomplex[] {}, new Apcomplex("0")); // p > q + 1 assertEquals("(2,3), (4,5), (6,7);; 0 precision", 1, a.precision()); assertEquals("(2,3), (4,5), (6,7);; 0 value", new Apcomplex("1"), a); // Polynomial case a = HypergeometricHelper.hypergeometricPFQ(new Apcomplex[] { new Apcomplex("-1.00000"), new Apcomplex("2.00000"), new Apcomplex("3.00000") }, new Apcomplex[] { new Apcomplex("4.00000") }, new Apcomplex("5.00000")); // p > q + 1 assertEquals("-1, 2, 3; 4; 5 precision", 6, a.precision()); assertEquals("-1, 2, 3; 4; 5 value", new Apcomplex("-6.50000"), a, new Apfloat("5e-5")); // Reduction to 2F1 a = HypergeometricHelper.hypergeometricPFQ(new Apcomplex[] { new Apcomplex("1.00000"), new Apcomplex("42.0000"), new Apcomplex("2.20000") }, new Apcomplex[] { new Apcomplex("3.30000"), new Apcomplex("42.0000") }, new Apcomplex("5.00000")); assertEquals("1, 42, 2.2; 3.3, 42; 5 precision", 5, a.precision()); assertEquals("1, 42, 2.2; 3.3, 42; 5 value", new Apcomplex("(-0.527130,-0.228019)"), a, new Apfloat("5e-6")); // Non converging cases try { HypergeometricHelper.hypergeometricPFQ(new Apcomplex[] { new Apcomplex("1.00000"), new Apcomplex("42.0000"), new Apcomplex("2.20000") }, new Apcomplex[] { new Apcomplex("3.30000") }, new Apcomplex("0.10000")); fail("p > q + 1 accepted with z != 0 and not polynomial"); } catch (ArithmeticException ae) { // OK, result is infinite } } public static void testHypergeometricPFQRegularized() { Apcomplex a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("3.00000"), new Apcomplex("3.00000") }, new Apcomplex[] { new Apcomplex("4.00000"), new Apcomplex("4.00000"), new Apcomplex("4.00000") }, new Apcomplex("0.100000")); assertEquals("3, 3; 4, 4, 4; 0.1 precision", 6, a.precision()); assertEquals("3, 3; 4, 4, 4; 0.1 value", new Apcomplex("0.00469515"), a, new Apfloat("5e-8")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("0"), new Apcomplex("3.00000") }, new Apcomplex[] { new Apcomplex("4.00000"), new Apcomplex("4.00000"), new Apcomplex("4.00000") }, new Apcomplex("0.100000")); assertEquals("0, 3; 4, 4, 4; 0.1 precision", 6, a.precision()); assertEquals("0, 3; 4, 4, 4; 0.1 value", new Apcomplex("0.00462963"), a, new Apfloat("5e-8")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("3.00000"), new Apcomplex("0") }, new Apcomplex[] { new Apcomplex("4.00000"), new Apcomplex("4.00000"), new Apcomplex("4.00000") }, new Apcomplex("0.100000")); assertEquals("3, 0; 4, 4, 4; 0.1 precision", 6, a.precision()); assertEquals("3, 0; 4, 4, 4; 0.1 value", new Apcomplex("0.00462963"), a, new Apfloat("5e-8")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("3.000000"), new Apcomplex("3.000000") }, new Apcomplex[] { new Apcomplex("-4.000000"), new Apcomplex("4.000000"), new Apcomplex("4.000000") }, new Apcomplex("0.1000000")); assertEquals("3, 3; -4, 4, 4; 0.1 precision", 6, a.precision()); assertEquals("3, 3; -4, 4, 4; 0.1 value", new Apcomplex("3.29832e-10"), a, new Apfloat("5e-15")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("0"), new Apcomplex("3.00000") }, new Apcomplex[] { new Apcomplex("-4.00000"), new Apcomplex("4.00000"), new Apcomplex("4.00000") }, new Apcomplex("0.100000")); assertEquals("0, 3; -4, 4, 4; 0.1 precision", Apfloat.INFINITE, a.precision()); assertEquals("0, 3; -4, 4, 4; 0.1 value", new Apcomplex("0"), a); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("(2.00000,3.00000)"), new Apcomplex("(3.00000,4.00000)") }, new Apcomplex[] { new Apcomplex("-4.00000"), new Apcomplex("(4.00000,5.00000)"), new Apcomplex("(5.00000,6.00000)") }, new Apcomplex("(0.100000,0.200000)")); assertEquals("2+3i, 3+4i; -4, 4+5i, 5+6i; 0.1+0.2i precision", 6, a.precision()); assertEquals("2+3i, 3+4i; -4, 4+5i, 5+6i; 0.1+0.2i value", new Apcomplex("(2.39246e-7,4.75224e-8)"), a, new Apfloat("5e-12")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("(2.00000,3.00000)"), new Apcomplex("(3.00000,4.00000)") }, new Apcomplex[] { new Apcomplex("-4.00000"), new Apcomplex("-5.00000"), new Apcomplex("(5.00000,6.00000)") }, new Apcomplex("(0.100000,0.200000)")); assertEquals("2+3i, 3+4i; -4, -5, 5+6i; 0.1+0.2i precision", 6, a.precision()); assertEquals("2+3i, 3+4i; -4, -5, 5+6i; 0.1+0.2i value", new Apcomplex("(0.000531945,0.0000629876 )"), a, new Apfloat("5e-9")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("(2.00000,3.00000)"), new Apcomplex("(3.00000,4.00000)") }, new Apcomplex[] { new Apcomplex("-5.00000"), new Apcomplex("-4.00000"), new Apcomplex("(5.00000,6.00000)") }, new Apcomplex("(0.100000,0.200000)")); assertEquals("2+3i, 3+4i; -5, -4, 5+6i; 0.1+0.2i precision", 6, a.precision()); assertEquals("2+3i, 3+4i; -5, -4, 5+6i; 0.1+0.2i value", new Apcomplex("(0.000531945,0.0000629876 )"), a, new Apfloat("5e-9")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("(2.00000,3.00000)"), new Apcomplex("(3.00000,4.00000)") }, new Apcomplex[] { new Apcomplex("-6.00001"), new Apcomplex("-5.00000"), new Apcomplex("(5.00000,6.00000)") }, new Apcomplex("(0.100000,0.200000)")); assertEquals("2+3i, 3+4i; -6.00001, -5, 5+6i; 0.1+0.2i precision", 6, a.precision()); assertEquals("2+3i, 3+4i; -6.00001, -5, 5+6i; 0.1+0.2i value", new Apcomplex("(8.05671e-6,0.000115069)"), a, new Apfloat("5e-9")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("(2.00000,3.00000)"), new Apcomplex("(3.00000,4.00000)") }, new Apcomplex[] { new Apcomplex("-5.99999"), new Apcomplex("-5.00000"), new Apcomplex("(5.00000,6.00000)") }, new Apcomplex("(0.100000,0.200000)")); assertEquals("2+3i, 3+4i; -5.99999, -5, 5+6i; 0.1+0.2i precision", 6, a.precision()); assertEquals("2+3i, 3+4i; -5.99999, -5, 5+6i; 0.1+0.2i value", new Apcomplex("(8.06751e-6,0.000115071)"), a, new Apfloat("5e-9")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("(2.00000,3.00000)"), new Apcomplex("(3.00000,4.00000)") }, new Apcomplex[] { new Apcomplex("-6.99999"), new Apcomplex("-5.00000"), new Apcomplex("(5.00000,6.00000)") }, new Apcomplex("(0.100000,0.200000)")); assertEquals("2+3i, 3+4i; -6.99999, -5, 5+6i; 0.1+0.2i precision", 5, a.precision()); assertEquals("2+3i, 3+4i; -6.99999, -5, 5+6i; 0.1+0.2i value", new Apcomplex("(-0.0000115393,3.94988e-6)"), a, new Apfloat("5e-9")); a = HypergeometricHelper.hypergeometricPFQRegularized(new Apcomplex[] { new Apcomplex("(2.00000,3.00000)"), new Apcomplex("(3.00000,4.00000)") }, new Apcomplex[] { new Apcomplex("-7.50000"), new Apcomplex("-5.00000"), new Apcomplex("(5.00000,6.00000)") }, new Apcomplex("(0.100000,0.200000)")); assertEquals("2+3i, 3+4i; -7.5, -5, 5+6i; 0.1+0.2i precision", 6, a.precision()); assertEquals("2+3i, 3+4i; -7.5, -5, 5+6i; 0.1+0.2i value", new Apcomplex("(0.000209539,-0.0000265153)"), a, new Apfloat("5e-9")); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/LambertWHelperTest.java000066400000000000000000001714751461767713300261730ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import junit.framework.TestSuite; /** * @since 1.8.0 * @version 1.10.0 * @author Mikko Tommila */ public class LambertWHelperTest extends ApfloatTestCase { public LambertWHelperTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new LambertWHelperTest("testReal")); suite.addTest(new LambertWHelperTest("testComplex0")); suite.addTest(new LambertWHelperTest("testComplexMinus1")); suite.addTest(new LambertWHelperTest("testComplex1")); suite.addTest(new LambertWHelperTest("testComplexMinus2")); suite.addTest(new LambertWHelperTest("testComplex2")); suite.addTest(new LambertWHelperTest("testComplexBigK")); return suite; } public static void testReal() { Apfloat a = new Apfloat(0); assertEquals("0", Apfloat.ZERO, LambertWHelper.w(a)); a = new Apfloat("-0.1", 100); assertEquals("-0.1", new Apfloat("-0.1118325591589629648335694568202658422726453622912658633296897727621943319600088273854870109175450158"), LambertWHelper.w(a), new Apfloat("5e-100")); a = new Apfloat("0.1", 100); assertEquals("0.1", new Apfloat("0.09127652716086226429989572142317956865311922405147203264830839460717224625441755165020664592995606710"), LambertWHelper.w(a), new Apfloat("5e-101")); a = new Apfloat("0.9", 100); assertEquals("0.9", new Apfloat("0.5298329656334344121333664395454630485778813226980424276591307583895461718680181558074329260683928070"), LambertWHelper.w(a), new Apfloat("5e-100")); a = new Apfloat("1", 100); assertEquals("1", new Apfloat("0.5671432904097838729999686622103555497538157871865125081351310792230457930866845666932194469617522946"), LambertWHelper.w(a), new Apfloat("6e-100")); a = new Apfloat("2", 100); assertEquals("2", new Apfloat("0.8526055020137254913464724146953174668984533001514035087721073946525150656742630448965773783502494847"), LambertWHelper.w(a), new Apfloat("5e-100")); a = new Apfloat("2", 100, 16); assertEquals("2 radix 16", new Apfloat("0.da445aab89e28ccbe8ac8e1abd5cd1db4d2d1ee258d0f8a8b165f2b6e7e714a04cbc633a815cc724082c209dfbe85a495c83", 100, 16), LambertWHelper.w(a), new Apfloat(5, 1, 16).scale(-100)); a = new Apfloat("1000000", 100); assertEquals("1000000", new Apfloat("11.38335808614005262200015678158500428903377470601886512143238610626898610768018867797709315493717650"), LambertWHelper.w(a), new Apfloat("5e-98")); a = new Apfloat("1e1000000", 100); assertEquals("1e1000000", new Apfloat("2.302570443457404704952666749321722464564231438920240812279165776095559120686218647242692419819942329e6"), LambertWHelper.w(a), new Apfloat("5e-93")); a = ApfloatMath.exp(new Apfloat(-1, 200)).negate().precision(100).add(new Apfloat("1e-50", 100)); Apfloat w = LambertWHelper.w(a); assertEquals("-1/e + 1e-50 value", new Apfloat("-0.9999999999999999999999997668356018402875796636464119050387687556112724831557"), w, new Apfloat("1e-75")); assertEquals("-1/e + 1e-50 precision", 75, w.precision()); a = ApfloatMath.exp(new Apfloat(-1, 200)).negate().precision(100); w = LambertWHelper.w(a); assertEquals("-1/e value", new Apfloat(-1), w, new Apfloat("1e-50")); assertEquals("-1/e precision", 50, w.precision()); a = new Apfloat("-0.3"); w = LambertWHelper.w(a); assertEquals("-0.3 low precision value", new Apfloat(-1), w, new Apfloat("0.5")); assertEquals("-0.3 low precision precision", 1, w.precision()); String two = "0.8526055020137254913464724146953174668984533001514035087721073946525150656742630448965773783502494847334503972691804119834761668851953598826198984364998343940330324849743119327028383008883133161249045727544669202220292076639777316648311871183719040610274221013237163543451621208284315007250267190731048119566857455987975973474411544571619699938899354169616378479326962044241495398851839432070255805880"; for (int precision = 100; precision <= 400; precision++) { a = new Apfloat(2, precision); assertEquals("2 precision " + precision, new Apfloat(two.substring(0, 2 + precision)), LambertWHelper.w(a), new Apfloat("5e-" + precision)); } for (int radix = 2; radix <= 36; radix++) { String minusOnePerE = ApfloatMath.exp(new Apfloat(-1, 500, radix)).negate().toString(true); int precision = 400; a = new Apfloat(minusOnePerE.substring(0, 2 + precision), precision, radix); w = LambertWHelper.w(a); assertEquals("-1/e radix " + radix + " value", new Apfloat(-1, precision / 2, radix), w, new Apfloat(5 * radix, 1, radix).scale(-precision / 2)); assertEquals("-1/e radix " + radix + " precision", precision / 2.0, w.precision(), 1.0); } String minusOnePerE = ApfloatMath.exp(new Apfloat(-1, 500)).negate().toString(true); for (int precision = 100; precision <= 400; precision++) { a = new Apfloat(minusOnePerE.substring(0, 2 + precision), precision); w = LambertWHelper.w(a); assertEquals("-1/e radix precision " + precision + " value", new Apfloat(-1, precision / 2), w, new Apfloat(5).scale(1 - precision / 2)); assertEquals("-1/e radix precision " + precision + " precision", precision / 2.0, w.precision(), 1.0); } /* // Runs for half an hour or so... for (int radix = 2; radix <= 36; radix++) { String minusOnePerE = ApfloatMath.exp(new Apfloat(-1, 500, radix)).negate().toString(true); for (int precision = 100; precision <= 400; precision++) { a = new Apfloat(minusOnePerE.substring(0, 2 + precision), precision, radix); w = LambertWHelper.w(a); assertEquals("-1/e radix " + radix + " precision " + precision + " value", new Apfloat(-1, precision / 2, radix), w, new Apfloat(5 * radix, 1, radix).scale(-precision / 2)); assertEquals("-1/e radix " + radix + " precision " + precision + " precision", precision / 2.0 + 0.5, w.precision(), 1.0); } } */ try { LambertWHelper.w(new Apfloat("-0.4")); fail("Far beyond branch point accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } try { LambertWHelper.w(new Apfloat("-0.367879441171442321595523780")); fail("Beyond branch point accepted"); } catch (ArithmeticException ae) { // OK; result would be complex } try { LambertWHelper.w(new Apfloat(2)); fail("Infinite precision accepted"); } catch (InfiniteExpansionException iee) { // OK; result would have infinite digits } } public static void testComplex0() { Apcomplex a = new Apcomplex("0"); assertEquals("0", Apfloat.ZERO, LambertWHelper.w(a)); a = new Apfloat("0.1", 100); assertEquals("0.1", new Apfloat("0.09127652716086226429989572142317956865311922405147203264830839460717224625441755165020664592995606710"), LambertWHelper.w(a), new Apfloat("5e-101")); a = new Apcomplex("(1e-100,1e-100)").precision(50); assertEquals("(1e-100,1e-100)", new Apcomplex("(1e-100,1e-100)").precision(50), LambertWHelper.w(a), new Apfloat("5e-149")); a = new Apcomplex("(1e-10,1e-10)").precision(50); assertEquals("(1e-10,1e-10)", new Apcomplex("(9.99999999999999999970000000010666666664583333333333e-11,9.9999999980000000002999999999999999999791666666753e-11)"), LambertWHelper.w(a), new Apfloat("5e-60")); a = new Apcomplex("(0.01,0.01)").precision(50); assertEquals("(0.01,0.01)", new Apcomplex("(0.0099971045851194534814524027709866897371957494651958,0.0098029980012010341194102411514982873087094006939282)"), LambertWHelper.w(a), new Apfloat("5e-52")); a = new Apcomplex("(0.1,0.1)").precision(50); assertEquals("(0.1,0.1)", new Apcomplex("(0.097870452916895276985068259728479600256253771097645,0.082860601390283166169392801012174651981013542958101)"), LambertWHelper.w(a), new Apfloat("5e-51")); a = new Apcomplex("(0.1,-0.1)").precision(50); assertEquals("(0.1,-0.1)", new Apcomplex("(0.097870452916895276985068259728479600256253771097645,-0.082860601390283166169392801012174651981013542958101)"), LambertWHelper.w(a), new Apfloat("5e-51")); a = new Apcomplex("(-0.1,0.1)").precision(50); assertEquals("(-0.1,0.1)", new Apcomplex("(-0.09575356787640000111807153287925558057943622268787,0.12268954209524810694854593242675798178478977541188)"), LambertWHelper.w(a), new Apfloat("5e-50")); a = new Apcomplex("(-0.1,-0.1)").precision(50); assertEquals("(-0.1,-0.1)", new Apcomplex("(-0.09575356787640000111807153287925558057943622268787,-0.12268954209524810694854593242675798178478977541188)"), LambertWHelper.w(a), new Apfloat("5e-50")); a = new Apcomplex("(0.9,0.9)").precision(50); assertEquals("(0.9,0.9)", new Apcomplex("(0.61367490011103129037350636966615982396555265609392,0.31332676840151583505948676785521310456288766083836)"), LambertWHelper.w(a), new Apfloat("5e-50")); a = new Apcomplex("(0.9,-0.9)").precision(50); assertEquals("(0.9,-0.9)", new Apcomplex("(0.61367490011103129037350636966615982396555265609392,-0.31332676840151583505948676785521310456288766083836)"), LambertWHelper.w(a), new Apfloat("5e-50")); a = new Apcomplex("(-0.9,0.9)").precision(50); assertEquals("(-0.9,0.9)", new Apcomplex("(0.21798309457331980992831606988147432124834284905112,1.00001975213679071996724784845911235217908252496852)"), LambertWHelper.w(a), new Apfloat("5e-50")); a = new Apcomplex("(-0.9,-0.9)").precision(50); assertEquals("(-0.9,-0.9)", new Apcomplex("(0.21798309457331980992831606988147432124834284905112,-1.00001975213679071996724784845911235217908252496852)"), LambertWHelper.w(a), new Apfloat("5e-50")); Apfloat minusOnePerE = new Apfloat("-0.36787944117144232159552377016146086744581113103177"); a = new Apcomplex("(1e-1,1e-2)").precision(50).add(minusOnePerE).precision(50); assertEquals("-1/e + (1e-1,1e-2)", new Apcomplex("(-0.39856416144865505878487405032790278503831237022966,0.02477976526323124917823700098342674498925458678055)"), LambertWHelper.w(a), new Apfloat("5e-50")); a = new Apcomplex("(1e-2,1e-2)").precision(50).add(minusOnePerE).precision(50); Apcomplex w = LambertWHelper.w(a); assertEquals("-1/e + (1e-2,1e-2) value", new Apcomplex("(-0.76072254901895636327164466506061887160499199636868,0.09058702846060393422375172650148570490563684917247)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-2,1e-2) precision", 49, w.precision()); a = new Apcomplex("(1e-3,1e-3)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (1e-3,1e-3) value", new Apcomplex("(-0.92076351549145164412509774220456376946214404250169,0.03183363220504445084857857851911777030681297024975)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-3,1e-3) precision", 49, w.precision()); a = new Apcomplex("(1e-4,1e-4)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (1e-4,1e-4) value", new Apcomplex("(-0.97456257064644008106039222921174885372729080458095,0.01043281923771948088092118424656929963710261496991)"), w, new Apfloat("5e-48")); assertEquals("-1/e + (1e-4,1e-4) precision", 48, w.precision()); a = new Apcomplex("(1e-5,1e-5)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (1e-5,1e-5) value", new Apcomplex("(-0.99191714865667190156669839954650235929288803603429,0.00333748945952032916845539337622356972009389475345)"), w, new Apfloat("5e-47")); assertEquals("-1/e + (1e-5,1e-5) precision", 47, w.precision()); a = new Apcomplex("(1e-8,1e-8)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (1e-8,1e-8) value", new Apcomplex("(-0.99974384410054809266419794964421548387024632303884,0.00010609263457633916917686652477996175142983720356)"), w, new Apfloat("5e-46")); assertEquals("-1/e + (1e-8,1e-8) precision", 46, w.precision()); a = new Apcomplex("(1e-16,1e-16)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (1e-16,1e-16) value", new Apcomplex("(-0.99999997438259817278287711182013622236756853118502,1.061107516343913271268043854017293402382483e-8)"), w, new Apfloat("5e-42")); assertEquals("-1/e + (1e-16,1e-16) precision", 42, w.precision()); a = new Apcomplex("(1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (1e-25,1e-25) value", new Apcomplex("(-0.99999999999918990661917188670455841174547849228700,3.3555166512757099178982471977490658151e-13)"), w, new Apfloat("5e-37")); assertEquals("-1/e + (1e-25,1e-25) precision", 37, w.precision()); a = new Apcomplex("(1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (1e-25,-1e-25)", new Apcomplex("(-0.99999999999918990661917188670455841174547849228700,-3.3555166512757099178982471977490658151e-13)"), w, new Apfloat("5e-37")); assertEquals("-1/e + (1e-25,-1e-25) precision", 37, w.precision()); a = new Apcomplex("(-1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (-1e-25,1e-25)", new Apcomplex("(-0.99999999999966444833487206657063304759783841878650,8.1009338082811329544158817569195577427e-13)"), w, new Apfloat("5e-37")); assertEquals("-1/e + (-1e-25,1e-25) precision", 37, w.precision()); a = new Apcomplex("(-1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (-1e-25,-1e-25)", new Apcomplex("(-0.99999999999966444833487206657063304759783841878650,-8.1009338082811329544158817569195577427e-13)"), w, new Apfloat("5e-37")); assertEquals("-1/e + (-1e-25,-1e-25) precision", 37, w.precision()); a = new Apcomplex("(0,1e-50)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a); assertEquals("-1/e + (0,1e-50)", new Apfloat("-1", 25), w, new Apfloat("5e-25")); assertEquals("-1/e + (0,1e-50) precision", 25, w.precision()); a = new Apcomplex("(-0.3,0.01)"); w = LambertWHelper.w(a); assertEquals("(-0.3,0.01) low precision value", new Apfloat(-1), w, new Apfloat("0.5")); assertEquals("(-0.3,0.01) low precision precision", 1, w.precision()); Apcomplex one = new Apcomplex("(0.6569660692304364058739351896150295119261810504985686094708810348849230553332090089811209990930923361884822337635046832506679161073935215432141999633668086783842052290733792803001199461391811969507519731175665294093942297272688866492133887278935030771348369162776716469274104390721707403107629322610256867265039997015298781807300548738748048553243945570919106773762856665717128930867337457753104606262,0.3254503394134150299892819513886224030106515829224425965100201871391242964163981983384434529333246378839071010829232817221003148680000586621992702293807852649794166119757415274667292782447037751105434386197607160329394263166712361134026294024524617643743202183812262212671628767427209694220240411422491183527487987228384662597891505579819415701334004762447837029591767086368225252212869238674050125163)"); for (int precision = 100; precision <= 400; precision++) { a = new Apcomplex(new Apfloat(1, precision), new Apfloat(1, precision)); assertEquals("1 + I precision " + precision, one.precision(precision), LambertWHelper.w(a), new Apfloat(5).scale(-precision)); } a = new Apcomplex("(2,1000000)").precision(50); assertEquals("(2,1000000)", new Apcomplex("(11.3760067875170608075520076107048712025774238213364,1.4444930636028915094393063196068810276369117644198)"), LambertWHelper.w(a), new Apfloat("5e-48")); a = new Apcomplex("(2,-1000000)").precision(50); assertEquals("(2,-1000000)", new Apcomplex("(11.3760067875170608075520076107048712025774238213364,-1.4444930636028915094393063196068810276369117644198)"), LambertWHelper.w(a), new Apfloat("5e-48")); a = new Apcomplex("(0,1000000)").precision(50); assertEquals("(0,1000000)", new Apcomplex("(11.3760067689068545924515956427133996741988651343661,1.4444949041717766545754105178986714424877495553053)"), LambertWHelper.w(a), new Apfloat("5e-48")); a = new Apcomplex("(0,-1000000)").precision(50); assertEquals("(0,-1000000)", new Apcomplex("(11.3760067689068545924515956427133996741988651343661,-1.4444949041717766545754105178986714424877495553053)"), LambertWHelper.w(a), new Apfloat("5e-48")); a = new Apcomplex("(-2,1000000)").precision(50); assertEquals("(-2,1000000)", new Apcomplex("(11.3760067503003063865838678439354530886497673603144,1.4444967447407042437063363618062470846843727797294)"), LambertWHelper.w(a), new Apfloat("5e-48")); a = new Apcomplex("(-2,-1000000)").precision(50); assertEquals("(-2,-1000000)", new Apcomplex("(11.3760067503003063865838678439354530886497673603144,-1.4444967447407042437063363618062470846843727797294)"), LambertWHelper.w(a), new Apfloat("5e-48")); a = new Apcomplex("(2,1e1000000)").precision(50); assertEquals("(2,1e1000000)", new Apcomplex("(2.3025704434574047047199737372509488036925000475234e6,1.5707956446026757185680399419191874646943170)"), LambertWHelper.w(a), new Apfloat("5e-43")); a = new Apcomplex("(2,-1e1000000)").precision(50); assertEquals("(2,-1e1000000)", new Apcomplex("(2.3025704434574047047199737372509488036925000475234e6,-1.5707956446026757185680399419191874646943170)"), LambertWHelper.w(a), new Apfloat("5e-43")); a = new Apcomplex("(0,1e1000000)").precision(50); assertEquals("(0,1e1000000)", new Apcomplex("(2.3025704434574047047199737372509488036925000475234e6,1.5707956446026757185680399419191874646943170)"), LambertWHelper.w(a), new Apfloat("5e-43")); a = new Apcomplex("(0,-1e1000000)").precision(50); assertEquals("(0,-1e1000000)", new Apcomplex("(2.3025704434574047047199737372509488036925000475234e6,-1.5707956446026757185680399419191874646943170)"), LambertWHelper.w(a), new Apfloat("5e-43")); a = new Apcomplex("(-2,1e1000000)").precision(50); assertEquals("(-2,1e1000000)", new Apcomplex("(2.3025704434574047047199737372509488036925000475234e6,1.5707956446026757185680399419191874646943170)"), LambertWHelper.w(a), new Apfloat("5e-43")); a = new Apcomplex("(-2,-1e1000000)").precision(50); assertEquals("(-2,-1e1000000)", new Apcomplex("(2.3025704434574047047199737372509488036925000475234e6,-1.5707956446026757185680399419191874646943170)"), LambertWHelper.w(a), new Apfloat("5e-43")); // Test for issue #10 a = new Apcomplex(new Apfloat(1.0), new Apfloat(-6.123233995736766e-17)); assertEquals("(1.0, -6.123233995736766e-17)", new Apcomplex("(0.5671432904097839, 0)"), LambertWHelper.w(a), new Apfloat("5e-16")); try { LambertWHelper.w(new Apcomplex(new Apfloat(2))); fail("Infinite precision accepted, real input"); } catch (InfiniteExpansionException iee) { // OK; result would have infinite digits } try { LambertWHelper.w(new Apcomplex(Apfloat.ZERO, new Apfloat(2))); fail("Infinite precision accepted, pure imaginary input"); } catch (InfiniteExpansionException iee) { // OK; result would have infinite digits } try { LambertWHelper.w(new Apcomplex(new Apfloat(2), new Apfloat(2))); fail("Infinite precision accepted, complex input"); } catch (InfiniteExpansionException iee) { // OK; result would have infinite digits } } public static void testComplexMinus1() { Apcomplex a = new Apfloat("-0.9", 100); assertEquals("-0.9", new Apcomplex("(-0.391432526121527750133034526147075943687827652712403323727116341052850551878987815079192989219382464,-1.272337572189570832430671752662551965493618371061232468771183304041782647776233562678062247476551034)"), LambertWHelper.w(a, -1), new Apfloat("5e-99")); a = new Apfloat("-0.1", 100); assertEquals("-0.1", new Apcomplex("-3.577152063957297218409391963511994880401796257793075923683527755791687236350575462861463655620846808"), LambertWHelper.w(a, -1), new Apfloat("5e-99")); a = new Apfloat("0.1", 100); assertEquals("0.1", new Apcomplex("(-4.02809648961011506264076041156402069873813347744141842416512930094612491698102377715320004508143354,-3.91242454869037428736013966471897475301250989497551827987402128965086307260195851567480077547937895)"), LambertWHelper.w(a, -1), new Apfloat("5e-99")); a = new Apfloat("0.9", 100); assertEquals("0.9", new Apcomplex("(-1.642470593279425020495276790198233535547049490665863488077316751279119834648747227774223895906912197,-4.351470475183312597711213055387012655711778525544444292119730537944815740672766029381862336231076436)"), LambertWHelper.w(a, -1), new Apfloat("5e-99")); a = new Apfloat("1", 100); assertEquals("1", new Apcomplex("(-1.533913319793574507919741082072733779785298610650766671733076005689449081100439244990610565534637096,-4.375185153061898385470906564852584291623823114677011864961044491803721563089347281759881823990959514)"), LambertWHelper.w(a, -1), new Apfloat("5e-99")); a = new Apfloat("2", 100); assertEquals("2", new Apcomplex("(-0.834310366631110014694725298171332139697179984494606985270644699985232754988730730357308978327940795,-4.530265998555008292131366279840451269080850198446391800466755572147815249787522323401907849111228103)"), LambertWHelper.w(a, -1), new Apfloat("5e-99")); a = new Apfloat("1000000", 100); assertEquals("1000000", new Apcomplex("(11.2752468562544339947180593529396553368595844926367045416137821549829067032062579694569561623234427342,-5.8075536510615827049173421518236546415873061942318932562300202046160560302747533665111940363888637664)"), LambertWHelper.w(a, -1), new Apfloat("5e-98")); a = new Apfloat("1e1000000", 100); assertEquals("1e1000000", new Apcomplex("(2.3025704434574047012295785562023389265357833825088593826397356104077744144457e6,-6.2831825784107028806218101388997157457028155078601957175368061400651450)"), LambertWHelper.w(a, -1), new Apfloat("5e-93")); a = new Apcomplex("(0.1,0.1)").precision(50); assertEquals("(0.1,0.1)", new Apcomplex("(-3.494370237224259073810794317924915029229909917936,-3.078388134528402866198196276013121902626535540677)"), LambertWHelper.w(a, -1), new Apfloat("5e-49")); a = new Apcomplex("(0.1,-0.1)").precision(50); assertEquals("(0.1,-0.1)", new Apcomplex("(-3.76940931372708814708271270800229359221355274363303,-4.83567134279640724016070688927989061085551400221897)"), LambertWHelper.w(a, -1), new Apfloat("5e-49")); a = new Apcomplex("(-0.1,0.1)").precision(50); assertEquals("(-0.1,0.1)", new Apcomplex("(-3.1689801292043678933642898831595709207335040405717,-1.1271168412956324398669025214666584531292112870714)"), LambertWHelper.w(a, -1), new Apfloat("5e-49")); a = new Apcomplex("(-0.1,-0.1)").precision(50); assertEquals("(-0.1,-0.1)", new Apcomplex("(-3.98985219695476256961953773435712367855538271559129,-6.51938865759154711525687235769823729506874694669240)"), LambertWHelper.w(a, -1), new Apfloat("5e-49")); a = new Apcomplex("(0.9,0.9)").precision(50); assertEquals("(0.9,0.9)", new Apcomplex("(-1.0926454500596423319036442434651916858606625525617,-3.6349920188858778056033971806870738270264155979072)"), LambertWHelper.w(a, -1), new Apfloat("5e-49")); a = new Apcomplex("(0.9,-0.9)").precision(50); assertEquals("(0.9,-0.9)", new Apcomplex("(-1.44972299161521104839286677766248538197930381108885,-5.22724706111442259544746566443002584026268188667821)"), LambertWHelper.w(a, -1), new Apfloat("5e-49")); a = new Apcomplex("(-0.9,0.9)").precision(50); assertEquals("(-0.9,0.9)", new Apcomplex("(-0.5355045584526520713025783875171692559639125322935,-2.1073485797364305882343695573825528332701956975255)"), LambertWHelper.w(a, -1), new Apfloat("5e-49")); a = new Apcomplex("(-0.9,-0.9)").precision(50); assertEquals("(-0.9,-0.9)", new Apcomplex("(-1.70954106162722618992015552843949798975878623087174,-6.82308486245240807403229525936443072239343329432382)"), LambertWHelper.w(a, -1), new Apfloat("5e-49")); Apfloat minusOnePerE = new Apfloat("-0.36787944117144232159552377016146086744581113103177"); a = new Apcomplex("(1e-1,1e-2)").precision(50).add(minusOnePerE).precision(50); assertEquals("-1/e + (1e-1,1e-2)", new Apcomplex("(-2.0205678829547190357896012430738825194504249931872,-0.0738416343062390264115221514178280173059856118129)"), LambertWHelper.w(a, -1), new Apfloat("5e-49")); a = new Apcomplex("(1e-2,1e-2)").precision(50).add(minusOnePerE).precision(50); Apcomplex w = LambertWHelper.w(a, -1); assertEquals("-1/e + (1e-2,1e-2) value", new Apcomplex("(-1.2755038208041206244353602468815721885958795761298,-0.1277888928494640657435110228230078875932085308564)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-2,1e-2) precision", 49, w.precision()); a = new Apcomplex("(1e-2,-1e-2)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (1e-2,-1e-2) value", new Apcomplex("(-3.11349050891483652161146165469929706550158668484065,-7.42919350583428899857090083748667060072764392328836)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-2,-1e-2) precision", 50, w.precision()); a = new Apcomplex("(1e-3,1e-3)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (1e-3,1e-3) value", new Apcomplex("(-1.08286084351113162002293325126217133344405890773,-0.03546743888232764678696099640150275124724728981)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-3,1e-3) precision", 49, w.precision()); a = new Apcomplex("(1e-4,1e-4)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (1e-4,1e-4) value", new Apcomplex("(-1.0257998669139797269627934713927798727163466425,-0.0107953509735967697958752446518968266762032938)"), w, new Apfloat("5e-48")); assertEquals("-1/e + (1e-4,1e-4) precision", 48, w.precision()); a = new Apcomplex("(1e-5,1e-5)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (1e-5,1e-5) value", new Apcomplex("(-1.008119095101024183688608313618380516549321428681,-0.003373734158670298533292555437275306346525720479)"), w, new Apfloat("5e-47")); assertEquals("-1/e + (1e-5,1e-5) precision", 47, w.precision()); a = new Apcomplex("(1e-8,1e-8)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (1e-8,1e-8) value", new Apcomplex("(-1.0002561921432096201230551538165443521981490847,-0.0001061288783349933769441253168206744317626089)"), w, new Apfloat("5e-46")); assertEquals("-1/e + (1e-8,1e-8) precision", 46, w.precision()); a = new Apcomplex("(1e-16,1e-16)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (1e-16,1e-16) value", new Apcomplex("(-1.000000025617402189654700016052561825670761,-1.0611075525876709840553230730259339e-8)"), w, new Apfloat("5e-42")); assertEquals("-1/e + (1e-16,1e-16) precision", 42, w.precision()); a = new Apcomplex("(1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (1e-25,1e-25) value", new Apcomplex("(-1.0000000000008100933808284757330187161,-3.355516651279334293669526e-13)"), w, new Apfloat("5e-37")); assertEquals("-1/e + (1e-25,1e-25) precision", 37, w.precision()); a = new Apcomplex("(1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (1e-25,-1e-25)", new Apcomplex("(-3.08884301561304385595708696427755538303311335575167,-7.46148928565425455690611629711746943754305678567092)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-25,-1e-25) precision", 50, w.precision()); a = new Apcomplex("(-1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (-1e-25,1e-25)", new Apcomplex("(-1.0000000000003355516651275709917898245,-8.100933808284757330187160e-13)"), w, new Apfloat("5e-37")); assertEquals("-1/e + (-1e-25,1e-25) precision", 37, w.precision()); a = new Apcomplex("(-1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -1); assertEquals("-1/e + (-1e-25,-1e-25)", new Apcomplex("(-3.08884301561304385595708640170600160357965553350553,-7.46148928565425455690611636468380745202167537848733)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (-1e-25,-1e-25) precision", 50, w.precision()); a = new Apcomplex("-0.3678794411714423215955237701615").precision(400); w = LambertWHelper.w(a, -1); assertEquals("-0.3678794411714423215955237701615 value", new Apcomplex("(-0.9999999999999999999999999999999290844593648057274890111324409909772743495610372098324992841989871764928737740609004793534682540053443051399418812510079552126308029943163910621009255881821995159178880095852554333370463395603248151517019196520469670849976233621765675059713043410110477719736952492808165979901145821944546091377396631038507940797034413787153721563900362732037292590866126803411791060595,-4.61244644311002073593990950383005301185756786088441915947765419354022153345185286269640964675349907862653578915254654696678064789269795860983141052266643067979800363293013989928411810795941375083587751904376634023242645843420325518066327564804765851332735851986261489467922733871343154656608287717411712113540450424299636698379699050316619168405756676557611416361034660e-16)"), w, new Apfloat("5e-383")); assertEquals("-0.3678794411714423215955237701615 precision", 384, w.precision()); a = new Apcomplex("-0.36787944117144232159552377016146").precision(185); w = LambertWHelper.w(a, -1); assertEquals("-0.36787944117144232159552377016146 value", new Apcomplex("(-1.000000000000000068672588207674257657443699681618940429313824645972320261044650790536548311713641687234758741030702101798690781938624824161254982003710688119992988154843)"), w, new Apfloat("5e-167")); assertEquals("-0.36787944117144232159552377016146 precision", 168, w.precision()); try { LambertWHelper.w(new Apfloat(0), -1); fail("Zero accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } public static void testComplex1() { Apcomplex a = new Apfloat("-0.9", 100); assertEquals("-0.9", new Apcomplex("(-2.1696402027752207874871174308091539919889333294692997574577771392574830573295888027357084819789128019,7.5750296170109843098532982876582625035605375877146409519391718892752281434037966807811301735860372005)"), LambertWHelper.w(a, 1), new Apfloat("5e-99")); a = new Apfloat("-0.1", 100); assertEquals("-0.1", new Apcomplex("(-4.4490981787008898640867157232460451274645883248560292243219377121537983732391815602785462059256437129,7.3070607892176086310144168455358639797400912986829032801724659855526522573777510811321213152295822684)"), LambertWHelper.w(a, 1), new Apfloat("5e-99")); a = new Apfloat("0.1", 100); assertEquals("0.1", new Apcomplex("(-4.02809648961011506264076041156402069873813347744141842416512930094612491698102377715320004508143354,3.91242454869037428736013966471897475301250989497551827987402128965086307260195851567480077547937895)"), LambertWHelper.w(a, 1), new Apfloat("5e-99")); a = new Apfloat("0.9", 100); assertEquals("0.9", new Apcomplex("(-1.642470593279425020495276790198233535547049490665863488077316751279119834648747227774223895906912197,4.351470475183312597711213055387012655711778525544444292119730537944815740672766029381862336231076436)"), LambertWHelper.w(a, 1), new Apfloat("5e-99")); a = new Apfloat("1", 100); assertEquals("1", new Apcomplex("(-1.533913319793574507919741082072733779785298610650766671733076005689449081100439244990610565534637096,4.375185153061898385470906564852584291623823114677011864961044491803721563089347281759881823990959514)"), LambertWHelper.w(a, 1), new Apfloat("5e-99")); a = new Apfloat("2", 100); assertEquals("2", new Apcomplex("(-0.834310366631110014694725298171332139697179984494606985270644699985232754988730730357308978327940795,4.530265998555008292131366279840451269080850198446391800466755572147815249787522323401907849111228103)"), LambertWHelper.w(a, 1), new Apfloat("5e-99")); a = new Apfloat("1000000", 100); assertEquals("1000000", new Apcomplex("(11.2752468562544339947180593529396553368595844926367045416137821549829067032062579694569561623234427342,5.8075536510615827049173421518236546415873061942318932562300202046160560302747533665111940363888637664)"), LambertWHelper.w(a, 1), new Apfloat("5e-98")); a = new Apfloat("1e1000000", 100); assertEquals("1e1000000", new Apcomplex("(2.3025704434574047012295785562023389265357833825088593826397356104077744144457e6,6.2831825784107028806218101388997157457028155078601957175368061400651450)"), LambertWHelper.w(a, 1), new Apfloat("5e-93")); a = new Apcomplex("(0.1,0.1)").precision(50); assertEquals("(0.1,0.1)", new Apcomplex("(-3.76940931372708814708271270800229359221355274363303,4.83567134279640724016070688927989061085551400221897)"), LambertWHelper.w(a, 1), new Apfloat("5e-49")); a = new Apcomplex("(0.1,-0.1)").precision(50); assertEquals("(0.1,-0.1)", new Apcomplex("(-3.494370237224259073810794317924915029229909917936,3.078388134528402866198196276013121902626535540677)"), LambertWHelper.w(a, 1), new Apfloat("5e-49")); a = new Apcomplex("(-0.1,0.1)").precision(50); assertEquals("(-0.1,0.1)", new Apcomplex("(-3.98985219695476256961953773435712367855538271559129,6.51938865759154711525687235769823729506874694669240)"), LambertWHelper.w(a, 1), new Apfloat("5e-49")); a = new Apcomplex("(-0.1,-0.1)").precision(50); assertEquals("(-0.1,-0.1)", new Apcomplex("(-3.1689801292043678933642898831595709207335040405717,1.1271168412956324398669025214666584531292112870714)"), LambertWHelper.w(a, 1), new Apfloat("5e-49")); a = new Apcomplex("(0.9,0.9)").precision(50); assertEquals("(0.9,0.9)", new Apcomplex("(-1.44972299161521104839286677766248538197930381108885,5.22724706111442259544746566443002584026268188667821)"), LambertWHelper.w(a, 1), new Apfloat("5e-49")); a = new Apcomplex("(0.9,-0.9)").precision(50); assertEquals("(0.9,-0.9)", new Apcomplex("(-1.0926454500596423319036442434651916858606625525617,3.6349920188858778056033971806870738270264155979072)"), LambertWHelper.w(a, 1), new Apfloat("5e-49")); a = new Apcomplex("(-0.9,0.9)").precision(50); assertEquals("(-0.9,0.9)", new Apcomplex("(-1.70954106162722618992015552843949798975878623087174,6.82308486245240807403229525936443072239343329432382)"), LambertWHelper.w(a, 1), new Apfloat("5e-49")); a = new Apcomplex("(-0.9,-0.9)").precision(50); assertEquals("(-0.9,-0.9)", new Apcomplex("(-0.5355045584526520713025783875171692559639125322935,2.1073485797364305882343695573825528332701956975255)"), LambertWHelper.w(a, 1), new Apfloat("5e-49")); Apfloat minusOnePerE = new Apfloat("-0.36787944117144232159552377016146086744581113103177"); a = new Apcomplex("(1e-1,1e-2)").precision(50).add(minusOnePerE).precision(50); assertEquals("-1/e + (1e-1,1e-2)", new Apcomplex("(-3.41260053537264765727988995284861910196950965532302,7.38373371787849281512592031397374471437222278075429)"), LambertWHelper.w(a, 1), new Apfloat("5e-49")); a = new Apcomplex("(1e-2,1e-2)").precision(50).add(minusOnePerE).precision(50); Apcomplex w = LambertWHelper.w(a, 1); assertEquals("-1/e + (1e-2,1e-2) value", new Apcomplex("(-3.11349050891483652161146165469929706550158668484065,7.42919350583428899857090083748667060072764392328836)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-2,1e-2) precision", 50, w.precision()); a = new Apcomplex("(1e-2,-1e-2)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (1e-2,-1e-2) value", new Apcomplex("(-1.2755038208041206244353602468815721885958795761298,0.1277888928494640657435110228230078875932085308564)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-2,-1e-2) precision", 49, w.precision()); a = new Apcomplex("(1e-3,-1e-3)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (1e-3,-1e-3) value", new Apcomplex("(-1.08286084351113162002293325126217133344405890773,0.03546743888232764678696099640150275124724728981)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-3,-1e-3) precision", 49, w.precision()); a = new Apcomplex("(1e-4,-1e-4)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (1e-4,-1e-4) value", new Apcomplex("(-1.0257998669139797269627934713927798727163466425,0.0107953509735967697958752446518968266762032938)"), w, new Apfloat("5e-48")); assertEquals("-1/e + (1e-4,-1e-4) precision", 48, w.precision()); a = new Apcomplex("(1e-5,-1e-5)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (1e-5,-1e-5) value", new Apcomplex("(-1.008119095101024183688608313618380516549321428681,0.003373734158670298533292555437275306346525720479)"), w, new Apfloat("5e-47")); assertEquals("-1/e + (1e-5,-1e-5) precision", 47, w.precision()); a = new Apcomplex("(1e-8,-1e-8)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (1e-8,-1e-8) value", new Apcomplex("(-1.0002561921432096201230551538165443521981490847,0.0001061288783349933769441253168206744317626089)"), w, new Apfloat("5e-46")); assertEquals("-1/e + (1e-8,-1e-8) precision", 46, w.precision()); a = new Apcomplex("(1e-16,-1e-16)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (1e-16,-1e-16) value", new Apcomplex("(-1.000000025617402189654700016052561825670761,1.0611075525876709840553230730259339e-8)"), w, new Apfloat("5e-42")); assertEquals("-1/e + (1e-16,-1e-16) precision", 42, w.precision()); a = new Apcomplex("(1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (1e-25,1e-25)", new Apcomplex("(-3.08884301561304385595708696427755538303311335575167,7.46148928565425455690611629711746943754305678567092)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-25,1e-25) precision", 50, w.precision()); a = new Apcomplex("(1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (1e-25,-1e-25) value", new Apcomplex("(-1.0000000000008100933808284757330187161,3.355516651279334293669526e-13)"), w, new Apfloat("5e-37")); assertEquals("-1/e + (1e-25,-1e-25) precision", 37, w.precision()); a = new Apcomplex("(-1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (-1e-25,1e-25)", new Apcomplex("(-3.08884301561304385595708640170600160357965553350553,7.46148928565425455690611636468380745202167537848733)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (-1e-25,1e-25) precision", 50, w.precision()); a = new Apcomplex("(-1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 1); assertEquals("-1/e + (-1e-25,-1e-25)", new Apcomplex("(-1.0000000000003355516651275709917898245,8.100933808284757330187160e-13)"), w, new Apfloat("5e-37")); assertEquals("-1/e + (-1e-25,-1e-25) precision", 37, w.precision()); try { LambertWHelper.w(new Apfloat(0), 1); fail("Zero accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } public static void testComplexMinus2() { Apcomplex a = new Apfloat("-0.9", 100); assertEquals("-0.9", new Apcomplex("(-2.1696402027752207874871174308091539919889333294692997574577771392574830573295888027357084819789128019,-7.5750296170109843098532982876582625035605375877146409519391718892752281434037966807811301735860372005)"), LambertWHelper.w(a, -2), new Apfloat("5e-99")); a = new Apfloat("-0.1", 100); assertEquals("-0.1", new Apcomplex("(-4.4490981787008898640867157232460451274645883248560292243219377121537983732391815602785462059256437129,-7.3070607892176086310144168455358639797400912986829032801724659855526522573777510811321213152295822684)"), LambertWHelper.w(a, -2), new Apfloat("5e-99")); a = new Apfloat("0.1", 100); assertEquals("0.1", new Apcomplex("(-4.752924560539896501162753801930674336761884015575296912634002580497382636717867505212605,-10.573111784534943705555301345953051927597028025159592622540268741980634029224381240134255)"), LambertWHelper.w(a, -2), new Apfloat("5e-99")); a = new Apfloat("0.9", 100); assertEquals("0.9", new Apcomplex("(-2.5082431083766972979390938498275007121312900409911210568146700207260115202611491149295270,-10.7666934268043841675736179633389172700542145561797254359291099360428020322733883326938578)"), LambertWHelper.w(a, -2), new Apfloat("5e-99")); a = new Apfloat("1", 100); assertEquals("1", new Apcomplex("(-2.40158510486800288417413977468407647920574720363862201506340595568500161119813263131511672,-10.77629951611507089849710334639114764356272881108572638210088260662431487130270095507071949)"), LambertWHelper.w(a, -2), new Apfloat("5e-99")); a = new Apfloat("2", 100); assertEquals("2", new Apcomplex("(-1.70225900555760418421169531849422743741100852687484668594853268958582652624730469228795175,-10.83980867635929817161430296528775785075955528184433941773103962590404738511147335839990100)"), LambertWHelper.w(a, -2), new Apfloat("5e-99")); a = new Apfloat("1000000", 100); assertEquals("1000000", new Apcomplex("(11.0354852870884541556114342850176398521815497733759312875404969277650410480510310486335176253571236420,-11.7496396980728366336315836335846570571748464337355079073702587880867608468150554007964025611923176174)"), LambertWHelper.w(a, -2), new Apfloat("5e-98")); a = new Apfloat("1e1000000", 100); assertEquals("1e1000000", new Apcomplex("(2.3025704434574046900603139770105247722136418061583123550509005233524648309767e6,-12.5663651568214058018813826529115311494596561375242805601367375513007391)"), LambertWHelper.w(a, -2), new Apfloat("5e-93")); a = new Apcomplex("(0.1,0.1)").precision(50); assertEquals("(0.1,0.1)", new Apcomplex("(-4.32694598298195301567101913174024904383609408294303,-9.79417240669519814321681889366099503452634756326525)"), LambertWHelper.w(a, -2), new Apfloat("5e-49")); a = new Apcomplex("(0.1,-0.1)").precision(50); assertEquals("(0.1,-0.1)", new Apcomplex("(-4.46150099885356534168179199389468758681480568726818,-11.40818006630707645202745568528364138775149089044037)"), LambertWHelper.w(a, -2), new Apfloat("5e-48")); a = new Apcomplex("(-0.1,0.1)").precision(50); assertEquals("(-0.1,0.1)", new Apcomplex("(-4.17206000198761389916980339367569553340272515041870,-8.16709991236722495654333433874576651246049617173758)"), LambertWHelper.w(a, -2), new Apfloat("5e-49")); a = new Apcomplex("(-0.1,-0.1)").precision(50); assertEquals("(-0.1,-0.1)", new Apcomplex("(-4.58038275692009635302775100106541142184228107393803,-13.01333459901300720639047799260012653428906553185216)"), LambertWHelper.w(a, -2), new Apfloat("5e-48")); a = new Apcomplex("(0.9,0.9)").precision(50); assertEquals("(0.9,0.9)", new Apcomplex("(-2.08308039125534457091462580249672703675832197614088,-10.00490281337842995053643413552988782638091117564826)"), LambertWHelper.w(a, -2), new Apfloat("5e-48")); a = new Apcomplex("(0.9,-0.9)").precision(50); assertEquals("(0.9,-0.9)", new Apcomplex("(-2.22715505448192395274331336493646484435206146304835,-11.59114315011385962030468122170837190368462856991551)"), LambertWHelper.w(a, -2), new Apfloat("5e-48")); a = new Apcomplex("(-0.9,0.9)").precision(50); assertEquals("(-0.9,0.9)", new Apcomplex("(-1.91410930491369070543340051140645802624032344774990,-8.41574038133572741523579549611439943379759998796892)"), LambertWHelper.w(a, -2), new Apfloat("5e-49")); a = new Apcomplex("(-0.9,-0.9)").precision(50); assertEquals("(-0.9,-0.9)", new Apcomplex("(-2.35280842816729699806331011414977130420894944780259,-13.17505104043316522138211734518438096809787404617582)"), LambertWHelper.w(a, -2), new Apfloat("5e-48")); Apfloat minusOnePerE = new Apfloat("-0.36787944117144232159552377016146086744581113103177"); a = new Apcomplex("(1e-2,1e-2)").precision(50).add(minusOnePerE).precision(50); Apcomplex w = LambertWHelper.w(a, -2); assertEquals("-1/e + (1e-2,1e-2) value", new Apcomplex("(-3.12042317846178133420655257832849242941900358279720,-7.48703153555803272188014570620298820375269188816625)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-2,1e-2) precision", 51, w.precision()); a = new Apcomplex("(1e-2,-1e-2)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -2); assertEquals("-1/e + (1e-2,-1e-2) value", new Apcomplex("(-3.68965926447077142781441532734581320117222723454881,-13.84885659062717730687065656572845992814464654071224)"), w, new Apfloat("5e-48")); assertEquals("-1/e + (1e-2,-1e-2) precision", 51, w.precision()); a = new Apcomplex("(1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -2); assertEquals("-1/e + (1e-25,1e-25)", new Apcomplex("(-3.08884301561304385595708703184389339751173194856795,-7.46148928565425455690611685968902321699651460791724)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-25,1e-25) precision", 51, w.precision()); a = new Apcomplex("(1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -2); assertEquals("-1/e + (1e-25,-1e-25) value", new Apcomplex("(-3.66406814242907101707075129536537687200837112614960,-13.87905600274680942535355712749209564794866828664858)"), w, new Apfloat("5e-48")); assertEquals("-1/e + (1e-25,-1e-25) precision", 51, w.precision()); a = new Apcomplex("(-1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -2); assertEquals("-1/e + (-1e-25,1e-25)", new Apcomplex("(-3.08884301561304385595708646927233961805827412632177,-7.46148928565425455690611692725536123147513320073334)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (-1e-25,1e-25) precision", 51, w.precision()); a = new Apcomplex("(-1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, -2); assertEquals("-1/e + (-1e-25,-1e-25)", new Apcomplex("(-3.66406814242907101707075074445736863315369647333033,-13.87905600274680942535355716527114169388794146277880)"), w, new Apfloat("5e-48")); assertEquals("-1/e + (-1e-25,-1e-25) precision", 51, w.precision()); try { LambertWHelper.w(new Apfloat(0), -2); fail("Zero accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } public static void testComplex2() { Apcomplex a = new Apfloat("-0.9", 100); assertEquals("-0.9", new Apcomplex("(-2.75946327141826742489413365006537853029870165199682582964615371041076964501146169979262105021743979,13.94176464069150052152167624996073846234452900845388730939992976630026789069486464296816115244547952)"), LambertWHelper.w(a, 2), new Apfloat("5e-99")); a = new Apfloat("-0.1", 100); assertEquals("-0.1", new Apcomplex("(-4.9880136260605828005616558438145653171651930088796221871134876787550777308243035135248133243187902,13.7900985636568655239755915840066119002189639614688424337178890778888735747762802755938053596950001)"), LambertWHelper.w(a, 2), new Apfloat("5e-99")); a = new Apfloat("0.1", 100); assertEquals("0.1", new Apcomplex("(-4.752924560539896501162753801930674336761884015575296912634002580497382636717867505212605,10.573111784534943705555301345953051927597028025159592622540268741980634029224381240134255)"), LambertWHelper.w(a, 2), new Apfloat("5e-99")); a = new Apfloat("0.9", 100); assertEquals("0.9", new Apcomplex("(-2.5082431083766972979390938498275007121312900409911210568146700207260115202611491149295270,10.7666934268043841675736179633389172700542145561797254359291099360428020322733883326938578)"), LambertWHelper.w(a, 2), new Apfloat("5e-99")); a = new Apfloat("1", 100); assertEquals("1", new Apcomplex("(-2.40158510486800288417413977468407647920574720363862201506340595568500161119813263131511672,10.77629951611507089849710334639114764356272881108572638210088260662431487130270095507071949)"), LambertWHelper.w(a, 2), new Apfloat("5e-99")); a = new Apfloat("2", 100); assertEquals("2", new Apcomplex("(-1.70225900555760418421169531849422743741100852687484668594853268958582652624730469228795175,10.83980867635929817161430296528775785075955528184433941773103962590404738511147335839990100)"), LambertWHelper.w(a, 2), new Apfloat("5e-99")); a = new Apfloat("1000000", 100); assertEquals("1000000", new Apcomplex("(11.0354852870884541556114342850176398521815497733759312875404969277650410480510310486335176253571236420,11.7496396980728366336315836335846570571748464337355079073702587880867608468150554007964025611923176174)"), LambertWHelper.w(a, 2), new Apfloat("5e-98")); a = new Apfloat("1e1000000", 100); assertEquals("1e1000000", new Apcomplex("(2.3025704434574046900603139770105247722136418061583123550509005233524648309767e6,12.5663651568214058018813826529115311494596561375242805601367375513007391)"), LambertWHelper.w(a, 2), new Apfloat("5e-93")); a = new Apcomplex("(0.1,0.1)").precision(50); assertEquals("(0.1,0.1)", new Apcomplex("(-4.46150099885356534168179199389468758681480568726818,11.40818006630707645202745568528364138775149089044037)"), LambertWHelper.w(a, 2), new Apfloat("5e-48")); a = new Apcomplex("(0.1,-0.1)").precision(50); assertEquals("(0.1,-0.1)", new Apcomplex("(-4.32694598298195301567101913174024904383609408294303,9.79417240669519814321681889366099503452634756326525)"), LambertWHelper.w(a, 2), new Apfloat("5e-49")); a = new Apcomplex("(-0.1,0.1)").precision(50); assertEquals("(-0.1,0.1)", new Apcomplex("(-4.58038275692009635302775100106541142184228107393803,13.01333459901300720639047799260012653428906553185216)"), LambertWHelper.w(a, 2), new Apfloat("5e-48")); a = new Apcomplex("(-0.1,-0.1)").precision(50); assertEquals("(-0.1,-0.1)", new Apcomplex("(-4.17206000198761389916980339367569553340272515041870,8.16709991236722495654333433874576651246049617173758)"), LambertWHelper.w(a, 2), new Apfloat("5e-49")); a = new Apcomplex("(0.9,0.9)").precision(50); assertEquals("(0.9,0.9)", new Apcomplex("(-2.22715505448192395274331336493646484435206146304835,11.59114315011385962030468122170837190368462856991551)"), LambertWHelper.w(a, 2), new Apfloat("5e-48")); a = new Apcomplex("(0.9,-0.9)").precision(50); assertEquals("(0.9,-0.9)", new Apcomplex("(-2.08308039125534457091462580249672703675832197614088,10.00490281337842995053643413552988782638091117564826)"), LambertWHelper.w(a, 2), new Apfloat("5e-48")); a = new Apcomplex("(-0.9,0.9)").precision(50); assertEquals("(-0.9,0.9)", new Apcomplex("(-2.35280842816729699806331011414977130420894944780259,13.17505104043316522138211734518438096809787404617582)"), LambertWHelper.w(a, 2), new Apfloat("5e-48")); a = new Apcomplex("(-0.9,-0.9)").precision(50); assertEquals("(-0.9,-0.9)", new Apcomplex("(-1.91410930491369070543340051140645802624032344774990,8.41574038133572741523579549611439943379759998796892)"), LambertWHelper.w(a, 2), new Apfloat("5e-49")); Apfloat minusOnePerE = new Apfloat("-0.36787944117144232159552377016146086744581113103177"); a = new Apcomplex("(1e-2,1e-2)").precision(50).add(minusOnePerE).precision(50); Apcomplex w = LambertWHelper.w(a, 2); assertEquals("-1/e + (1e-2,1e-2) value", new Apcomplex("(-3.68965926447077142781441532734581320117222723454881,13.84885659062717730687065656572845992814464654071224)"), w, new Apfloat("5e-48")); assertEquals("-1/e + (1e-2,1e-2) precision", 51, w.precision()); a = new Apcomplex("(1e-2,-1e-2)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 2); assertEquals("-1/e + (1e-2,-1e-2) value", new Apcomplex("(-3.12042317846178133420655257832849242941900358279720,7.48703153555803272188014570620298820375269188816625)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-2,-1e-2) precision", 51, w.precision()); a = new Apcomplex("(1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 2); assertEquals("-1/e + (1e-25,1e-25) value", new Apcomplex("(-3.66406814242907101707075129536537687200837112614960,13.87905600274680942535355712749209564794866828664858)"), w, new Apfloat("5e-48")); assertEquals("-1/e + (1e-25,1e-25) precision", 51, w.precision()); a = new Apcomplex("(1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 2); assertEquals("-1/e + (1e-25,-1e-25)", new Apcomplex("(-3.08884301561304385595708703184389339751173194856795,7.46148928565425455690611685968902321699651460791724)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (1e-25,-1e-25) precision", 51, w.precision()); a = new Apcomplex("(-1e-25,1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 2); assertEquals("-1/e + (-1e-25,1e-25)", new Apcomplex("(-3.66406814242907101707075074445736863315369647333033,13.87905600274680942535355716527114169388794146277880)"), w, new Apfloat("5e-48")); assertEquals("-1/e + (-1e-25,1e-25) precision", 51, w.precision()); a = new Apcomplex("(-1e-25,-1e-25)").precision(50).add(minusOnePerE).precision(50); w = LambertWHelper.w(a, 2); assertEquals("-1/e + (-1e-25,-1e-25)", new Apcomplex("(-3.08884301561304385595708646927233961805827412632177,7.46148928565425455690611692725536123147513320073334)"), w, new Apfloat("5e-49")); assertEquals("-1/e + (-1e-25,-1e-25) precision", 51, w.precision()); try { LambertWHelper.w(new Apfloat(0), 2); fail("Zero accepted"); } catch (ArithmeticException ae) { // OK; result would be infinite } } public static void testComplexBigK() { Apcomplex a = new Apcomplex("(0.1,0.1)").precision(60); Apcomplex w = LambertWHelper.w(a, 7); assertEquals("(0.1,0.1) k=7 value", new Apcomplex("(-5.727481440633124530039091428658978161456806576373186053989185,43.064677733769856152109519838050639882060333900419297108268996)"), w, new Apfloat("5e-59")); assertEquals("(0.1,0.1) k=7 precision", 61, w.precision()); a = new Apcomplex("(-0.1,-0.1)").precision(40); w = LambertWHelper.w(a, 17); assertEquals("(-0.1,-0.1) k=17 value", new Apcomplex("(-6.5910722487103657564303352667701682922203,102.8231459290324957587950708059456713967620)"), w, new Apfloat("5e-39")); assertEquals("(-0.1,-0.1) k=17 precision", 42, w.precision()); a = new Apcomplex("(-0.9,0.1)").precision(70); w = LambertWHelper.w(a, 37); assertEquals("(-0.9,0.1) k=37 value", new Apcomplex("(-5.5544619326951672831439378170318286914007057845042983632997693607309607,233.9142542147682233318982170262440480826987266245944321123830964887996136)"), w, new Apfloat("5e-69")); assertEquals("(-0.9,0.1) k=37 precision", 72, w.precision()); a = new Apcomplex("(0.9,0.9)").precision(80); w = LambertWHelper.w(a, 330); assertEquals("(0.9,0.9) k=330 value", new Apcomplex("(-7.39538243061762074201129843802868979391130777923658009354747064410444890778712847,2072.66218516129995517643750165430389609331547118778642894683887552361804086525913277)"), w, new Apfloat("5e-79")); assertEquals("(0.9,0.9) k=330 precision", 83, w.precision()); a = new Apcomplex("(0.9,0.9)").precision(90); w = LambertWHelper.w(a, 330); assertEquals("(0.9,0.9) k=330 value", new Apcomplex("(-7.39538243061762074201129843802868979391130777923658009354747064410444890778712847,2072.66218516129995517643750165430389609331547118778642894683887552361804086525913277)"), w, new Apfloat("5e-89")); assertEquals("(0.9,0.9) k=330 precision", 93, w.precision()); a = new Apcomplex("(2,2)").precision(90); w = LambertWHelper.w(a, 1000000); assertEquals("(2,2) k=1000000 value", new Apcomplex("(-14.61366672853602840268817724838932227540464815235263968785440674,6.28318452177909724188970670954088541855494104163284957145366705105291e6)"), w, new Apfloat("5e-89")); assertEquals("(2,2) k=1000000 precision", 96, w.precision()); a = new Apcomplex("(1,1)").precision(40); w = LambertWHelper.w(a, 1000000000); assertEquals("(1,1) k=1000000000 value", new Apcomplex("(-22.214569312950783990694,6.283185306394188309992279941688e9)"), w, new Apfloat("5e-39")); assertEquals("(1,1) k=1000000000 precision", 49, w.precision()); a = new Apcomplex("(1,1)").precision(50); w = LambertWHelper.w(a, 1000000000000000000L); assertEquals("(1,1) k=1000000000000000000 value", new Apcomplex("(-42.937835150022195141050889596400702754759628494762,6.2831853071795864761398886031615574519449092431393702253372752910936e18)"), w, new Apfloat("5e-49")); assertEquals("(1,1) k=1000000000000000000 precision", 68, w.precision()); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/RootFinderTest.java000066400000000000000000000067021461767713300253570ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import junit.framework.TestSuite; import static org.apfloat.Apfloat.ONE; import static org.apfloat.Apfloat.ZERO; import static org.apfloat.ApfloatMath.airyAiPrime; import static org.apfloat.ApfloatMath.besselJ; import static org.apfloat.ApfloatMath.digamma; import static org.apfloat.ApfloatMath.exp; import static org.apfloat.ApfloatMath.gamma; /** * @version 1.14.0 * @author Mikko Tommila */ public class RootFinderTest extends ApfloatTestCase { public RootFinderTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RootFinderTest("testFindRoot")); return suite; } public static void testFindRoot() { Apfloat x = new Apfloat(2, 100); Apfloat a = RootFinder.findRoot(y -> exp(y), (y, f) -> f, x, new Apfloat(0.5), 100); assertEquals("log(2) precision", 100, a.precision()); assertEquals("log(2) value", new Apfloat("0.6931471805599453094172321214581765680755001343602552541206800094933936219696947156058633269964186875"), a, new Apfloat("5e-100")); a = RootFinder.findRoot(y -> gamma(y), (y, f) -> f.multiply(digamma(y)), x, new Apfloat(0.3), 100); assertEquals("inverseGamma(2) precision", 100, a.precision()); assertEquals("inverseGamma(2) value", new Apfloat("0.4428773964847274374520325165206056717103645380663664029912307198958524822841740804077009377298448221"), a, new Apfloat("5e-100")); a = RootFinder.findRoot(y -> besselJ(ZERO, y), (y, f) -> besselJ(ONE, y).negate(), ZERO, new Apfloat(2.4), 100); assertEquals("J_0 first zero precision", 100, a.precision()); assertEquals("J_0 first zero value", new Apfloat("2.404825557695772768621631879326454643124244909145967135706999090596765838677194029204436343760145255"), a, new Apfloat("5e-99")); a = RootFinder.findRoot(ApfloatMath::airyAi, (y, f) -> airyAiPrime(y), ZERO, new Apfloat(-4.0), 6); assertEquals("Ai second zero precision", 6, a.precision()); assertEquals("Ai second zero value", new Apfloat("-4.08795"), a, new Apfloat("5e-5")); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/RoundingHelperTest.java000066400000000000000000000102271461767713300262260ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.math.RoundingMode; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @since 1.7.0 * @version 1.11.0 * @author Mikko Tommila */ public class RoundingHelperTest extends TestCase { public RoundingHelperTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RoundingHelperTest("testRoundToPrecision")); suite.addTest(new RoundingHelperTest("testRoundToInteger")); suite.addTest(new RoundingHelperTest("testRoundToPlaces")); suite.addTest(new RoundingHelperTest("testRoundToMultiple")); suite.addTest(new RoundingHelperTest("testCompareToHalf")); return suite; } public static void testRoundToPrecision() { assertEquals("roundToPrecision", new Apfloat("1.0"), RoundingHelper.roundToPrecision(new Apfloat("1.1"), 1, RoundingMode.DOWN)); } public static void testRoundToInteger() { assertEquals("roundToInteger", new Apfloat(12346), RoundingHelper.roundToInteger(new Apfloat("12345.67"), RoundingMode.HALF_EVEN)); } public static void testRoundToPlaces() { assertEquals("roundToPlaces", new Apfloat("12345.6"), RoundingHelper.roundToPlaces(new Apfloat("12345.65"), 1, RoundingMode.HALF_EVEN)); } public static void testRoundToMultiple() { assertEquals("roundToMultiple float", new Apfloat("6.6"), RoundingHelper.roundToMultiple(new Apfloat("5.5"), new Apfloat("2.2"), RoundingMode.HALF_UP)); assertEquals("roundToMultiple rational", new Aprational("4/5"), RoundingHelper.roundToMultiple(new Apint(1), new Aprational("2/5"), RoundingMode.HALF_DOWN)); } public static void testCompareToHalf() { assertEquals("0", -1, RoundingHelper.compareToHalf(new Apfloat("0"))); assertEquals("0.4", -1, RoundingHelper.compareToHalf(new Apfloat("0.4"))); assertEquals("0.5", 0, RoundingHelper.compareToHalf(new Apfloat("0.5"))); assertEquals("0.6", 1, RoundingHelper.compareToHalf(new Apfloat("0.6"))); assertEquals("0.4 radix 9", -1, RoundingHelper.compareToHalf(new Apfloat("0.4", 1, 9))); assertEquals("0.5 radix 9", 1, RoundingHelper.compareToHalf(new Apfloat("0.6", 1, 9))); assertEquals("1/3", -1, RoundingHelper.compareToHalf(new Aprational("1/3"))); assertEquals("1/2", 0, RoundingHelper.compareToHalf(new Aprational("1/2"))); assertEquals("2/3", 1, RoundingHelper.compareToHalf(new Aprational("2/3"))); assertEquals("1/3 radix 3", -1, RoundingHelper.compareToHalf(new Aprational("1/10", 3))); assertEquals("1/2 radix 3", 0, RoundingHelper.compareToHalf(new Aprational("1/2", 3))); assertEquals("2/3 radix 3", 1, RoundingHelper.compareToHalf(new Aprational("2/10", 3))); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ShutdownMapTest.java000066400000000000000000000043611461767713300255540ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import java.util.Map; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.9.0 * @author Mikko Tommila */ public class ShutdownMapTest extends TestCase { public ShutdownMapTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ShutdownMapTest("testMap")); return suite; } public static void testMap() { Map map = new ShutdownMap<>(); try { map.put(0, Apfloat.ZERO); fail("ShutdownMap allowed put()"); } catch (ApfloatRuntimeException are) { // OK } try { map.get(0); fail("ShutdownMap allowed get()"); } catch (ApfloatRuntimeException are) { // OK } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/ZetaHelperTest.java000066400000000000000000000074021461767713300253450ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat; import junit.framework.TestSuite; /** * @version 1.11.0 * @author Mikko Tommila */ public class ZetaHelperTest extends ApfloatTestCase { public ZetaHelperTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ZetaHelperTest("testZetafast")); return suite; } public static void testZetafast() { Apcomplex a = new ZetaHelper().zetafast(new Apcomplex("(0,30.00000)")); assertEquals("0+10i precision", 6, a.precision()); assertEquals("0+10i value", new Apcomplex("(-1.26512,-0.60232)"), a, new Apfloat("5e-5")); a = new ZetaHelper().zetafast(new Apcomplex("(0.50000,1000.00000)")); assertEquals("0.5+1000i precision", 5, a.precision()); assertEquals("0.5+1000i value", new Apcomplex("(0.356334,0.931998)"), a, new Apfloat("5e-5")); a = new ZetaHelper().zetafast(new Apcomplex("(1.00000,0.00100000)")); assertEquals("1+0.001i precision", 6, a.precision()); assertEquals("1+0.001i value", new Apcomplex("(0.577216,-1000.00)"), a, new Apfloat("5e-2")); a = new ZetaHelper().zetafast(new Apcomplex(new Apfloat("0.5", 100), new Apfloat(1000, 104))); assertEquals("0.5+1000i precision 100", 100, a.precision()); assertEquals("0.5+1000i value 100", new Apcomplex("(0.3563343671943960550744024767110296418750462109065525137341055161422510305547050764059845122070513740,0.9319978312329936651150604327370560741603548016645680162344141200846918466728345537721968349602390048)"), a, new Apfloat("5e-100")); /* These tests are quite slow a = new ZetaHelper().zetafast(new Apcomplex(new Apfloat("0.5", 100), new Apfloat(10000, 105))); assertEquals("0.5+10000i precision", 100, a.precision()); assertEquals("0.5+10000i value", new Apcomplex("(-0.3393738026388344575674710779459893805666468101906410889337680247470798756615454924994040171851332603,-0.0370915059732060314743442068130120234022523694433894137028295017082175782077688242563900270774953535)"), a, new Apfloat("5e-100")); */ a = new ZetaHelper().zetafast(new Apcomplex(new Apfloat(2, 6, 11), new Apfloat(3, 6, 11))); assertEquals("2+3i radix 11 precision", 6, a.precision()); assertEquals("2+3i radix 11 value", new Apcomplex(new Apfloat("0.886193", 6, 11), new Apfloat("-0.128437", 6, 11)), a, new Apfloat("5e-6", 1, 11)); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/internal/000077500000000000000000000000001461767713300234105ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/java/org/apfloat/internal/ConcurrentSoftHashMapTest.java000066400000000000000000000076611461767713300313450ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.List; import java.util.ArrayList; import java.util.concurrent.ConcurrentMap; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class ConcurrentSoftHashMapTest extends TestCase { public ConcurrentSoftHashMapTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ConcurrentSoftHashMapTest("testSoft")); suite.addTest(new ConcurrentSoftHashMapTest("testPutIfAbsent")); return suite; } public static void testSoft() { ConcurrentMap map = new ConcurrentSoftHashMap<>(); final int SIZE = 1000000; byte[] value = new byte[4 * SIZE]; map.put(1, value); assertEquals("Size after put", 1, map.size()); assertNotNull("Value", map.get(1)); value = null; // Force out of memory try { List dummy = new ArrayList<>(); for (int i = 2; i < 1000000000 && map.get(1) != null; i++) { dummy.add(new byte[SIZE]); } } catch (OutOfMemoryError oome) { // Should happen eventually } assertNull("Cleared", map.get(1)); map.put(1, value); map.clear(); assertNull("Explicitly cleared", map.get(1)); assertNull("Removed", map.remove(1)); try { map.entrySet(); } catch (UnsupportedOperationException uoe) { // Ignore } try { map.remove(1, value); } catch (UnsupportedOperationException uoe) { // Ignore } try { map.replace(1, value); } catch (UnsupportedOperationException uoe) { // Ignore } try { map.replace(1, value, value); } catch (UnsupportedOperationException uoe) { // Ignore } } public static void testPutIfAbsent() { ConcurrentMap map = new ConcurrentSoftHashMap<>(); Integer key1 = 1; Integer value1 = 2; Integer value2 = 3; assertNull("First putIfAbsent", map.putIfAbsent(key1, value1)); assertSame("Second putIfAbsent", value1, map.putIfAbsent(key1, value2)); assertSame("Get", value1, map.get(key1)); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/internal/Java9ClassLoader.java000066400000000000000000000063001461767713300273410ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.IOException; import java.io.InputStream; /** * Class loader to load Java 9 specific multi-version classes. * * @version 1.9.0 * @author Mikko Tommila */ public class Java9ClassLoader extends ClassLoader { public Java9ClassLoader(ClassLoader parent) { super(parent); } /** * Force load a Java 8 class from the normal (non-multi-version) location. * Loads the class again even if it has been already loaded by this or a * parent class loader. * * @param name Name of the class. * * @return The class. * * @throws IOException In case of error reading the class bytes. * @throws ClassNotFoundException In case the class file is not found. */ public Class loadJava8Class(String name) throws IOException, ClassNotFoundException { return loadClassWithPrefix("", name); } /** * Force load a Java 9 class from the Java 9 multi-version location. * Loads the class again even if it has been already loaded by this or a * parent class loader. * * @param name Name of the class. * * @return The class. * * @throws IOException In case of error reading the class bytes. * @throws ClassNotFoundException In case the class file is not found. */ public Class loadJava9Class(String name) throws IOException, ClassNotFoundException { return loadClassWithPrefix("META-INF/versions/9/", name); } private Class loadClassWithPrefix(String prefix, String name) throws IOException, ClassNotFoundException { String path = prefix + name.replace('.', '/') + ".class"; byte[] bytes; try (InputStream in = getResourceAsStream(path)) { if (in == null) { throw new ClassNotFoundException(name); } bytes = in.readAllBytes(); } return defineClass(name, bytes, 0, bytes.length); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/internal/MessagePasserTest.java000066400000000000000000000065521461767713300276650ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @since 1.6 * @version 1.9.0 * @author Mikko Tommila */ public class MessagePasserTest extends TestCase { public MessagePasserTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new MessagePasserTest("testPassMessage")); suite.addTest(new MessagePasserTest("testPassMessageParallel")); return suite; } public static void testPassMessage() { MessagePasser messagePasser = new MessagePasser<>(); assertNull("No message yet", messagePasser.getMessage(1)); messagePasser.sendMessage(1, "Hello, world!"); assertEquals("Message received", "Hello, world!", messagePasser.receiveMessage(1)); assertNull("No message anymore", messagePasser.getMessage(1)); messagePasser.sendMessage(2, "Hello, world!"); assertEquals("Message got", "Hello, world!", messagePasser.getMessage(2)); assertNull("No message anymore 2", messagePasser.getMessage(2)); } public static void testPassMessageParallel() { MessagePasser messagePasser = new MessagePasser<>(); Thread thread = new Thread() { @Override public void run() { assertNull("No message yet", messagePasser.getMessage(1)); assertEquals("Message received", "Hello, world!", messagePasser.receiveMessage(1)); } }; thread.start(); sleepUninterrupted(100); messagePasser.sendMessage(1, "Hello, world!"); sleepUninterrupted(100); assertNull("No message anymore", messagePasser.getMessage(1)); } private static void sleepUninterrupted(long time) { try { Thread.sleep(time); } catch (InterruptedException ie) { fail(ie.toString()); } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/internal/ParallelRunnerTest.java000066400000000000000000000277441461767713300300570ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.apfloat.*; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @since 1.1 * @version 1.14.0 * @author Mikko Tommila */ public class ParallelRunnerTest extends TestCase { private static abstract class DummyFuture implements Future { @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public Object get() { return null; } @Override public Object get(long timeout, TimeUnit unit) { return null; } } public ParallelRunnerTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ParallelRunnerTest("testRunParallel")); suite.addTest(new ParallelRunnerTest("testRunParallelLong")); suite.addTest(new ParallelRunnerTest("testRunParallelTwo")); suite.addTest(new ParallelRunnerTest("testWait")); suite.addTest(new ParallelRunnerTest("testInterrupt")); return suite; } public static void testRunParallel() { for (int threads = 1; threads <= 32; threads++) { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(threads); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); final int LENGTH = 1000000; int[] values = new int[LENGTH]; ParallelRunnable parallelRunnable = new ParallelRunnable(LENGTH) { @Override public Runnable getRunnable(int start, int length) { return () -> { for (int i = start; i < start + length; i++) { values[i] += i; } }; } }; ParallelRunner.runParallel(parallelRunnable); for (int i = 0; i < LENGTH; i++) { assertEquals(threads + " threads, element " + i, i, values[i]); } } } public static void testRunParallelLong() { for (int threads = 1; threads <= 32; threads++) { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(threads); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); final long LENGTH = 1000000000000L; final int SQRT_LENGTH = 1000000; Map starts = new ConcurrentHashMap<>(); ParallelRunnable parallelRunnable = new ParallelRunnable(LENGTH) { @Override public Runnable getRunnable(long start, long length) { return () -> { starts.put(start, start); assertEquals("length", SQRT_LENGTH, length); }; } @Override protected long getPreferredBatchSize() { return SQRT_LENGTH; } }; ParallelRunner.runParallel(parallelRunnable); assertEquals("starts size", SQRT_LENGTH, starts.size()); for (int i = 0; i < SQRT_LENGTH; i++) { assertTrue(i + " started", starts.containsKey(SQRT_LENGTH * (long) i)); } } } public static void testRunParallelTwo() throws Exception { for (int threads = 1; threads <= 32; threads++) { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(threads); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); final int LENGTH = 1000000; int[] values = new int[LENGTH]; ParallelRunnable parallelRunnable = new ParallelRunnable(LENGTH) { @Override public Runnable getRunnable(int start, int length) { return () -> { for (int i = start; i < start + length; i++) { values[i] += i; } }; } }; int[] values2 = new int[LENGTH]; ParallelRunnable parallelRunnable2 = new ParallelRunnable(LENGTH) { @Override public Runnable getRunnable(int start, int length) { return () -> { for (int i = start; i < start + length; i++) { values2[i] += i; } }; } }; Future future = ctx.getExecutorService().submit(parallelRunnable); ParallelRunner.runParallel(parallelRunnable2); future.get(); for (int i = 0; i < LENGTH; i++) { assertEquals(threads + " threads, element " + i, i, values[i]); } for (int i = 0; i < LENGTH; i++) { assertEquals(threads + " threads, other element " + i, i, values2[i]); } } } public static void testWait() { for (int threads = 2; threads <= 32; threads += 2) { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(threads); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); ctx.setNumberOfProcessors(threads / 2); // Both ParallelRunner and stealer thread use half of the available processors final int LENGTH = 10000; Map threadNames = new ConcurrentHashMap<>(); AtomicBoolean done = new AtomicBoolean(); CountDownLatch startLatch = new CountDownLatch(threads), endLatch = new CountDownLatch(threads), otherLatch = new CountDownLatch(1); ParallelRunnable parallelRunnable = new ParallelRunnable(LENGTH) { @Override public Runnable getRunnable(int start, int length) { return () -> { threadNames.put(Thread.currentThread().getName(), ""); startLatch.countDown(); awaitUninterrupted(startLatch); done.set(true); endLatch.countDown(); awaitUninterrupted(endLatch); }; } }; // In some other thread, steal some work for the entire execution time (do not let the ExecutorService use this thread for anything else) Runnable otherTask = () -> { Future dummyFuture = new DummyFuture() { @Override public boolean isDone() { return done.get(); } }; ctx.wait(dummyFuture); otherLatch.countDown(); }; ctx.getExecutorService().execute(otherTask); ParallelRunner.runParallel(parallelRunnable); awaitUninterrupted(otherLatch); assertEquals(threads + " threads (" + threadNames + ")", threads, threadNames.size()); } } public static void testInterrupt() { for (int threads = 1; threads <= 32; threads++) { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(threads); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); final long LENGTH = 1000000000000000000L; CountDownLatch startLatch = new CountDownLatch(threads), endLatch = new CountDownLatch(threads); ParallelRunnable parallelRunnable = new ParallelRunnable(LENGTH) { @Override public Runnable getRunnable(long start, long length) { return () -> { startLatch.countDown(); int hash = 0; while (true) { try { hash += ApfloatContext.getContext().hashCode(); } catch (ApfloatInterruptedException aie) { endLatch.countDown(); aie.addSuppressed(new Exception("Hash: " + hash)); throw aie; } Thread.yield(); } }; } }; Thread currentThread = Thread.currentThread(); new Thread(() -> { awaitUninterrupted(startLatch); currentThread.interrupt(); }).start(); try { ParallelRunner.runParallel(parallelRunnable); fail("No exception thrown"); } catch (ApfloatInterruptedException aie) { // Ok, should be thrown } awaitUninterrupted(endLatch); assertEquals(threads + " threads, start latch count", 0, startLatch.getCount()); assertEquals(threads + " threads, end latch count", 0, endLatch.getCount()); } } private static void awaitUninterrupted(CountDownLatch latch) { try { latch.await(); } catch (InterruptedException ie) { fail(ie.toString()); } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/internal/ScrambleTest.java000066400000000000000000000057761461767713300266620ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.0 * @author Mikko Tommila */ public class ScrambleTest extends TestCase { public ScrambleTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new ScrambleTest("testPermute")); suite.addTest(new ScrambleTest("testCreateScrambleTable")); return suite; } public static void testPermute() { assertEquals("permute(0, 1)", 0, Scramble.permute(0, 1)); assertEquals("permute(0, 2)", 0, Scramble.permute(0, 2)); assertEquals("permute(1, 2)", 1, Scramble.permute(1, 2)); assertEquals("permute(1, 8)", 4, Scramble.permute(1, 8)); assertEquals("permute(3, 16)", 12, Scramble.permute(3, 16)); assertEquals("permute(5, 256)", 160, Scramble.permute(5, 256)); } public static void testCreateScrambleTable() { int[] table = Scramble.createScrambleTable(8); assertEquals("length", 4, table.length); int[] ints = { 0, 1, 2, 3, 4, 5, 6, 7 }; int tmp; tmp = ints[table[0]]; ints[table[0]] = ints[table[1]]; ints[table[1]] = tmp; tmp = ints[table[2]]; ints[table[2]] = ints[table[3]]; ints[table[3]] = tmp; assertEquals("[0]", 0, ints[0]); assertEquals("[1]", 4, ints[1]); assertEquals("[2]", 2, ints[2]); assertEquals("[3]", 6, ints[3]); assertEquals("[4]", 1, ints[4]); assertEquals("[5]", 5, ints[5]); assertEquals("[6]", 3, ints[6]); assertEquals("[7]", 7, ints[7]); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/spi/000077500000000000000000000000001461767713300223675ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/java/org/apfloat/spi/DataStorageTest.java000066400000000000000000000350551461767713300263000ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import org.apfloat.ApfloatRuntimeException; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @since 1.8.1 * @version 1.9.0 * @author Mikko Tommila */ public class DataStorageTest extends TestCase { private static class DummyDataStorage extends DataStorage { public DummyDataStorage(long size) { this.size = size; } @Override protected DataStorage implSubsequence(long offset, long length) { throw new UnsupportedOperationException(); } @Override protected void implCopyFrom(DataStorage dataStorage, long size) { throw new UnsupportedOperationException(); } @Override protected long implGetSize() { return this.size; } @Override protected void implSetSize(long size) { throw new UnsupportedOperationException(); } @Override protected ArrayAccess implGetArray(int mode, long offset, int length) { throw new UnsupportedOperationException(); } @Override protected ArrayAccess implGetArray(int mode, int startColumn, int columns, int rows) { throw new UnsupportedOperationException(); } @Override protected ArrayAccess implGetTransposedArray(int mode, int startColumn, int columns, int rows) { throw new UnsupportedOperationException(); } @Override public Iterator iterator(int mode, long startPosition, long endPosition) { throw new UnsupportedOperationException(); } @Override public boolean isCached() { throw new UnsupportedOperationException(); } private static final long serialVersionUID = 1L; private long size; } private static class DummyArrayAccess extends ArrayAccess { public DummyArrayAccess() { super(0, 0); } @Override public ArrayAccess subsequence(int offset, int length) { throw new UnsupportedOperationException(); } @Override public Object getData() { throw new UnsupportedOperationException(); } @Override public void close() { throw new UnsupportedOperationException(); } private static final long serialVersionUID = 1L; } public DataStorageTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new DataStorageTest("testGetArray")); suite.addTest(new DataStorageTest("testGetArrayBig")); suite.addTest(new DataStorageTest("testGetArrayBlockSmall")); suite.addTest(new DataStorageTest("testGetArrayBlockBig")); suite.addTest(new DataStorageTest("testGetTransposedArrayBlockSmall")); suite.addTest(new DataStorageTest("testGetTransposedArrayBlockBig")); return suite; } public static void testGetArray() { ArrayAccess arrayAccess = new DummyArrayAccess(); DataStorage dataStorage = new DummyDataStorage(10) { @Override protected ArrayAccess implGetArray(int mode, long offset, int length) { return arrayAccess; } private static final long serialVersionUID = 1L; }; assertSame("0 10", arrayAccess, dataStorage.getArray(DataStorage.READ, 0, 10)); assertSame("1 9", arrayAccess, dataStorage.getArray(DataStorage.READ, 9, 1)); try { dataStorage.getArray(DataStorage.READ, 10, 1); fail("Too big offset accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getArray(DataStorage.READ, 0, 11); fail("Too big array accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getArray(DataStorage.READ, -1, 10); fail("Negative offset accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getArray(DataStorage.READ, 0, -1); fail("Negative length accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } } public static void testGetArrayBig() { ArrayAccess arrayAccess = new DummyArrayAccess(); DataStorage dataStorage = new DummyDataStorage(Long.MAX_VALUE) { @Override protected ArrayAccess implGetArray(int mode, long offset, int length) { return arrayAccess; } private static final long serialVersionUID = 1L; }; assertSame("0 max", arrayAccess, dataStorage.getArray(DataStorage.READ, 0, Integer.MAX_VALUE)); assertSame("1 max-1", arrayAccess, dataStorage.getArray(DataStorage.READ, Long.MAX_VALUE - 1, 1)); try { dataStorage.getArray(DataStorage.READ, Long.MAX_VALUE, 1); fail("Too big offset accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } } public static void testGetArrayBlockSmall() { ArrayAccess arrayAccess = new DummyArrayAccess(); DataStorage dataStorage = new DummyDataStorage(100) { @Override protected ArrayAccess implGetArray(int mode, int startColumn, int columns, int rows) { return arrayAccess; } private static final long serialVersionUID = 1L; }; assertSame("0 10 10", arrayAccess, dataStorage.getArray(DataStorage.READ, 0, 10, 10)); assertSame("1 9 10", arrayAccess, dataStorage.getArray(DataStorage.READ, 1, 9, 10)); assertSame("9 1 10", arrayAccess, dataStorage.getArray(DataStorage.READ, 9, 1, 10)); try { dataStorage.getArray(DataStorage.READ, 1, 10, 10); fail("Too big start column accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getArray(DataStorage.READ, 0, 11, 10); fail("Too many columns accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getArray(DataStorage.READ, 0, 10, 11); fail("Too many rows accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getArray(DataStorage.READ, -1, 10, 10); fail("Negative start column accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getArray(DataStorage.READ, 0, -1, 10); fail("Negative columns accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getArray(DataStorage.READ, 0, 10, -1); fail("Negative rows accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } } public static void testGetArrayBlockBig() { ArrayAccess arrayAccess = new DummyArrayAccess(); DataStorage dataStorage = new DummyDataStorage((long) Integer.MAX_VALUE * Integer.MAX_VALUE) { @Override protected ArrayAccess implGetArray(int mode, int startColumn, int columns, int rows) { return arrayAccess; } private static final long serialVersionUID = 1L; }; assertSame("0 1 max", arrayAccess, dataStorage.getArray(DataStorage.READ, 0, 1, Integer.MAX_VALUE)); assertSame("max-1 1 max", arrayAccess, dataStorage.getArray(DataStorage.READ, Integer.MAX_VALUE - 1, 1, Integer.MAX_VALUE)); try { dataStorage.getArray(DataStorage.READ, 1, Integer.MAX_VALUE, Integer.MAX_VALUE); fail("Too big start column accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getArray(DataStorage.READ, 0, 0x10000, 0x8000); fail("Too big array accepted"); } catch (ApfloatRuntimeException are) { // OK, too big array } try { dataStorage.getArray(DataStorage.READ, 0, 2, Integer.MAX_VALUE); fail("Too big array 2 accepted"); } catch (ApfloatRuntimeException are) { // OK, too big array } } public static void testGetTransposedArrayBlockSmall() { ArrayAccess arrayAccess = new DummyArrayAccess(); DataStorage dataStorage = new DummyDataStorage(100) { @Override protected ArrayAccess implGetTransposedArray(int mode, int startColumn, int columns, int rows) { return arrayAccess; } private static final long serialVersionUID = 1L; }; assertSame("0 10 10", arrayAccess, dataStorage.getTransposedArray(DataStorage.READ, 0, 10, 10)); assertSame("1 9 10", arrayAccess, dataStorage.getTransposedArray(DataStorage.READ, 1, 9, 10)); assertSame("9 1 10", arrayAccess, dataStorage.getTransposedArray(DataStorage.READ, 9, 1, 10)); try { dataStorage.getTransposedArray(DataStorage.READ, 1, 10, 10); fail("Too big start column accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getTransposedArray(DataStorage.READ, 0, 11, 10); fail("Too many columns accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getTransposedArray(DataStorage.READ, 0, 10, 11); fail("Too many rows accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getTransposedArray(DataStorage.READ, -1, 10, 10); fail("Negative start column accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getTransposedArray(DataStorage.READ, 0, -1, 10); fail("Negative columns accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getTransposedArray(DataStorage.READ, 0, 10, -1); fail("Negative rows accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } } public static void testGetTransposedArrayBlockBig() { ArrayAccess arrayAccess = new DummyArrayAccess(); DataStorage dataStorage = new DummyDataStorage((long) Integer.MAX_VALUE * Integer.MAX_VALUE) { @Override protected ArrayAccess implGetTransposedArray(int mode, int startColumn, int columns, int rows) { return arrayAccess; } private static final long serialVersionUID = 1L; }; assertSame("0 1 max", arrayAccess, dataStorage.getTransposedArray(DataStorage.READ, 0, 1, Integer.MAX_VALUE)); assertSame("max-1 1 max", arrayAccess, dataStorage.getTransposedArray(DataStorage.READ, Integer.MAX_VALUE - 1, 1, Integer.MAX_VALUE)); try { dataStorage.getTransposedArray(DataStorage.READ, 1, Integer.MAX_VALUE, Integer.MAX_VALUE); fail("Too big start column accepted"); } catch (IllegalArgumentException iae) { // OK, out of range } try { dataStorage.getTransposedArray(DataStorage.READ, 0, 0x10000, 0x8000); fail("Too big array accepted"); } catch (ApfloatRuntimeException are) { // OK, too big array } try { dataStorage.getTransposedArray(DataStorage.READ, 0, 2, Integer.MAX_VALUE); fail("Too big array 2 accepted"); } catch (ApfloatRuntimeException are) { // OK, too big array } } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/spi/FilenameGeneratorTest.java000066400000000000000000000041031461767713300274570ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.0 * @author Mikko Tommila */ public class FilenameGeneratorTest extends TestCase { public FilenameGeneratorTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new FilenameGeneratorTest("testGenerateFilename")); return suite; } public static void testGenerateFilename() { FilenameGenerator filenameGenerator = new FilenameGenerator("path", "5", "suffix"); assertEquals("filename", "path5suffix", filenameGenerator.generateFilename()); assertEquals("filename", "path6suffix", filenameGenerator.generateFilename()); } } apfloat-1.14.0/apfloat/src/test/java/org/apfloat/spi/UtilTest.java000066400000000000000000000345371461767713300250230ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.spi; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; import junit.framework.TestCase; import junit.framework.TestSuite; import org.apfloat.Apfloat; import org.apfloat.OverflowException; /** * @version 1.14.0 * @author Mikko Tommila */ public class UtilTest extends TestCase { public UtilTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new UtilTest("testRound2down")); suite.addTest(new UtilTest("testRound2up")); suite.addTest(new UtilTest("testRound23down")); suite.addTest(new UtilTest("testRound23up")); suite.addTest(new UtilTest("testSqrt4down")); suite.addTest(new UtilTest("testSqrt4up")); suite.addTest(new UtilTest("testLog2down")); suite.addTest(new UtilTest("testLog2up")); suite.addTest(new UtilTest("testIfFinite")); suite.addTest(new UtilTest("testMax")); suite.addTest(new UtilTest("testMin")); suite.addTest(new UtilTest("testMultiplyExact")); suite.addTest(new UtilTest("testAddExact")); suite.addTest(new UtilTest("testSubtractExact")); suite.addTest(new UtilTest("testStream")); return suite; } public static void testRound2down() { assertEquals("0", 0, Util.round2down(0)); assertEquals("1", 1, Util.round2down(1)); assertEquals("2", 2, Util.round2down(2)); assertEquals("3", 2, Util.round2down(3)); assertEquals("4", 4, Util.round2down(4)); assertEquals("5", 4, Util.round2down(5)); assertEquals("7", 4, Util.round2down(7)); assertEquals("8", 8, Util.round2down(8)); assertEquals("9", 8, Util.round2down(9)); assertEquals("max integer", 1 << 30, Util.round2down(Integer.MAX_VALUE)); assertEquals("0L", 0, Util.round2down(0L)); assertEquals("1L", 1, Util.round2down(1L)); assertEquals("2L", 2, Util.round2down(2L)); assertEquals("3L", 2, Util.round2down(3L)); assertEquals("4L", 4, Util.round2down(4L)); assertEquals("5L", 4, Util.round2down(5L)); assertEquals("7L", 4, Util.round2down(7L)); assertEquals("8L", 8, Util.round2down(8L)); assertEquals("9L", 8, Util.round2down(9L)); assertEquals("max long", 1L << 62, Util.round2down(Long.MAX_VALUE)); } public static void testRound2up() { assertEquals("0", 0, Util.round2up(0)); assertEquals("1", 1, Util.round2up(1)); assertEquals("2", 2, Util.round2up(2)); assertEquals("3", 4, Util.round2up(3)); assertEquals("4", 4, Util.round2up(4)); assertEquals("5", 8, Util.round2up(5)); assertEquals("7", 8, Util.round2up(7)); assertEquals("8", 8, Util.round2up(8)); assertEquals("9", 16, Util.round2up(9)); assertEquals("max integer", 1 << 30, Util.round2up(0x20000001)); assertEquals("max integer", 1 << 30, Util.round2up(0x40000000)); assertEquals("0L", 0, Util.round2up(0L)); assertEquals("1L", 1, Util.round2up(1L)); assertEquals("2L", 2, Util.round2up(2L)); assertEquals("3L", 4, Util.round2up(3L)); assertEquals("4L", 4, Util.round2up(4L)); assertEquals("5L", 8, Util.round2up(5L)); assertEquals("7L", 8, Util.round2up(7L)); assertEquals("8L", 8, Util.round2up(8L)); assertEquals("9L", 16, Util.round2up(9L)); assertEquals("max long rounded", 1L << 62, Util.round2up(0x2000000000000001L)); assertEquals("max long", 1L << 62, Util.round2up(0x4000000000000000L)); } public static void testRound23down() { assertEquals("0", 0, Util.round23down(0)); assertEquals("1", 1, Util.round23down(1)); assertEquals("2", 2, Util.round23down(2)); assertEquals("3", 3, Util.round23down(3)); assertEquals("4", 4, Util.round23down(4)); assertEquals("5", 4, Util.round23down(5)); assertEquals("6", 6, Util.round23down(6)); assertEquals("7", 6, Util.round23down(7)); assertEquals("8", 8, Util.round23down(8)); assertEquals("9", 8, Util.round23down(9)); assertEquals("max integer", 3 << 29, Util.round23down(Integer.MAX_VALUE)); assertEquals("0L", 0, Util.round23down(0L)); assertEquals("1L", 1, Util.round23down(1L)); assertEquals("2L", 2, Util.round23down(2L)); assertEquals("3L", 3, Util.round23down(3L)); assertEquals("4L", 4, Util.round23down(4L)); assertEquals("5L", 4, Util.round23down(5L)); assertEquals("6L", 6, Util.round23down(6L)); assertEquals("7L", 6, Util.round23down(7L)); assertEquals("8L", 8, Util.round23down(8L)); assertEquals("9L", 8, Util.round23down(9L)); assertEquals("max long", 3L << 61, Util.round23down(Long.MAX_VALUE)); } public static void testRound23up() { assertEquals("0", 0, Util.round23up(0)); assertEquals("1", 1, Util.round23up(1)); assertEquals("2", 2, Util.round23up(2)); assertEquals("3", 3, Util.round23up(3)); assertEquals("4", 4, Util.round23up(4)); assertEquals("5", 6, Util.round23up(5)); assertEquals("6", 6, Util.round23up(6)); assertEquals("7", 8, Util.round23up(7)); assertEquals("8", 8, Util.round23up(8)); assertEquals("9", 12, Util.round23up(9)); assertEquals("max integer", 3 << 29, Util.round23up(0x40000001)); assertEquals("max integer", 3 << 29, Util.round23up(0x60000000)); assertEquals("0L", 0, Util.round23up(0L)); assertEquals("1L", 1, Util.round23up(1L)); assertEquals("2L", 2, Util.round23up(2L)); assertEquals("3L", 3, Util.round23up(3L)); assertEquals("4L", 4, Util.round23up(4L)); assertEquals("5L", 6, Util.round23up(5L)); assertEquals("6L", 6, Util.round23up(6L)); assertEquals("7L", 8, Util.round23up(7L)); assertEquals("8L", 8, Util.round23up(8L)); assertEquals("9L", 12, Util.round23up(9L)); assertEquals("max long rounded", 3L << 61, Util.round23up(0x4000000000000001L)); assertEquals("max long", 3L << 61, Util.round23up(0x6000000000000000L)); } public static void testSqrt4down() { assertEquals("0", 0, Util.sqrt4down(0)); assertEquals("1", 1, Util.sqrt4down(1)); assertEquals("2", 1, Util.sqrt4down(2)); assertEquals("3", 1, Util.sqrt4down(3)); assertEquals("4", 2, Util.sqrt4down(4)); assertEquals("5", 2, Util.sqrt4down(5)); assertEquals("7", 2, Util.sqrt4down(7)); assertEquals("8", 2, Util.sqrt4down(8)); assertEquals("9", 2, Util.sqrt4down(9)); assertEquals("15", 2, Util.sqrt4down(15)); assertEquals("16", 4, Util.sqrt4down(16)); assertEquals("17", 4, Util.sqrt4down(17)); assertEquals("max integer", 0x8000, Util.sqrt4down(Integer.MAX_VALUE)); assertEquals("0L", 0, Util.sqrt4down(0L)); assertEquals("1L", 1, Util.sqrt4down(1L)); assertEquals("2L", 1, Util.sqrt4down(2L)); assertEquals("3L", 1, Util.sqrt4down(3L)); assertEquals("4L", 2, Util.sqrt4down(4L)); assertEquals("5L", 2, Util.sqrt4down(5L)); assertEquals("7L", 2, Util.sqrt4down(7L)); assertEquals("8L", 2, Util.sqrt4down(8L)); assertEquals("9L", 2, Util.sqrt4down(9L)); assertEquals("15L", 2, Util.sqrt4down(15L)); assertEquals("16L", 4, Util.sqrt4down(16L)); assertEquals("17L", 4, Util.sqrt4down(17L)); assertEquals("max long", 0x80000000L, Util.sqrt4down(Long.MAX_VALUE)); } public static void testSqrt4up() { assertEquals("0", 0, Util.sqrt4up(0)); assertEquals("1", 1, Util.sqrt4up(1)); assertEquals("2", 2, Util.sqrt4up(2)); assertEquals("3", 2, Util.sqrt4up(3)); assertEquals("4", 2, Util.sqrt4up(4)); assertEquals("5", 4, Util.sqrt4up(5)); assertEquals("7", 4, Util.sqrt4up(7)); assertEquals("8", 4, Util.sqrt4up(8)); assertEquals("9", 4, Util.sqrt4up(9)); assertEquals("15", 4, Util.sqrt4up(15)); assertEquals("16", 4, Util.sqrt4up(16)); assertEquals("17", 8, Util.sqrt4up(17)); assertEquals("max integer", 0x10000, Util.sqrt4up(Integer.MAX_VALUE)); assertEquals("0L", 0, Util.sqrt4up(0L)); assertEquals("1L", 1, Util.sqrt4up(1L)); assertEquals("2L", 2, Util.sqrt4up(2L)); assertEquals("3L", 2, Util.sqrt4up(3L)); assertEquals("4L", 2, Util.sqrt4up(4L)); assertEquals("5L", 4, Util.sqrt4up(5L)); assertEquals("7L", 4, Util.sqrt4up(7L)); assertEquals("8L", 4, Util.sqrt4up(8L)); assertEquals("9L", 4, Util.sqrt4up(9L)); assertEquals("15L", 4, Util.sqrt4up(15L)); assertEquals("16L", 4, Util.sqrt4up(16L)); assertEquals("17L", 8, Util.sqrt4up(17L)); assertEquals("max long", 0x100000000L, Util.sqrt4up(Long.MAX_VALUE)); } public static void testLog2down() { assertEquals("1", 0, Util.log2down(1)); assertEquals("2", 1, Util.log2down(2)); assertEquals("3", 1, Util.log2down(3)); assertEquals("4", 2, Util.log2down(4)); assertEquals("5", 2, Util.log2down(5)); assertEquals("7", 2, Util.log2down(7)); assertEquals("8", 3, Util.log2down(8)); assertEquals("9", 3, Util.log2down(9)); assertEquals("max integer", 30, Util.log2down(Integer.MAX_VALUE)); assertEquals("1L", 0, Util.log2down(1L)); assertEquals("2L", 1, Util.log2down(2L)); assertEquals("3L", 1, Util.log2down(3L)); assertEquals("4L", 2, Util.log2down(4L)); assertEquals("5L", 2, Util.log2down(5L)); assertEquals("7L", 2, Util.log2down(7L)); assertEquals("8L", 3, Util.log2down(8L)); assertEquals("9L", 3, Util.log2down(9L)); assertEquals("max long", 62, Util.log2down(Long.MAX_VALUE)); } public static void testLog2up() { assertEquals("1", 0, Util.log2up(1)); assertEquals("2", 1, Util.log2up(2)); assertEquals("3", 2, Util.log2up(3)); assertEquals("4", 2, Util.log2up(4)); assertEquals("5", 3, Util.log2up(5)); assertEquals("7", 3, Util.log2up(7)); assertEquals("8", 3, Util.log2up(8)); assertEquals("9", 4, Util.log2up(9)); assertEquals("max integer", 31, Util.log2up(Integer.MAX_VALUE)); assertEquals("1L", 0, Util.log2up(1L)); assertEquals("2L", 1, Util.log2up(2L)); assertEquals("3L", 2, Util.log2up(3L)); assertEquals("4L", 2, Util.log2up(4L)); assertEquals("5L", 3, Util.log2up(5L)); assertEquals("7L", 3, Util.log2up(7L)); assertEquals("8L", 3, Util.log2up(8L)); assertEquals("9L", 4, Util.log2up(9L)); assertEquals("max long", 63, Util.log2up(Long.MAX_VALUE)); } public static void testIfFinite() { assertEquals("Finite", 2, Util.ifFinite(1, 2)); assertEquals("Infinite", Apfloat.INFINITE, Util.ifFinite(Apfloat.INFINITE, 2)); } public static void testMax() { assertEquals("Only", 1, Util.max(1)); assertEquals("First", 2, Util.max(1, 2)); assertEquals("Last", 3, Util.max(2, 1, 3)); assertEquals("Middle", 3, Util.max(2, 3, 1)); } public static void testMin() { assertEquals("Only", 1, Util.min(1)); assertEquals("First", 1, Util.min(1, 2)); assertEquals("Last", 1, Util.min(3, 2, 1)); assertEquals("Middle", 1, Util.min(3, 1, 2)); } public static void testMultiplyExact() { assertEquals("Valid", 6, Util.multiplyExact(2, 3)); try { Util.multiplyExact(2, Long.MAX_VALUE); fail("Overflow allowed"); } catch (OverflowException oe) { // OK: overflow } } public static void testAddExact() { assertEquals("Valid", 5, Util.addExact(2, 3)); try { Util.addExact(1, Long.MAX_VALUE); fail("Overflow allowed"); } catch (OverflowException oe) { // OK: overflow } } public static void testSubtractExact() { assertEquals("Valid", -1, Util.subtractExact(2, 3)); try { Util.subtractExact(-2, Long.MAX_VALUE); fail("Overflow allowed"); } catch (OverflowException oe) { // OK: overflow } } public static void testStream() { Iterator iterator = Arrays.asList(1, 2, 3).iterator(); Stream stream = Util.stream(iterator); List list = stream.collect(Collectors.toList()); assertEquals("Items", Arrays.asList(1, 2, 3), list); } } apfloat-1.14.0/apfloat/src/test/template/000077500000000000000000000000001461767713300202515ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/000077500000000000000000000000001461767713300210405ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/apfloat/000077500000000000000000000000001461767713300224665ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/000077500000000000000000000000001461767713300243025ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeAdditionStrategyTest.java000066400000000000000000000154121461767713300326420ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeAdditionStrategyTest extends RawtypeTestCase implements RawtypeRadixConstants { public RawtypeAdditionStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeAdditionStrategyTest("testAdd")); suite.addTest(new RawtypeAdditionStrategyTest("testSubtract")); suite.addTest(new RawtypeAdditionStrategyTest("testMultiplyAdd")); suite.addTest(new RawtypeAdditionStrategyTest("testDivide")); return suite; } private static DataStorage createDataStorage(rawtype[] data) { int size = data.length; ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); DataStorage dataStorage = dataStorageBuilder.createDataStorage(size * RawType.BYTES); dataStorage.setSize(size); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, size)) { System.arraycopy(data, 0, arrayAccess.getData(), arrayAccess.getOffset(), size); } return dataStorage; } private static void check(String message, rawtype[] expected, DataStorage actual) { try (ArrayAccess arrayAccess = actual.getArray(DataStorage.READ, 0, expected.length)) { assertEquals(message + " length", expected.length, arrayAccess.getLength()); for (int i = 0; i < arrayAccess.getLength(); i++) { assertEquals(message + " [" + i + "]", (long) expected[i], (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + i]); } } } public static void testAdd() { DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 0, (rawtype) 1, (rawtype) 2, (rawtype) 3 }), src2 = createDataStorage(new rawtype[] { (rawtype) 4, (rawtype) 5, (rawtype) 6, (rawtype) 7 }), dst = createDataStorage(new rawtype[4]); RawtypeAdditionStrategy strategy = new RawtypeAdditionStrategy(10); rawtype carry = strategy.zero(); carry = strategy.add(src1.iterator(DataStorage.READ, 0, 4), src2.iterator(DataStorage.READ, 0, 4), carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("carry", strategy.zero(), (RawType) carry); check("result", new rawtype[] { (rawtype) 4, (rawtype) 6, (rawtype) 8, (rawtype) 10 }, dst); } public static void testSubtract() { DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 4, (rawtype) 5, (rawtype) 6, (rawtype) 7 }), src2 = createDataStorage(new rawtype[] { (rawtype) 0, (rawtype) 1, (rawtype) 2, (rawtype) 3 }), dst = createDataStorage(new rawtype[4]); RawtypeAdditionStrategy strategy = new RawtypeAdditionStrategy(10); rawtype carry = strategy.zero(); carry = strategy.subtract(src1.iterator(DataStorage.READ, 0, 4), src2.iterator(DataStorage.READ, 0, 4), carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("carry", strategy.zero(), (RawType) carry); check("result", new rawtype[] { (rawtype) 4, (rawtype) 4, (rawtype) 4, (rawtype) 4 }, dst); } public static void testMultiplyAdd() { DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4 }), src2 = createDataStorage(new rawtype[] { (rawtype) 5, (rawtype) 6, (rawtype) 7, (rawtype) 8 }), dst = createDataStorage(new rawtype[4]); RawtypeAdditionStrategy strategy = new RawtypeAdditionStrategy(10); rawtype carry = strategy.zero(); carry = strategy.multiplyAdd(src1.iterator(DataStorage.READ, 0, 4), src2.iterator(DataStorage.READ, 0, 4), (rawtype) 9, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("carry", strategy.zero(), (RawType) carry); check("result", new rawtype[] { (rawtype) 14, (rawtype) 24, (rawtype) 34, (rawtype) 44 }, dst); } public static void testDivide() { DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 0, (rawtype) 2, (rawtype) 4, (rawtype) 7 }), dst = createDataStorage(new rawtype[4]); RawtypeAdditionStrategy strategy = new RawtypeAdditionStrategy(10); rawtype carry = strategy.zero(); carry = strategy.divide(src1.iterator(DataStorage.READ, 0, 4), (rawtype) 2, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("carry", 1, (long) carry); check("result", new rawtype[] { (rawtype) 0, (rawtype) 1, (rawtype) 2, (rawtype) 3 }, dst); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeApfloatBuilderTest.java000066400000000000000000000142431461767713300322620ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.PushbackReader; import java.io.StringReader; import java.io.IOException; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.0 * @author Mikko Tommila */ public class RawtypeApfloatBuilderTest extends RawtypeTestCase { public RawtypeApfloatBuilderTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeApfloatBuilderTest("testLongCreate")); suite.addTest(new RawtypeApfloatBuilderTest("testDoubleCreate")); suite.addTest(new RawtypeApfloatBuilderTest("testStringCreate")); suite.addTest(new RawtypeApfloatBuilderTest("testStreamCreate")); return suite; } public static void testLongCreate() { ApfloatImpl impl; ApfloatBuilder apfloatBuilder = new RawtypeApfloatBuilder(); impl = apfloatBuilder.createApfloat(5, Apfloat.INFINITE, 11); assertEquals("normal radix", 11, impl.radix()); assertEquals("normal precision", Apfloat.INFINITE, impl.precision()); assertEquals("normal String", "5", impl.toString(true)); impl = apfloatBuilder.createApfloat(6, 7, 11); assertEquals("prec radix", 11, impl.radix()); assertEquals("prec precision", 7, impl.precision()); assertEquals("prec String", "6", impl.toString(true)); try { impl = apfloatBuilder.createApfloat(7, 8, -1); fail("Invalid radix accepted"); } catch (RuntimeException re) { // OK: should not be allowed } } public static void testDoubleCreate() { ApfloatImpl impl; ApfloatBuilder apfloatBuilder = new RawtypeApfloatBuilder(); impl = apfloatBuilder.createApfloat(5.0, Apfloat.INFINITE, 11); assertEquals("normal radix", 11, impl.radix()); assertEquals("normal precision", Apfloat.INFINITE, impl.precision()); assertEquals("normal String", "5", impl.toString(true)); impl = apfloatBuilder.createApfloat(6.0, 7, 11); assertEquals("prec radix", 11, impl.radix()); assertEquals("prec precision", 7, impl.precision()); assertEquals("prec String", "6", impl.toString(true)); try { impl = apfloatBuilder.createApfloat(7.0, 8, -1); fail("Invalid radix accepted"); } catch (RuntimeException re) { // OK: should not be allowed } } public static void testStringCreate() { ApfloatImpl impl; ApfloatBuilder apfloatBuilder = new RawtypeApfloatBuilder(); impl = apfloatBuilder.createApfloat("5", Apfloat.INFINITE, 11, true); assertEquals("normal radix", 11, impl.radix()); assertEquals("normal precision", Apfloat.INFINITE, impl.precision()); assertEquals("normal String", "5", impl.toString(true)); impl = apfloatBuilder.createApfloat("6.5", 7, 11, false); assertEquals("prec radix", 11, impl.radix()); assertEquals("prec precision", 7, impl.precision()); assertEquals("prec String", "6.5", impl.toString(true)); try { impl = apfloatBuilder.createApfloat("7.0", 8, -1, false); fail("Invalid radix accepted"); } catch (RuntimeException re) { // OK: should not be allowed } try { impl = apfloatBuilder.createApfloat("7.0", 8, 9, true); fail("Invalid string accepted"); } catch (RuntimeException re) { // OK: should not be allowed } } private static PushbackReader getReader(String value) { return new PushbackReader(new StringReader(value)); } public static void testStreamCreate() throws IOException { ApfloatImpl impl; ApfloatBuilder apfloatBuilder = new RawtypeApfloatBuilder(); impl = apfloatBuilder.createApfloat(getReader("5"), Apfloat.INFINITE, 11, true); assertEquals("normal radix", 11, impl.radix()); assertEquals("normal precision", Apfloat.INFINITE, impl.precision()); assertEquals("normal String", "5", impl.toString(true)); impl = apfloatBuilder.createApfloat(getReader("6.5"), 7, 11, false); assertEquals("prec radix", 11, impl.radix()); assertEquals("prec precision", 7, impl.precision()); assertEquals("prec String", "6.5", impl.toString(true)); try { impl = apfloatBuilder.createApfloat(getReader("7.0"), 8, -1, false); fail("Invalid radix accepted"); } catch (RuntimeException re) { // OK: should not be allowed } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeApfloatImplTest.java000066400000000000000000005056731461767713300316110ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.io.Reader; import java.io.PushbackReader; import java.io.StringReader; import java.io.StringWriter; import java.io.ByteArrayOutputStream; import java.io.ByteArrayInputStream; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.IOException; import java.util.Random; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.11.0 * @author Mikko Tommila */ public class RawtypeApfloatImplTest extends RawtypeTestCase { public RawtypeApfloatImplTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeApfloatImplTest("testLongConstructor")); suite.addTest(new RawtypeApfloatImplTest("testDoubleConstructor")); suite.addTest(new RawtypeApfloatImplTest("testStringConstructor")); suite.addTest(new RawtypeApfloatImplTest("testStreamConstructor")); suite.addTest(new RawtypeApfloatImplTest("testAdd")); suite.addTest(new RawtypeApfloatImplTest("testSubtract")); suite.addTest(new RawtypeApfloatImplTest("testMultiply")); suite.addTest(new RawtypeApfloatImplTest("testIsShort")); suite.addTest(new RawtypeApfloatImplTest("testDivideShort")); suite.addTest(new RawtypeApfloatImplTest("testAbsFloor")); suite.addTest(new RawtypeApfloatImplTest("testAbsCeil")); suite.addTest(new RawtypeApfloatImplTest("testFrac")); suite.addTest(new RawtypeApfloatImplTest("testSize")); suite.addTest(new RawtypeApfloatImplTest("testNegate")); suite.addTest(new RawtypeApfloatImplTest("testDoubleValue")); suite.addTest(new RawtypeApfloatImplTest("testLongValue")); suite.addTest(new RawtypeApfloatImplTest("testEqualDigits")); suite.addTest(new RawtypeApfloatImplTest("testCompareTo")); suite.addTest(new RawtypeApfloatImplTest("testEquals")); suite.addTest(new RawtypeApfloatImplTest("testHashCode")); suite.addTest(new RawtypeApfloatImplTest("testToString")); suite.addTest(new RawtypeApfloatImplTest("testWriteTo")); suite.addTest(new RawtypeApfloatImplTest("testSerialization")); return suite; } private static String pad(String text, int length) { StringBuilder buffer = new StringBuilder(length); buffer.append(text); length -= text.length(); for (int i = 0; i < length; i++) { buffer.append('0'); } return buffer.toString(); } public static void testLongConstructor() { ApfloatImpl impl; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { impl = new RawtypeApfloatImpl(0, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " zero sign", 0, impl.signum()); assertEquals("radix " + radix + " zero precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " zero radix", radix, impl.radix()); assertEquals("radix " + radix + " zero String", "0", impl.toString(true)); impl = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " one sign", 1, impl.signum()); assertEquals("radix " + radix + " one precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " one radix", radix, impl.radix()); assertEquals("radix " + radix + " one scale", 1, impl.scale()); assertEquals("radix " + radix + " one String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " minus one sign", -1, impl.signum()); assertEquals("radix " + radix + " minus one precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " minus one radix", radix, impl.radix()); assertEquals("radix " + radix + " minus one scale", 1, impl.scale()); assertEquals("radix " + radix + " minus one String", "-1", impl.toString(true)); impl = new RawtypeApfloatImpl(Long.MAX_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " max sign", 1, impl.signum()); assertEquals("radix " + radix + " max precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " max radix", radix, impl.radix()); assertEquals("radix " + radix + " max scale", Long.toString(Long.MAX_VALUE, radix).length(), impl.scale()); assertEquals("radix " + radix + " max String", Long.toString(Long.MAX_VALUE, radix), impl.toString(true)); impl = new RawtypeApfloatImpl(-Long.MAX_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " min+1 sign", -1, impl.signum()); assertEquals("radix " + radix + " min+1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " min+1 radix", radix, impl.radix()); assertEquals("radix " + radix + " min+1 scale", Long.toString(Long.MAX_VALUE, radix).length(), impl.scale()); assertEquals("radix " + radix + " min+1 String", Long.toString(-Long.MAX_VALUE, radix), impl.toString(true)); impl = new RawtypeApfloatImpl(Long.MIN_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " min sign", -1, impl.signum()); assertEquals("radix " + radix + " min precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " min radix", radix, impl.radix()); assertEquals("radix " + radix + " min scale", Long.toString(Long.MIN_VALUE, radix).length() - 1, impl.scale()); assertEquals("radix " + radix + " min String", Long.toString(Long.MIN_VALUE, radix), impl.toString(true)); impl = new RawtypeApfloatImpl(radix * radix, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " radix^2 sign", 1, impl.signum()); assertEquals("radix " + radix + " radix^2 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " radix^2 radix", radix, impl.radix()); assertEquals("radix " + radix + " radix^2 scale", 3, impl.scale()); assertEquals("radix " + radix + " radix^2 String", "100", impl.toString(true)); impl = new RawtypeApfloatImpl(Long.MAX_VALUE, 4, radix); String expected = Long.toString(Long.MAX_VALUE, radix); expected = pad(expected.substring(0, 4), expected.length()); assertEquals("radix " + radix + " max sign", 1, impl.signum()); assertEquals("radix " + radix + " max precision", 4, impl.precision()); assertEquals("radix " + radix + " max radix", radix, impl.radix()); assertEquals("radix " + radix + " max scale", Long.toString(Long.MAX_VALUE, radix).length(), impl.scale()); assertEquals("radix " + radix + " max String", expected, impl.toString(true)); } impl = new RawtypeApfloatImpl(1000000000000000001L, 1, 10); assertEquals("truncated String", "1000000000000000000", impl.precision(Apfloat.INFINITE).toString(true)); impl = new RawtypeApfloatImpl(1, 1, 10); assertTrue("one", impl.isOne()); impl = new RawtypeApfloatImpl(-1, 1, 10); assertFalse("not one", impl.isOne()); } public static void testDoubleConstructor() { ApfloatImpl impl; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { impl = new RawtypeApfloatImpl(0.0, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " zero sign", 0, impl.signum()); assertEquals("radix " + radix + " zero precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " zero radix", radix, impl.radix()); assertEquals("radix " + radix + " zero String", "0", impl.toString(true)); impl = new RawtypeApfloatImpl(1.0, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " one sign", 1, impl.signum()); assertEquals("radix " + radix + " one precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " one radix", radix, impl.radix()); assertEquals("radix " + radix + " one scale", 1, impl.scale()); assertEquals("radix " + radix + " one String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(-1.0, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " minus one sign", -1, impl.signum()); assertEquals("radix " + radix + " minus one precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " minus one radix", radix, impl.radix()); assertEquals("radix " + radix + " minus one scale", 1, impl.scale()); assertEquals("radix " + radix + " minus one String", "-1", impl.toString(true)); impl = new RawtypeApfloatImpl(Double.MAX_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " max sign", 1, impl.signum()); assertEquals("radix " + radix + " max precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " max radix", radix, impl.radix()); impl = new RawtypeApfloatImpl(Double.MIN_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " max sign", 1, impl.signum()); assertEquals("radix " + radix + " max precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " max radix", radix, impl.radix()); impl = new RawtypeApfloatImpl(1.0 * radix * radix + 0.0000001, 1, radix); assertEquals("radix " + radix + " radix^2 sign", 1, impl.signum()); assertEquals("radix " + radix + " radix^2 precision", 1, impl.precision()); assertEquals("radix " + radix + " radix^2 radix", radix, impl.radix()); assertEquals("radix " + radix + " radix^2 scale", 3, impl.scale()); assertEquals("radix " + radix + " radix^2 String", "100", impl.toString(true)); impl = new RawtypeApfloatImpl(1.0 / radix + 0.0000001, 1, radix); assertEquals("radix " + radix + " 1/radix sign", 1, impl.signum()); assertEquals("radix " + radix + " 1/radix precision", 1, impl.precision()); assertEquals("radix " + radix + " 1/radix radix", radix, impl.radix()); assertEquals("radix " + radix + " 1/radix scale", 0, impl.scale()); assertEquals("radix " + radix + " 1/radix String", "0.1", impl.toString(true)); } impl = new RawtypeApfloatImpl(10000.1, 1, 10); assertEquals("truncated String", "10000", impl.precision(Apfloat.INFINITE).toString(true)); impl = new RawtypeApfloatImpl(Double.MAX_VALUE, Apfloat.INFINITE, 10); assertEquals("max 10 sign", 1, impl.signum()); assertEquals("max 10 scale", 309, impl.scale()); assertEquals("max 10 String length", 309, impl.toString(true).length()); assertEquals("max 10 String begin", "1797693134862315", impl.toString(true).substring(0, 16)); impl = new RawtypeApfloatImpl(Double.MIN_VALUE, Apfloat.INFINITE, 10); assertEquals("min 10 sign", 1, impl.signum()); assertEquals("min 10 scale", -323, impl.scale()); assertEquals("min 10 String begin", "0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000049", impl.toString(true).substring(0, 327)); impl = new RawtypeApfloatImpl(1.0, 2, 10); assertEquals("1 size", 1, impl.size()); impl = new RawtypeApfloatImpl(111111.0, 7, 10); assertEquals("111111 size", 6, impl.size()); try { impl = new RawtypeApfloatImpl(Double.NaN, Apfloat.INFINITE, 10); fail("NaN accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl(Double.POSITIVE_INFINITY, Apfloat.INFINITE, 10); fail("+Inf accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl(Double.NEGATIVE_INFINITY, Apfloat.INFINITE, 10); fail("-Inf accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } } public static void testStringConstructor() { ApfloatImpl impl; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { impl = new RawtypeApfloatImpl("0", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0 sign", 0, impl.signum()); assertEquals("radix " + radix + " 0 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0 String", "0", impl.toString(true)); impl = new RawtypeApfloatImpl("00", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 00 sign", 0, impl.signum()); assertEquals("radix " + radix + " 00 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 00 radix", radix, impl.radix()); assertEquals("radix " + radix + " 00 String", "0", impl.toString(true)); if (radix < 15) { impl = new RawtypeApfloatImpl("0e5", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0e5 sign", 0, impl.signum()); assertEquals("radix " + radix + " 0e5 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0e5 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0e5 String", "0", impl.toString(true)); impl = new RawtypeApfloatImpl("1E5", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1E5 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1E5 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1E5 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1E5 scale", 6, impl.scale()); assertEquals("radix " + radix + " 1E5 String", "100000", impl.toString(true)); impl = new RawtypeApfloatImpl("1E+5", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1E+5 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1E+5 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1E+5 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1E+5 scale", 6, impl.scale()); assertEquals("radix " + radix + " 1E+5 String", "100000", impl.toString(true)); impl = new RawtypeApfloatImpl("1.0E5", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.0E5 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.0E5 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1.0E5 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.0E5 scale", 6, impl.scale()); assertEquals("radix " + radix + " 1.0E5 String", "100000", impl.toString(true)); impl = new RawtypeApfloatImpl("1.1E5", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.1E5 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.1E5 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1.1E5 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.1E5 scale", 6, impl.scale()); assertEquals("radix " + radix + " 1.1E5 String", "110000", impl.toString(true)); impl = new RawtypeApfloatImpl("1.1E5", 1, radix, false); assertEquals("radix " + radix + " 1.1E5 prec1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.1E5 prec1 precision", 1, impl.precision()); assertEquals("radix " + radix + " 1.1E5 prec1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.1E5 prec1 scale", 6, impl.scale()); assertEquals("radix " + radix + " 1.1E5 prec1 String", "100000", impl.toString(true)); impl = new RawtypeApfloatImpl("1e50", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e50 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e50 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1e50 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e50 scale", 51, impl.scale()); assertEquals("radix " + radix + " 1e50 String", "100000000000000000000000000000000000000000000000000", impl.toString(true)); impl = new RawtypeApfloatImpl("1e-1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e-1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e-1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1e-1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e-1 scale", 0, impl.scale()); assertEquals("radix " + radix + " 1e-1 String", "0.1", impl.toString(true)); impl = new RawtypeApfloatImpl("1e-2", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e-2 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e-2 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1e-2 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e-2 scale", -1, impl.scale()); assertEquals("radix " + radix + " 1e-2 String", "0.01", impl.toString(true)); impl = new RawtypeApfloatImpl("1e-50", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e-50 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e-50 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1e-50 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e-50 scale", -49, impl.scale()); assertEquals("radix " + radix + " 1e-50 String", "0.00000000000000000000000000000000000000000000000001", impl.toString(true)); impl = new RawtypeApfloatImpl("0.1e" + Long.MIN_VALUE, Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.1eMIN sign", 0, impl.signum()); assertEquals("radix " + radix + " 0.1eMIN precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.1eMIN radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.1eMIN String", "0", impl.toString(true)); impl = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + 400), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.1eMIN+400 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.1eMIN+400 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.1eMIN+400 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.1eMIN+400 defaultprec scale", Long.MIN_VALUE + 401, impl.scale()); impl = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.1eMAX-400 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.1eMAX-400 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.1eMAX-400 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.1eMAX-400 defaultprec scale", Long.MAX_VALUE - 399, impl.scale()); } impl = new RawtypeApfloatImpl("1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1 scale", 1, impl.scale()); assertEquals("radix " + radix + " 1 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl("01", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 01 sign", 1, impl.signum()); assertEquals("radix " + radix + " 01 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 01 radix", radix, impl.radix()); assertEquals("radix " + radix + " 01 scale", 1, impl.scale()); assertEquals("radix " + radix + " 01 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl("1.", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1. sign", 1, impl.signum()); assertEquals("radix " + radix + " 1. precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1. radix", radix, impl.radix()); assertEquals("radix " + radix + " 1. scale", 1, impl.scale()); assertEquals("radix " + radix + " 1. String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl("1.0", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.0 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.0 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1.0 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.0 scale", 1, impl.scale()); assertEquals("radix " + radix + " 1.0 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl("01.0", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 01.0 sign", 1, impl.signum()); assertEquals("radix " + radix + " 01.0 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 01.0 radix", radix, impl.radix()); assertEquals("radix " + radix + " 01.0 scale", 1, impl.scale()); assertEquals("radix " + radix + " 01.0 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl("0.1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.1 scale", 0, impl.scale()); assertEquals("radix " + radix + " 0.1 String", "0.1", impl.toString(true)); impl = new RawtypeApfloatImpl(".1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " .1 sign", 1, impl.signum()); assertEquals("radix " + radix + " .1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " .1 radix", radix, impl.radix()); assertEquals("radix " + radix + " .1 scale", 0, impl.scale()); assertEquals("radix " + radix + " .1 String", "0.1", impl.toString(true)); impl = new RawtypeApfloatImpl("0.01", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.01 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.01 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.01 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.01 scale", -1, impl.scale()); assertEquals("radix " + radix + " 0.01 String", "0.01", impl.toString(true)); impl = new RawtypeApfloatImpl("0.01", 3, radix, false); assertEquals("radix " + radix + " 0.01 prec3 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.01 prec3 precision", 3, impl.precision()); assertEquals("radix " + radix + " 0.01 prec3 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.01 prec3 scale", -1, impl.scale()); assertEquals("radix " + radix + " 0.01 prec3 String", "0.01", impl.toString(true)); impl = new RawtypeApfloatImpl("1.01", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.01 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.01 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1.01 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.01 scale", 1, impl.scale()); assertEquals("radix " + radix + " 1.01 String", "1.01", impl.toString(true)); impl = new RawtypeApfloatImpl("-1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " -1 sign", -1, impl.signum()); assertEquals("radix " + radix + " -1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " -1 radix", radix, impl.radix()); assertEquals("radix " + radix + " -1 scale", 1, impl.scale()); assertEquals("radix " + radix + " -1 String", "-1", impl.toString(true)); impl = new RawtypeApfloatImpl("+1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " +1 sign", 1, impl.signum()); assertEquals("radix " + radix + " +1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " +1 radix", radix, impl.radix()); assertEquals("radix " + radix + " +1 scale", 1, impl.scale()); assertEquals("radix " + radix + " +1 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl("1", Apfloat.INFINITE, radix, true); assertEquals("radix " + radix + " 1 integer sign", 1, impl.signum()); assertEquals("radix " + radix + " 1 integer precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1 integer radix", radix, impl.radix()); assertEquals("radix " + radix + " 1 integer scale", 1, impl.scale()); assertEquals("radix " + radix + " 1 integer String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl("1000000000000000000000000000000000000000000000000000000001", 1, radix, false); assertEquals("radix " + radix + " 1e57+1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e57+1 precision", 1, impl.precision()); assertEquals("radix " + radix + " 1e57+1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e57+1 scale", 58, impl.scale()); assertEquals("radix " + radix + " 1e57+1 String", "1000000000000000000000000000000000000000000000000000000000", impl.toString(true)); assertEquals("radix " + radix + " 1e57+1 extended String", "1000000000000000000000000000000000000000000000000000000000", impl.precision(Apfloat.INFINITE).toString(true)); impl = new RawtypeApfloatImpl("1", Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 1 defaultprec sign", 1, impl.signum()); assertEquals("radix " + radix + " 1 defaultprec precision", 1, impl.precision()); assertEquals("radix " + radix + " 1 defaultprec radix", radix, impl.radix()); assertEquals("radix " + radix + " 1 defaultprec scale", 1, impl.scale()); assertEquals("radix " + radix + " 1 defaultprec String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl("1.0", Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 1.0 defaultprec sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.0 defaultprec precision", 2, impl.precision()); assertEquals("radix " + radix + " 1.0 defaultprec radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.0 defaultprec scale", 1, impl.scale()); assertEquals("radix " + radix + " 1.0 defaultprec String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl("01", Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 01 defaultprec sign", 1, impl.signum()); assertEquals("radix " + radix + " 01 defaultprec precision", 1, impl.precision()); assertEquals("radix " + radix + " 01 defaultprec radix", radix, impl.radix()); assertEquals("radix " + radix + " 01 defaultprec scale", 1, impl.scale()); assertEquals("radix " + radix + " 01 defaultprec String", "1", impl.toString(true)); } try { impl = new RawtypeApfloatImpl("1e0", Apfloat.INFINITE, 10, true); fail("1e0 integer accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl("1.", Apfloat.INFINITE, 10, true); fail("1. integer accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl("", Apfloat.INFINITE, 10, false); fail("empty string accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl(".", Apfloat.INFINITE, 10, false); fail(". accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl("1e", Apfloat.INFINITE, 10, false); fail("1e accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl("e1", Apfloat.INFINITE, 10, false); fail("e1 accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl("1e-", Apfloat.INFINITE, 10, false); fail("1e- accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl("-e-", Apfloat.INFINITE, 10, false); fail("-e- accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl("10e" + Long.MAX_VALUE, Apfloat.INFINITE, 10, false); fail("10eMAX accepted"); } catch (RuntimeException re) { // OK: should not be allowed } } public static void testStreamConstructor() throws IOException { ApfloatImpl impl; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { impl = new RawtypeApfloatImpl(getReader("0"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0 sign", 0, impl.signum()); assertEquals("radix " + radix + " 0 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0 String", "0", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("00"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 00 sign", 0, impl.signum()); assertEquals("radix " + radix + " 00 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 00 radix", radix, impl.radix()); assertEquals("radix " + radix + " 00 String", "0", impl.toString(true)); if (radix < 15) { impl = new RawtypeApfloatImpl(getReader("0e5"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0e5 sign", 0, impl.signum()); assertEquals("radix " + radix + " 0e5 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0e5 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0e5 String", "0", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1E5"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1E5 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1E5 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1E5 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1E5 scale", 6, impl.scale()); assertEquals("radix " + radix + " 1E5 String", "100000", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1.0E5"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.0E5 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.0E5 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1.0E5 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.0E5 scale", 6, impl.scale()); assertEquals("radix " + radix + " 1.0E5 String", "100000", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1.1E5"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.1E5 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.1E5 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1.1E5 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.1E5 scale", 6, impl.scale()); assertEquals("radix " + radix + " 1.1E5 String", "110000", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1.1E5"), 1, radix, false); assertEquals("radix " + radix + " 1.1E5 prec1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.1E5 prec1 precision", 1, impl.precision()); assertEquals("radix " + radix + " 1.1E5 prec1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.1E5 prec1 scale", 6, impl.scale()); assertEquals("radix " + radix + " 1.1E5 prec1 String", "100000", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1e50"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e50 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e50 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1e50 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e50 scale", 51, impl.scale()); assertEquals("radix " + radix + " 1e50 String", "100000000000000000000000000000000000000000000000000", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1e-1"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e-1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e-1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1e-1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e-1 scale", 0, impl.scale()); assertEquals("radix " + radix + " 1e-1 String", "0.1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1e-2"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e-2 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e-2 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1e-2 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e-2 scale", -1, impl.scale()); assertEquals("radix " + radix + " 1e-2 String", "0.01", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1e-50"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e-50 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e-50 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1e-50 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e-50 scale", -49, impl.scale()); assertEquals("radix " + radix + " 1e-50 String", "0.00000000000000000000000000000000000000000000000001", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("0.1e" + Long.MIN_VALUE), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.1eMIN sign", 0, impl.signum()); assertEquals("radix " + radix + " 0.1eMIN precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.1eMIN radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.1eMIN String", "0", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1e" + (Long.MIN_VALUE + 400)), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.1eMIN+400 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.1eMIN+400 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.1eMIN+400 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.1eMIN+400 defaultprec scale", Long.MIN_VALUE + 401, impl.scale()); impl = new RawtypeApfloatImpl(getReader("1e" + (Long.MAX_VALUE - 400)), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.1eMAX-400 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.1eMAX-400 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.1eMAX-400 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.1eMAX-400 defaultprec scale", Long.MAX_VALUE - 399, impl.scale()); } impl = new RawtypeApfloatImpl(getReader("1"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1 scale", 1, impl.scale()); assertEquals("radix " + radix + " 1 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("01"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 01 sign", 1, impl.signum()); assertEquals("radix " + radix + " 01 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 01 radix", radix, impl.radix()); assertEquals("radix " + radix + " 01 scale", 1, impl.scale()); assertEquals("radix " + radix + " 01 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1."), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1. sign", 1, impl.signum()); assertEquals("radix " + radix + " 1. precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1. radix", radix, impl.radix()); assertEquals("radix " + radix + " 1. scale", 1, impl.scale()); assertEquals("radix " + radix + " 1. String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1.0"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.0 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.0 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1.0 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.0 scale", 1, impl.scale()); assertEquals("radix " + radix + " 1.0 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("01.0"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 01.0 sign", 1, impl.signum()); assertEquals("radix " + radix + " 01.0 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 01.0 radix", radix, impl.radix()); assertEquals("radix " + radix + " 01.0 scale", 1, impl.scale()); assertEquals("radix " + radix + " 01.0 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("0.1"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.1 scale", 0, impl.scale()); assertEquals("radix " + radix + " 0.1 String", "0.1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader(".1"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " .1 sign", 1, impl.signum()); assertEquals("radix " + radix + " .1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " .1 radix", radix, impl.radix()); assertEquals("radix " + radix + " .1 scale", 0, impl.scale()); assertEquals("radix " + radix + " .1 String", "0.1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("0.01"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 0.01 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.01 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 0.01 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.01 scale", -1, impl.scale()); assertEquals("radix " + radix + " 0.01 String", "0.01", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("0.01"), 3, radix, false); assertEquals("radix " + radix + " 0.01 prec3 sign", 1, impl.signum()); assertEquals("radix " + radix + " 0.01 prec3 precision", 3, impl.precision()); assertEquals("radix " + radix + " 0.01 prec3 radix", radix, impl.radix()); assertEquals("radix " + radix + " 0.01 prec3 scale", -1, impl.scale()); assertEquals("radix " + radix + " 0.01 prec3 String", "0.01", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1.01"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.01 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.01 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1.01 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.01 scale", 1, impl.scale()); assertEquals("radix " + radix + " 1.01 String", "1.01", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("-1"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " -1 sign", -1, impl.signum()); assertEquals("radix " + radix + " -1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " -1 radix", radix, impl.radix()); assertEquals("radix " + radix + " -1 scale", 1, impl.scale()); assertEquals("radix " + radix + " -1 String", "-1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("+1"), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " +1 sign", 1, impl.signum()); assertEquals("radix " + radix + " +1 precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " +1 radix", radix, impl.radix()); assertEquals("radix " + radix + " +1 scale", 1, impl.scale()); assertEquals("radix " + radix + " +1 String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1"), Apfloat.INFINITE, radix, true); assertEquals("radix " + radix + " 1 integer sign", 1, impl.signum()); assertEquals("radix " + radix + " 1 integer precision", Apfloat.INFINITE, impl.precision()); assertEquals("radix " + radix + " 1 integer radix", radix, impl.radix()); assertEquals("radix " + radix + " 1 integer scale", 1, impl.scale()); assertEquals("radix " + radix + " 1 integer String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1000000000000000000000000000000000000000000000000000000001"), 1, radix, false); assertEquals("radix " + radix + " 1e57+1 sign", 1, impl.signum()); assertEquals("radix " + radix + " 1e57+1 precision", 1, impl.precision()); assertEquals("radix " + radix + " 1e57+1 radix", radix, impl.radix()); assertEquals("radix " + radix + " 1e57+1 scale", 58, impl.scale()); assertEquals("radix " + radix + " 1e57+1 String", "1000000000000000000000000000000000000000000000000000000000", impl.toString(true)); assertEquals("radix " + radix + " 1e57+1 extended String", "1000000000000000000000000000000000000000000000000000000000", impl.precision(Apfloat.INFINITE).toString(true)); impl = new RawtypeApfloatImpl(getReader("1"), Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 1 defaultprec sign", 1, impl.signum()); assertEquals("radix " + radix + " 1 defaultprec precision", 1, impl.precision()); assertEquals("radix " + radix + " 1 defaultprec radix", radix, impl.radix()); assertEquals("radix " + radix + " 1 defaultprec scale", 1, impl.scale()); assertEquals("radix " + radix + " 1 defaultprec String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("1.0"), Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 1.0 defaultprec sign", 1, impl.signum()); assertEquals("radix " + radix + " 1.0 defaultprec precision", 2, impl.precision()); assertEquals("radix " + radix + " 1.0 defaultprec radix", radix, impl.radix()); assertEquals("radix " + radix + " 1.0 defaultprec scale", 1, impl.scale()); assertEquals("radix " + radix + " 1.0 defaultprec String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader("01"), Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 01 defaultprec sign", 1, impl.signum()); assertEquals("radix " + radix + " 01 defaultprec precision", 1, impl.precision()); assertEquals("radix " + radix + " 01 defaultprec radix", radix, impl.radix()); assertEquals("radix " + radix + " 01 defaultprec scale", 1, impl.scale()); assertEquals("radix " + radix + " 01 defaultprec String", "1", impl.toString(true)); impl = new RawtypeApfloatImpl(getReader('1', 9 * 16383), Apfloat.INFINITE, radix, true); assertEquals("radix " + radix + " 9 * 16383 String length", 9 * 16383, impl.toString(true).length()); impl = new RawtypeApfloatImpl(getReader('1', 9 * 16384), Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 9 * 16384 String length", 9 * 16384, impl.toString(true).length()); impl = new RawtypeApfloatImpl(getReader('1', 9 * 16385), Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 9 * 16385 String length", 9 * 16385, impl.toString(true).length()); impl = new RawtypeApfloatImpl(getReader('1', 9 * 65535), Apfloat.INFINITE, radix, true); assertEquals("radix " + radix + " 9 * 65535 String length", 9 * 65535, impl.toString(true).length()); impl = new RawtypeApfloatImpl(getReader('1', 9 * 65536), Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 9 * 65536 String length", 9 * 65536, impl.toString(true).length()); impl = new RawtypeApfloatImpl(getReader('1', 9 * 65537), Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 9 * 65537 String length", 9 * 65537, impl.toString(true).length()); impl = new RawtypeApfloatImpl(getReader('1', 9 * 1048575), Apfloat.INFINITE, radix, true); assertEquals("radix " + radix + " 9 * 1048575 String length", 9 * 1048575, impl.toString(true).length()); impl = new RawtypeApfloatImpl(getReader('1', 9 * 1048576), Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 9 * 1048576 String length", 9 * 1048576, impl.toString(true).length()); impl = new RawtypeApfloatImpl(getReader('1', 9 * 1048577), Apfloat.DEFAULT, radix, false); assertEquals("radix " + radix + " 9 * 1048577 String length", 9 * 1048577, impl.toString(true).length()); } PushbackReader reader = getReader("10e-1"); impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, false); assertEquals("10e-1 size", 1, impl.size()); assertTrue("10e-1 isOne", impl.isOne()); reader = getReader("0.1e1"); impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, false); assertEquals("0.1e1 size", 1, impl.size()); assertTrue("0.1e1 isOne", impl.isOne()); reader = getReader("1e1"); impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, false); assertEquals("1e1 size", 1, impl.size()); assertFalse("1e1 isOne", impl.isOne()); reader = getReader("1.1e1"); impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, false); assertEquals("1.1e1 size", 2, impl.size()); assertFalse("1.1e1 isOne", impl.isOne()); reader = getReader("1a"); impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, false); assertEquals("1a read as is", 'a', reader.read()); assertEquals("1a read incorrectly", "1", impl.toString(true)); reader = getReader("1e0"); impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, true); assertEquals("1e0 integer read as is", 'e', reader.read()); assertEquals("1e0 integer read incorrectly", "1", impl.toString(true)); reader = getReader("1."); impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, true); assertEquals("1. integer read as is", '.', reader.read()); assertEquals("1. integer read incorrectly", "1", impl.toString(true)); // Test transition from memory allocation to disk allocation ApfloatContext ctx = ApfloatContext.getContext(); long memoryThreshold = ctx.getMemoryThreshold(); int blockSize = ctx.getBlockSize(); try { int size = 1 << 7; ctx.setMemoryThreshold(size); ctx.setBlockSize(size); Random random = new Random(); StringBuilder buffer = new StringBuilder(); buffer.append('1'); // First character(s) should not be zero digits for (int i = 0; i < 4 * size - 1; i++) { buffer.append(Character.forDigit(random.nextInt(16), 16)); } String text = buffer.toString(); reader = getReader(text); impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 16, true); assertEquals("Memory to disk transition", text, impl.toString(true)); } finally { ctx.setMemoryThreshold(memoryThreshold); ctx.setBlockSize(blockSize); } try { impl = new RawtypeApfloatImpl(getReader(""), Apfloat.INFINITE, 10, false); fail("empty string accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } try { impl = new RawtypeApfloatImpl(getReader("."), Apfloat.INFINITE, 10, false); fail(". accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } reader = getReader(".["); try { impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, false); fail(". accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed assertEquals(". read next", '[', reader.read()); } try { impl = new RawtypeApfloatImpl(getReader("1e"), Apfloat.INFINITE, 10, false); fail("1e accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } reader = getReader("e1"); try { impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, false); fail("e1 accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed assertEquals("e1 read next", 'e', reader.read()); } try { impl = new RawtypeApfloatImpl(getReader("1e-"), Apfloat.INFINITE, 10, false); fail("1e- accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed } reader = getReader("1e-["); try { impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, false); fail("1e- accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed assertEquals("1e- read next", '[', reader.read()); } reader = getReader("-e-"); try { impl = new RawtypeApfloatImpl(reader, Apfloat.INFINITE, 10, false); fail("-e- accepted"); } catch (NumberFormatException nfe) { // OK: should not be allowed assertEquals("-e- read next", 'e', reader.read()); } try { impl = new RawtypeApfloatImpl(getReader("10e" + Long.MAX_VALUE), Apfloat.INFINITE, 10, false); fail("10eMAX accepted"); } catch (RuntimeException re) { // OK: should not be allowed } } private static PushbackReader getReader(String value) { return new PushbackReader(new StringReader(value)); } private static PushbackReader getReader(char character, long size) { return new PushbackReader(new Reader() { @Override public int read() { if (this.remaining > 0 ) { this.remaining--; return character; } else { return -1; } } @Override public int read(char[] buffer, int offset, int length) { length = (int) Math.min(length, this.remaining); for (int i = 0; i < length; i++) { buffer[offset + i] = character; } this.remaining -= length; return length; } @Override public void close() {} private long remaining = size; }); } private static String getString(char character, int length) { StringBuilder buffer = new StringBuilder(length); for (int i = 0; i < length; i++) { buffer.append(character); } return buffer.toString(); } public static void testAdd() { ApfloatImpl a, b, r; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { char nine = Character.forDigit(radix - 1, radix), eight = Character.forDigit(radix - 2, radix); for (int i = 10000; i <= 10005; i++) { a = new RawtypeApfloatImpl(getString(nine, i), Apfloat.INFINITE, radix, true); b = new RawtypeApfloatImpl(getString(nine, i), Apfloat.INFINITE, radix, true); r = a.addOrSubtract(a, false); assertEquals("radix " + radix + " 9(" + i + ") * 2 precision", Apfloat.INFINITE, r.precision()); assertEquals("radix " + radix + " 9(" + i + ") * 2 String", '1' + getString(nine, i - 1) + eight, r.toString(true)); r = a.addOrSubtract(b, false); assertEquals("radix " + radix + " 9(" + i + ") + 9(" + i + ") precision", Apfloat.INFINITE, r.precision()); assertEquals("radix " + radix + " 9(" + i + ") + 9(" + i + ") String", '1' + getString(nine, i - 1) + eight, r.toString(true)); a = new RawtypeApfloatImpl(getString(nine, i), i, radix, false); b = new RawtypeApfloatImpl(getString(nine, i), i, radix, false); r = a.addOrSubtract(a, false); assertEquals("radix " + radix + " 9(" + i + ") * 2, prec precision", i + 1, r.precision()); assertEquals("radix " + radix + " 9(" + i + ") * 2, prec String", '1' + getString(nine, i - 1) + eight, r.toString(true)); r = a.addOrSubtract(b, false); assertEquals("radix " + radix + " 9(" + i + ") + 9(" + i + "), prec precision", i + 1, r.precision()); assertEquals("radix " + radix + " 9(" + i + ") + 9(" + i + "), prec String", '1' + getString(nine, i - 1) + eight, r.toString(true)); } } a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); r = a.addOrSubtract(a, false); assertEquals("1 * 2 precision", Apfloat.INFINITE, r.precision()); assertEquals("1 * 2 String", "2", r.toString(true)); a = new RawtypeApfloatImpl(1, 1, 10); r = a.addOrSubtract(a, false); assertEquals("1 * 2, prec precision", 1, r.precision()); assertEquals("1 * 2, prec String", "2", r.toString(true)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); r = a.addOrSubtract(b, false); assertEquals("1 + 1 precision", Apfloat.INFINITE, r.precision()); assertEquals("1 + 1 String", "2", r.toString(true)); a = new RawtypeApfloatImpl(1, 1, 10); b = new RawtypeApfloatImpl(1, 1, 10); r = a.addOrSubtract(b, false); assertEquals("1 + 1, prec precision", 1, r.precision()); assertEquals("1 + 1, prec String", "2", r.toString(true)); a = new RawtypeApfloatImpl(999999999, Apfloat.INFINITE, 10); r = a.addOrSubtract(a, false); assertEquals("999999999 * 2 precision", Apfloat.INFINITE, r.precision()); assertEquals("999999999 * 2 String", "1999999998", r.toString(true)); a = new RawtypeApfloatImpl(999999999, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(999999999, Apfloat.INFINITE, 10); r = a.addOrSubtract(b, false); assertEquals("999999999 + 999999999 precision", Apfloat.INFINITE, r.precision()); assertEquals("999999999 + 999999999 String", "1999999998", r.toString(true)); a = new RawtypeApfloatImpl(999999999, 9, 10); r = a.addOrSubtract(a, false); assertEquals("999999999 * 2, prec precision", 10, r.precision()); assertEquals("999999999 * 2, prec String", "1999999998", r.toString(true)); a = new RawtypeApfloatImpl(999999999, 9, 10); b = new RawtypeApfloatImpl(999999999, 9, 10); r = a.addOrSubtract(b, false); assertEquals("999999999 + 999999999, prec precision", 10, r.precision()); assertEquals("999999999 + 999999999, prec String", "1999999998", r.toString(true)); a = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, 2, false); b = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + 400), Apfloat.INFINITE, 2, false); r = a.addOrSubtract(b, false); assertEquals("max + min precision", Apfloat.INFINITE, r.precision()); assertEquals("max + min scale", Long.MAX_VALUE - 399, r.scale()); a = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), 1, 2, false); b = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + 400), 1, 2, false); r = a.addOrSubtract(b, false); assertEquals("max + min, prec precision", 1, r.precision()); assertEquals("max + min, prec scale", Long.MAX_VALUE - 399, r.scale()); a = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, 2, false); b = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, 2, false); try { for (int i = 0; i < 400; i++) { r = a.addOrSubtract(b, false); a = a.addOrSubtract(b, false); b = r; } fail("No overflow adding"); } catch (OverflowException oe) { // OK: overflow } a = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, 2, false); try { for (int i = 0; i < 400; i++) { a = a.addOrSubtract(a, false); } fail("No overflow doubling"); } catch (OverflowException are) { // OK: overflow } a = new RawtypeApfloatImpl(999999999, 9, 10); b = new RawtypeApfloatImpl(1, 1, 10); r = a.addOrSubtract(b, false); assertEquals("999999999 + 1, prec precision", 10, r.precision()); assertEquals("999999999 + 1, prec String", "1000000000", r.toString(true)); a = new RawtypeApfloatImpl(1, 1, 10); b = new RawtypeApfloatImpl(999999999, 9, 10); r = a.addOrSubtract(b, false); assertEquals("1 + 999999999, prec precision", 10, r.precision()); assertEquals("1 + 999999999, prec String", "1000000000", r.toString(true)); a = new RawtypeApfloatImpl(999999998, 9, 10); b = new RawtypeApfloatImpl(1, 1, 10); r = a.addOrSubtract(b, false); assertEquals("999999998 + 1, prec precision", 9, r.precision()); assertEquals("999999998 + 1, prec String", "999999999", r.toString(true)); a = new RawtypeApfloatImpl(9999999999L, 10, 10); b = new RawtypeApfloatImpl(1, 1, 10); r = a.addOrSubtract(b, false); assertEquals("9999999999 + 1, prec precision", 11, r.precision()); assertEquals("9999999999 + 1, prec String", "10000000000", r.toString(true)); a = new RawtypeApfloatImpl(1, 1, 10); b = new RawtypeApfloatImpl(9999999999L, 10, 10); r = a.addOrSubtract(b, false); assertEquals("1 + 9999999999, prec precision", 11, r.precision()); assertEquals("1 + 9999999999, prec String", "10000000000", r.toString(true)); a = new RawtypeApfloatImpl(-999999999, 9, 10); b = new RawtypeApfloatImpl(-1, 1, 10); r = a.addOrSubtract(b, false); assertEquals("-999999999 - 1, prec precision", 10, r.precision()); assertEquals("-999999999 - 1, prec String", "-1000000000", r.toString(true)); a = new RawtypeApfloatImpl(-1, 1, 10); b = new RawtypeApfloatImpl(-999999999, 9, 10); r = a.addOrSubtract(b, false); assertEquals("-1 - 999999999, prec precision", 10, r.precision()); assertEquals("-1 - 999999999, prec String", "-1000000000", r.toString(true)); a = new RawtypeApfloatImpl(-999999998, 9, 10); b = new RawtypeApfloatImpl(-1, 1, 10); r = a.addOrSubtract(b, false); assertEquals("-999999998 - 1, prec precision", 9, r.precision()); assertEquals("-999999998 - 1, prec String", "-999999999", r.toString(true)); a = new RawtypeApfloatImpl(-9999999999L, 10, 10); b = new RawtypeApfloatImpl(-1, 1, 10); r = a.addOrSubtract(b, false); assertEquals("-9999999999 - 1, prec precision", 11, r.precision()); assertEquals("-9999999999 - 1, prec String", "-10000000000", r.toString(true)); a = new RawtypeApfloatImpl(-1, 1, 10); b = new RawtypeApfloatImpl(-9999999999L, 10, 10); r = a.addOrSubtract(b, false); assertEquals("-1 - 9999999999, prec precision", 11, r.precision()); assertEquals("-1 - 9999999999, prec String", "-10000000000", r.toString(true)); a = new RawtypeApfloatImpl(4444444445L, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(5555555555L, Apfloat.INFINITE, 10); r = a.addOrSubtract(b, false); assertTrue("4444444445 + 5555555555, isShort", r.isShort()); assertEquals("4444444445 + 5555555555, String", "10000000000", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999999999999999999999999999999999900000000000000000000", 60, 10, false); b = new RawtypeApfloatImpl("0000000000000000000099999999999999999999999999999999999999999999999999", Apfloat.DEFAULT, 10, false); r = a.addOrSubtract(b, false); assertEquals("Partial overlap 1, prec precision", 61, r.precision()); assertEquals("Partial overlap 1, prec String", "10000000000000000000099999999999999999999999999999899999999990000000000", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999999999999999999999999999999999900000000000000000000", Apfloat.INFINITE, 10, true); b = new RawtypeApfloatImpl("0000000000000000000099999999999999999999999999999999999999999999999999", Apfloat.INFINITE, 10, true); r = a.addOrSubtract(b, false); assertEquals("Partial overlap 1 precision", Apfloat.INFINITE, r.precision()); assertEquals("Partial overlap 1 String", "10000000000000000000099999999999999999999999999999899999999999999999999", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999900000000000000000000000000000000000000000000000000", 60, 10, false); b = new RawtypeApfloatImpl("0000000000000000000000000000000000000000000000000099999999999999999999", Apfloat.DEFAULT, 10, false); r = a.addOrSubtract(b, false); assertEquals("Partial overlap 2, prec precision", 60, r.precision()); assertEquals("Partial overlap 2, prec String", "9999999999999999999900000000000000000000000000000099999999990000000000", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999900000000000000000000000000000000000000000000000000", Apfloat.INFINITE, 10, true); b = new RawtypeApfloatImpl("0000000000000000000000000000000000000000000000000099999999999999999999", Apfloat.INFINITE, 10, true); r = a.addOrSubtract(b, false); assertEquals("Partial overlap 2 precision", Apfloat.INFINITE, r.precision()); assertEquals("Partial overlap 2 String", "9999999999999999999900000000000000000000000000000099999999999999999999", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999999999999999999999999999999999999999999999999999999", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("0000000000000000000099999999999999999999999999999900000000000000000000", 40, 10, false); r = a.addOrSubtract(b, false); assertEquals("Partial overlap 3, prec precision", 61, r.precision()); assertEquals("Partial overlap 3, prec String", "10000000000000000000099999999999999999999999999999899999999990000000000", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999999999999999999999999999999999999999999999999999999", Apfloat.INFINITE, 10, true); b = new RawtypeApfloatImpl("0000000000000000000099999999999999999999999999999900000000000000000000", Apfloat.INFINITE, 10, true); r = a.addOrSubtract(b, false); assertEquals("Partial overlap 3 precision", Apfloat.INFINITE, r.precision()); assertEquals("Partial overlap 3 String", "10000000000000000000099999999999999999999999999999899999999999999999999", r.toString(true)); a = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 2, false); b = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 3, false); try { a.addOrSubtract(b, false); fail("No radix mismatch"); } catch (RadixMismatchException rme) { // OK: overflow } b = (RawType.TYPE.equals(Integer.TYPE) ? new LongApfloatImpl(0, Apfloat.INFINITE, 10) : new IntApfloatImpl(0, Apfloat.INFINITE, 10)); try { a.addOrSubtract(b, false); fail("No implementation mismatch"); } catch (ImplementationMismatchException ime) { // OK: wrong implementation class } } public static void testSubtract() { ApfloatImpl a, b, r; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { char nine = Character.forDigit(radix - 1, radix), eight = Character.forDigit(radix - 2, radix); for (int i = 10000; i <= 10005; i++) { a = new RawtypeApfloatImpl(getString(nine, i), Apfloat.INFINITE, radix, true); b = new RawtypeApfloatImpl(getString(nine, i), Apfloat.INFINITE, radix, true); r = a.addOrSubtract(b, true); assertEquals("radix " + radix + " 9(" + i + ") - 9(" + i + ") precision", Apfloat.INFINITE, r.precision()); assertEquals("radix " + radix + " 9(" + i + ") - 9(" + i + ") String", "0", r.toString(true)); a = new RawtypeApfloatImpl(getString(nine, i), i, radix, false); b = new RawtypeApfloatImpl(getString(nine, i), i, radix, false); r = a.addOrSubtract(b, true); assertEquals("radix " + radix + " 9(" + i + ") - 9(" + i + "), prec precision", Apfloat.INFINITE, r.precision()); assertEquals("radix " + radix + " 9(" + i + ") - 9(" + i + "), prec String", "0", r.toString(true)); if (radix > 2) { a = new RawtypeApfloatImpl(getString(nine, i), Apfloat.INFINITE, radix, true); b = new RawtypeApfloatImpl(getString(eight, i), Apfloat.INFINITE, radix, true); r = a.addOrSubtract(b, true); assertEquals("radix " + radix + " 9(" + i + ") - 8(" + i + ") precision", Apfloat.INFINITE, r.precision()); assertEquals("radix " + radix + " 9(" + i + ") - 8(" + i + ") String", getString('1', i), r.toString(true)); // "eight" is zero in base-2 a = new RawtypeApfloatImpl(getString(nine, i), i, radix, false); b = new RawtypeApfloatImpl(getString(eight, i), i, radix, false); r = a.addOrSubtract(b, true); assertEquals("radix " + radix + " 9(" + i + ") - 8(" + i + "), prec precision", i, r.precision()); assertEquals("radix " + radix + " 9(" + i + ") - 8(" + i + "), prec String", getString('1', i), r.toString(true)); a = new RawtypeApfloatImpl(getString(eight, i), Apfloat.INFINITE, radix, true); b = new RawtypeApfloatImpl(getString(nine, i), Apfloat.INFINITE, radix, true); r = a.addOrSubtract(b, true); assertEquals("radix " + radix + " 8(" + i + ") - 9(" + i + ") precision", Apfloat.INFINITE, r.precision()); assertEquals("radix " + radix + " 8(" + i + ") - 9(" + i + ") String", '-' + getString('1', i), r.toString(true)); a = new RawtypeApfloatImpl(getString(eight, i), i, radix, false); b = new RawtypeApfloatImpl(getString(nine, i), i, radix, false); r = a.addOrSubtract(b, true); assertEquals("radix " + radix + " 8(" + i + ") - 9(" + i + "), prec precision", i, r.precision()); assertEquals("radix " + radix + " 8(" + i + ") - 9(" + i + "), prec String", '-' + getString('1', i), r.toString(true)); } } } a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); r = a.addOrSubtract(a, true); assertEquals("1 to 0 precision", Apfloat.INFINITE, r.precision()); assertEquals("1 to 0 String", "0", r.toString(true)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); r = a.addOrSubtract(b, true); assertEquals("1 - 1 precision", Apfloat.INFINITE, r.precision()); assertEquals("1 - 1 String", "0", r.toString(true)); a = new RawtypeApfloatImpl(1, 1, 10); b = new RawtypeApfloatImpl(1, 1, 10); r = a.addOrSubtract(b, true); assertEquals("1 - 1, prec precision", Apfloat.INFINITE, r.precision()); assertEquals("1 - 1, prec String", "0", r.toString(true)); a = new RawtypeApfloatImpl(999999999, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(999999999, Apfloat.INFINITE, 10); r = a.addOrSubtract(b, true); assertEquals("999999999 - 999999999 precision", Apfloat.INFINITE, r.precision()); assertEquals("999999999 - 999999999 String", "0", r.toString(true)); a = new RawtypeApfloatImpl(999999999, 9, 10); b = new RawtypeApfloatImpl(999999999, 9, 10); r = a.addOrSubtract(b, true); assertEquals("999999999 - 999999999, prec precision", Apfloat.INFINITE, r.precision()); assertEquals("999999999 - 999999999, prec String", "0", r.toString(true)); a = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, 2, false); b = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + 400), Apfloat.INFINITE, 2, false); r = a.addOrSubtract(b, true); assertEquals("max + min precision", Apfloat.INFINITE, r.precision()); assertEquals("max + min scale", Long.MAX_VALUE - 399, r.scale()); a = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), 1, 2, false); b = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + 400), 1, 2, false); r = a.addOrSubtract(b, true); assertEquals("max + min, prec precision", 1, r.precision()); assertEquals("max + min, prec scale", Long.MAX_VALUE - 399, r.scale()); a = new RawtypeApfloatImpl("1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e" + (Long.MIN_VALUE + 400), Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e" + (Long.MIN_VALUE + 400), Apfloat.INFINITE, 10, false); r = a.addOrSubtract(b, true); assertTrue("min underflow precondition a", !a.toString().equals("1e" + (Long.MIN_VALUE + 400))); assertTrue("min underflow precondition b", !b.toString().equals("1e" + (Long.MIN_VALUE + 400))); assertEquals("min underflow precision", Apfloat.INFINITE, r.precision()); assertEquals("min underflow String", "0", r.toString(true)); a = new RawtypeApfloatImpl("1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001e" + (Long.MIN_VALUE + 400), Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002e" + (Long.MIN_VALUE + 400), Apfloat.DEFAULT, 10, false); r = a.addOrSubtract(b, true); assertTrue("min underflow, prec precondition a", !a.toString().equals("1e" + (Long.MIN_VALUE + 400))); assertTrue("min underflow, prec precondition b", !b.toString().equals("1e" + (Long.MIN_VALUE + 400))); assertEquals("min underflow, prec precision", Apfloat.INFINITE, r.precision()); assertEquals("min underflow, prec String", "0", r.toString(true)); a = new RawtypeApfloatImpl(1000000000L, 10, 10); b = new RawtypeApfloatImpl(1, 1, 10); r = a.addOrSubtract(b, true); assertEquals("1000000000 - 1, prec precision", 9, r.precision()); assertEquals("1000000000 - 1, prec String", "999999999", r.toString(true)); a = new RawtypeApfloatImpl(1, 1, 10); b = new RawtypeApfloatImpl(1000000000L, 10, 10); r = a.addOrSubtract(b, true); assertEquals("1 - 1000000000, prec precision", 9, r.precision()); assertEquals("1 - 1000000000, prec String", "-999999999", r.toString(true)); a = new RawtypeApfloatImpl(999999999, 9, 10); b = new RawtypeApfloatImpl(1, 1, 10); r = a.addOrSubtract(b, true); assertEquals("999999999 - 1, prec precision", 9, r.precision()); assertEquals("999999999 - 1, prec String", "999999998", r.toString(true)); a = new RawtypeApfloatImpl(10000000000L, 11, 10); b = new RawtypeApfloatImpl(1, 1, 10); r = a.addOrSubtract(b, true); assertEquals("10000000000 - 1, prec precision", 10, r.precision()); assertEquals("10000000000 - 1, prec String", "9999999999", r.toString(true)); a = new RawtypeApfloatImpl(1, 1, 10); b = new RawtypeApfloatImpl(10000000000L, 11, 10); r = a.addOrSubtract(b, true); assertEquals("1 - 10000000000, prec precision", 10, r.precision()); assertEquals("1 - 10000000000, prec String", "-9999999999", r.toString(true)); a = new RawtypeApfloatImpl(-1000000000L, 10, 10); b = new RawtypeApfloatImpl(-1, 1, 10); r = a.addOrSubtract(b, true); assertEquals("-1000000000 + 1, prec precision", 9, r.precision()); assertEquals("-1000000000 + 1, prec String", "-999999999", r.toString(true)); a = new RawtypeApfloatImpl(-1, 1, 10); b = new RawtypeApfloatImpl(-1000000000L, 10, 10); r = a.addOrSubtract(b, true); assertEquals("-1 + 1000000000, prec precision", 9, r.precision()); assertEquals("-1 + 1000000000, prec String", "999999999", r.toString(true)); a = new RawtypeApfloatImpl(-999999999, 9, 10); b = new RawtypeApfloatImpl(-1, 1, 10); r = a.addOrSubtract(b, true); assertEquals("-999999999 + 1, prec precision", 9, r.precision()); assertEquals("-999999999 + 1, prec String", "-999999998", r.toString(true)); a = new RawtypeApfloatImpl(-10000000000L, 11, 10); b = new RawtypeApfloatImpl(-1, 1, 10); r = a.addOrSubtract(b, true); assertEquals("-10000000000 + 1, prec precision", 10, r.precision()); assertEquals("-10000000000 + 1, prec String", "-9999999999", r.toString(true)); a = new RawtypeApfloatImpl(-1, 1, 10); b = new RawtypeApfloatImpl(-10000000000L, 11, 10); r = a.addOrSubtract(b, true); assertEquals("-1 + 10000000000, prec precision", 10, r.precision()); assertEquals("-1 + 10000000000, prec String", "9999999999", r.toString(true)); a = new RawtypeApfloatImpl(999999999, 9, 10); b = new RawtypeApfloatImpl(999999998, 9, 10); r = a.addOrSubtract(b, true); assertEquals("999999999 - 999999998, limited precision precision", 1, r.precision()); assertEquals("999999999 - 999999998, limited precision String", "1", r.toString(true)); a = new RawtypeApfloatImpl(999923456, 9, 10); b = new RawtypeApfloatImpl(999912345, 9, 10); r = a.addOrSubtract(b, true); assertEquals("999923456 - 999912345, limited precision precision", 5, r.precision()); assertEquals("999923456 - 999912345, limited precision String", "11111", r.toString(true)); a = new RawtypeApfloatImpl(923456789, 9, 10); b = new RawtypeApfloatImpl(912345678, 9, 10); r = a.addOrSubtract(b, true); assertEquals("923456789 - 912345678, limited precision precision", 8, r.precision()); assertEquals("923456789 - 912345678, limited precision String", "11111111", r.toString(true)); a = new RawtypeApfloatImpl(9999999999L, 10, 10); b = new RawtypeApfloatImpl(9999999998L, 10, 10); r = a.addOrSubtract(b, true); assertEquals("9999999999 - 9999999998, limited precision precision", 1, r.precision()); assertEquals("9999999999 - 9999999998, limited precision String", "1", r.toString(true)); a = new RawtypeApfloatImpl(9999923456L, 10, 10); b = new RawtypeApfloatImpl(9999912345L, 10, 10); r = a.addOrSubtract(b, true); assertEquals("9999923456 - 9999912345, limited precision precision", 5, r.precision()); assertEquals("9999923456 - 9999912345, limited precision String", "11111", r.toString(true)); a = new RawtypeApfloatImpl(9234567899L, 10, 10); b = new RawtypeApfloatImpl(9123456788L, 10, 10); r = a.addOrSubtract(b, true); assertEquals("9234567899 - 9123456788, limited precision precision", 9, r.precision()); assertEquals("9234567899 - 9123456788, limited precision String", "111111111", r.toString(true)); a = new RawtypeApfloatImpl(999999999, 1, 10); b = new RawtypeApfloatImpl(999999998, 1, 10); r = a.addOrSubtract(b, true); assertEquals("999999999 - 999999998, lost precision precision", Apfloat.INFINITE, r.precision()); assertEquals("999999999 - 999999998, lost precision String", "0", r.toString(true)); a = new RawtypeApfloatImpl(999923456, 4, 10); b = new RawtypeApfloatImpl(999912345, 4, 10); r = a.addOrSubtract(b, true); assertEquals("999923456 - 999912345, lost precision precision", Apfloat.INFINITE, r.precision()); assertEquals("999923456 - 999912345, lost precision String", "0", r.toString(true)); a = new RawtypeApfloatImpl(9999999999L, 2, 10); b = new RawtypeApfloatImpl(9999999998L, 2, 10); r = a.addOrSubtract(b, true); assertEquals("9999999999 - 9999999998, lost precision precision", Apfloat.INFINITE, r.precision()); assertEquals("9999999999 - 9999999998, lost precision String", "0", r.toString(true)); a = new RawtypeApfloatImpl(9999923456L, 5, 10); b = new RawtypeApfloatImpl(9999912345L, 5, 10); r = a.addOrSubtract(b, true); assertEquals("9999923456 - 9999912345, lost precision precision", Apfloat.INFINITE, r.precision()); assertEquals("9999923456 - 9999912345, lost precision String", "0", r.toString(true)); a = new RawtypeApfloatImpl(9999999999L, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(999999999L, Apfloat.INFINITE, 10); r = a.addOrSubtract(b, true); assertTrue("9999999999 - 999999999, isShort", r.isShort()); assertEquals("9999999999 - 999999999, String", "9000000000", r.toString(true)); a = new RawtypeApfloatImpl(1000000000, 2, 10); b = new RawtypeApfloatImpl(990000000, 1, 10); r = a.addOrSubtract(b, true); assertEquals("1000000000 - 990000000, lost precision precision", Apfloat.INFINITE, r.precision()); assertEquals("1000000000 - 990000000, lost precision String", "0", r.toString(true)); a = new RawtypeApfloatImpl(1000000000, 2, 10); b = new RawtypeApfloatImpl(999999999, 1, 10); r = a.addOrSubtract(b, true); assertEquals("1000000000 - 999999999, lost precision precision", Apfloat.INFINITE, r.precision()); assertEquals("1000000000 - 999999999, lost precision String", "0", r.toString(true)); a = new RawtypeApfloatImpl("9999999999000000000099999999999999999999999999999900000000000000000000", 60, 10, false); b = new RawtypeApfloatImpl("0000000000000000000099999999999999999999999999999999999999999999999999", Apfloat.DEFAULT, 10, false); r = a.addOrSubtract(b, true); assertEquals("Partial overlap 1, prec precision", 60, r.precision()); assertEquals("Partial overlap 1, prec String", "9999999998999999999999999999999999999999999999999900000000000000000000", r.toString(true)); a = new RawtypeApfloatImpl("9999999999000000000099999999999999999999999999999900000000000000000000", Apfloat.INFINITE, 10, true); b = new RawtypeApfloatImpl("0000000000000000000099999999999999999999999999999999999999999999999999", Apfloat.INFINITE, 10, true); r = a.addOrSubtract(b, true); assertEquals("Partial overlap 1 precision", Apfloat.INFINITE, r.precision()); assertEquals("Partial overlap 1 String", "9999999998999999999999999999999999999999999999999900000000000000000001", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999900000000000000000000000000000000000000000000000000", 60, 10, false); b = new RawtypeApfloatImpl("0000000000000000000000000000000000000000000000000099999999999999999999", Apfloat.DEFAULT, 10, false); r = a.addOrSubtract(b, true); assertEquals("Partial overlap 2, prec precision", 60, r.precision()); assertEquals("Partial overlap 2, prec String", "9999999999999999999899999999999999999999999999999900000000000000000000", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999900000000000000000000000000000000000000000000000000", Apfloat.INFINITE, 10, true); b = new RawtypeApfloatImpl("0000000000000000000000000000000000000000000000000099999999999999999999", Apfloat.INFINITE, 10, true); r = a.addOrSubtract(b, true); assertEquals("Partial overlap 2 precision", Apfloat.INFINITE, r.precision()); assertEquals("Partial overlap 2 String", "9999999999999999999899999999999999999999999999999900000000000000000001", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999900000000009999999999999999999999999999999999999999", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("0000000000000000000099999999999999999999999999999900000000000000000000", 40, 10, false); r = a.addOrSubtract(b, true); assertEquals("Partial overlap 3, prec precision", 60, r.precision()); assertEquals("Partial overlap 3, prec String", "9999999999999999999800000000010000000000000000000099999999990000000000", r.toString(true)); a = new RawtypeApfloatImpl("9999999999999999999900000000009999999999999999999999999999999999999999", Apfloat.INFINITE, 10, true); b = new RawtypeApfloatImpl("0000000000000000000099999999999999999999999999999900000000000000000000", Apfloat.INFINITE, 10, true); r = a.addOrSubtract(b, true); assertEquals("Partial overlap 3 precision", Apfloat.INFINITE, r.precision()); assertEquals("Partial overlap 3 String", "9999999999999999999800000000010000000000000000000099999999999999999999", r.toString(true)); a = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 2, false); b = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 3, false); try { a.addOrSubtract(b, true); fail("No radix mismatch"); } catch (RadixMismatchException rme) { // OK: overflow } } public static void testMultiply() { ApfloatContext.getContext().setMemoryThreshold(1 << 30); // To improve performance and stability... ApfloatImpl a, b; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { a = new RawtypeApfloatImpl(0, Apfloat.INFINITE, radix); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " 0 * 1", "0", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " 1 * 1", "1", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); b = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " 1 * -1", "-1", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, radix); b = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " -1 * 1.1", "-1.1", a.multiply(b).toString(true)); if (radix < 15) { a = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + 400), Apfloat.INFINITE, radix, false); b = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + 400), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " e * e", "0", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE / 2), Apfloat.INFINITE, radix, false); b = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE / 2), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " e * e just", "0", a.multiply(b).toString(false)); a = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, radix, false); b = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, radix, false); try { a.multiply(b); fail("radix " + radix + " no overflow"); } catch (OverflowException oe) { // OK: overflow } } char nine = Character.forDigit(radix - 1, radix), eight = Character.forDigit(radix - 2, radix); for (int i = 2; i <= 131072; i *= 2) { a = new RawtypeApfloatImpl(getString(nine, i), Apfloat.INFINITE, radix, false); for (int j = 2; j <= i; j *= 2) { String expected = getString(nine, j - 1) + eight + getString(nine, i - j) + getString('0', j - 1) + '1'; b = new RawtypeApfloatImpl(getString(nine, j), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 9(" + i + ") * 9(" + j + ")", expected, a.multiply(b).toString(true)); if (j == i) { assertEquals("radix " + radix + " 9(" + i + ")^2", expected, a.multiply(a).toString(true)); } } } for (int i = 10000; i <= 10005; i++) { a = new RawtypeApfloatImpl(getString(nine, i), i, radix, false); b = new RawtypeApfloatImpl(getString(nine, i), i, radix, false); assertEquals("radix " + radix + " 9(" + i + ") * 9(" + i + "), prec", getString(nine, i - 2), a.multiply(b).toString(true).substring(0, i - 2)); } } a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1", 16, 10, false); assertEquals("1234567890123456 * 1", "1234567890123456", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10", 16, 10, false); assertEquals("1234567890123456 * 10", "12345678901234560", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100", 16, 10, false); assertEquals("1234567890123456 * 100", "123456789012345600", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1000", 16, 10, false); assertEquals("1234567890123456 * 1000", "1234567890123456000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10000", 16, 10, false); assertEquals("1234567890123456 * 10000", "12345678901234560000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100000", 16, 10, false); assertEquals("1234567890123456 * 100000", "123456789012345600000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1000000", 16, 10, false); assertEquals("1234567890123456 * 1000000", "1234567890123456000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10000000", 16, 10, false); assertEquals("1234567890123456 * 10000000", "12345678901234560000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100000000", 16, 10, false); assertEquals("1234567890123456 * 100000000", "123456789012345600000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1000000000", 16, 10, false); assertEquals("1234567890123456 * 1000000000", "1234567890123456000000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10000000000", 16, 10, false); assertEquals("1234567890123456 * 10000000000", "12345678901234560000000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100000000000", 16, 10, false); assertEquals("1234567890123456 * 100000000000", "123456789012345600000000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1000000000000", 16, 10, false); assertEquals("1234567890123456 * 1000000000000", "1234567890123456000000000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10000000000000", 16, 10, false); assertEquals("1234567890123456 * 10000000000000", "12345678901234560000000000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100000000000000", 16, 10, false); assertEquals("1234567890123456 * 100000000000000", "123456789012345600000000000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 3); b = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 3); assertEquals("1 * 2", "2", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("aaa", Apfloat.INFINITE, 11, true); b = new RawtypeApfloatImpl("aaa", Apfloat.INFINITE, 11, true); assertEquals("aaa * aaa", "aa9001", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("9999999999999999999999999999999999999999", Apfloat.INFINITE, 10, true); b = new RawtypeApfloatImpl("9999999999999999999999999999999999999999", Apfloat.INFINITE, 10, true); assertEquals("1e40-1 * 1e40-1", "99999999999999999999999999999999999999980000000000000000000000000000000000000001", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); assertEquals("1.1 * 1.1", "1.21", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl(999999999, 8, 10); b = new RawtypeApfloatImpl(999999999, 8, 10); assertEquals("999999999 * 999999999, prec", "999999990000000000", a.multiply(b).toString(true)); assertEquals("999999999^2, prec", "999999990000000000", a.multiply(a).toString(true)); // Underflow a = new RawtypeApfloatImpl("1e-9000000000000000000", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1e-9000000000000000000", Apfloat.INFINITE, 10, false); assertEquals("1e-9000000000000000000 * 1e-9000000000000000000", "0", a.multiply(b).toString(true)); if (a instanceof IntApfloatImpl) { a = new RawtypeApfloatImpl("d3eafc3af14601", 14, 16, false); b = new RawtypeApfloatImpl("13540775b48cc32ba01", 19, 16, false); assertTrue("Fermat number, prec3 isShort", a.multiply(b).isShort()); assertEquals("Fermat number, prec3", "100000000000000000000000000000000", a.multiply(b).toString(true)); a = new RawtypeApfloatImpl("d3eafc3af14601", 21, 16, false); b = new RawtypeApfloatImpl("13540775b48cc32ba01", 21, 16, false); assertTrue("Fermat number, prec4 isShort", a.multiply(b).isShort()); assertEquals("Fermat number, prec4", "100000000000000000000000000000000", a.multiply(b).toString(true)); } a = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 2, false); b = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 3, false); try { a.multiply(b); fail("No radix mismatch"); } catch (RadixMismatchException rme) { // OK: overflow } b = (RawType.TYPE.equals(Integer.TYPE) ? new LongApfloatImpl(0, Apfloat.INFINITE, 10) : new IntApfloatImpl(0, Apfloat.INFINITE, 10)); try { a.multiply(b); fail("No implementation mismatch"); } catch (ImplementationMismatchException ime) { // OK: wrong implementation class } } public static void testIsShort() { ApfloatImpl impl = new RawtypeApfloatImpl(5, 2, 10); assertTrue("5", impl.isShort()); impl = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); assertTrue("0", impl.isShort()); impl = new RawtypeApfloatImpl("1111111111111111111111111111111111111111111111111111111111111111111111", Apfloat.DEFAULT, 10, false); assertTrue("1...e70", !impl.isShort()); } public static void testDivideShort() { ApfloatImpl a, b; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " 1 / 1", "1", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); b = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " 1 / -1", "-1", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("11", 2, radix, true); b = new RawtypeApfloatImpl("11", 2, radix, true); assertEquals("radix " + radix + " 11 / 11", "1", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(67, 1, radix); b = new RawtypeApfloatImpl(37, 1, radix); assertEquals("radix " + radix + " 67 / 37", "1", a.divideShort(b).toString(true)); if (radix < 15) { a = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + 400), Apfloat.INFINITE, radix, false); b = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " min / max", "0", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE / 2), Apfloat.INFINITE, radix, false); b = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE / 2), Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " min / max just", "0", a.divideShort(b).toString(false)); a = new RawtypeApfloatImpl("1e" + (Long.MAX_VALUE - 400), Apfloat.INFINITE, radix, false); b = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + 400), Apfloat.INFINITE, radix, false); try { a.divideShort(b); fail("radix " + radix + " no overflow"); } catch (OverflowException oe) { // OK: overflow } } char nine = Character.forDigit(radix - 1, radix); for (int i = 10000; i <= 10005; i++) { a = new RawtypeApfloatImpl(getString(nine, i), i, radix, false); b = new RawtypeApfloatImpl(getString(nine, 1), i, radix, false); assertEquals("radix " + radix + " 9(" + i + ") / 9, prec", getString('1', i), a.divideShort(b).toString(true)); } a = new RawtypeApfloatImpl(getString(nine, 10) + '.' + nine, Apfloat.INFINITE, radix, false); b = new RawtypeApfloatImpl(1, 11, radix); assertEquals("radix " + radix + " 9999999999.9 / 1, prec", getString(nine, 10) + '.' + nine, a.divideShort(b).toString(true)); assertEquals("radix " + radix + " 9999999999.9 / 1 precision", 11, a.divideShort(b).precision()); } a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1", 16, 10, false); assertEquals("1.234567890123456 / 1", "1.234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10", 16, 10, false); assertEquals("1.234567890123456 / 10", "0.1234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100", 16, 10, false); assertEquals("1.234567890123456 / 100", "0.01234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1000", 16, 10, false); assertEquals("1.234567890123456 / 1000", "0.001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10000", 16, 10, false); assertEquals("1.234567890123456 / 10000", "0.0001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100000", 16, 10, false); assertEquals("1.234567890123456 / 100000", "0.00001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1000000", 16, 10, false); assertEquals("1.234567890123456 / 1000000", "0.000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10000000", 16, 10, false); assertEquals("1.234567890123456 / 10000000", "0.0000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100000000", 16, 10, false); assertEquals("1.234567890123456 / 100000000", "0.00000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1000000000", 16, 10, false); assertEquals("1.234567890123456 / 1000000000", "0.000000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10000000000", 16, 10, false); assertEquals("1.234567890123456 / 10000000000", "0.0000000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100000000000", 16, 10, false); assertEquals("1.234567890123456 / 100000000000", "0.00000000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1000000000000", 16, 10, false); assertEquals("1.234567890123456 / 1000000000000", "0.000000000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("10000000000000", 16, 10, false); assertEquals("1.234567890123456 / 10000000000000", "0.0000000000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("100000000000000", 16, 10, false); assertEquals("1.234567890123456 / 100000000000000", "0.00000000000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl("1.234567890123456", 16, 10, false); b = new RawtypeApfloatImpl("1000000000000000", 16, 10, false); assertEquals("1.234567890123456 / 1000000000000000", "0.000000000000001234567890123456", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(2, 50, 10); b = new RawtypeApfloatImpl(3, 50, 10); assertEquals("2 / 3", "0.66666666666666666666666666666666666666666666666666", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(3, 50, 20); b = new RawtypeApfloatImpl(6, 50, 20); assertTrue("3 / 6 isShort", a.divideShort(b).isShort()); assertEquals("3 / 6 String", "0.a", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(6, 50, 7); b = new RawtypeApfloatImpl(3, 50, 7); assertTrue("6 / 3 isShort", a.divideShort(b).isShort()); assertEquals("6 / 3", "2", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(5, Apfloat.INFINITE, 10); assertEquals("2 / 5", "0.4", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(5, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); assertEquals("5 / 2", "2.5", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(8388608, Apfloat.INFINITE, 10); assertEquals("1 / 8388608", "0.00000011920928955078125", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(9765625, Apfloat.INFINITE, 10); assertEquals("1 / 9765625", "0.0000001024", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(10000000, Apfloat.INFINITE, 10); assertEquals("1 / 10000000", "0.0000001", a.divideShort(b).toString(true)); // Underflow a = new RawtypeApfloatImpl("1e-9000000000000000000", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("2e9000000000000000000", Apfloat.INFINITE, 10, false); assertEquals("1e-9000000000000000000 / 2e9000000000000000000", "0", a.divideShort(b).toString(true)); a = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(3, Apfloat.INFINITE, 10); try { a.divideShort(b); fail("Infinite expansion allowed"); } catch (InfiniteExpansionException iee) { // OK: would be an infinite expansion } a = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 2, false); b = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 3, false); try { a.divideShort(b); fail("No radix mismatch"); } catch (RadixMismatchException rme) { // OK: overflow } b = (RawType.TYPE.equals(Integer.TYPE) ? new LongApfloatImpl(0, Apfloat.INFINITE, 10) : new IntApfloatImpl(0, Apfloat.INFINITE, 10)); try { a.divideShort(b); fail("No implementation mismatch"); } catch (ImplementationMismatchException ime) { // OK: wrong implementation class } } public static void testAbsFloor() { ApfloatImpl impl; impl = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); assertEquals("zero", "0", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl(1, 1, 10); assertEquals("one precision", Apfloat.INFINITE, impl.absFloor().precision()); assertEquals("one", "1", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl(-1, 1, 10); assertEquals("minus one precision", Apfloat.INFINITE, impl.absFloor().precision()); assertEquals("minus one", "-1", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("1.1", Apfloat.DEFAULT, 10, false); assertEquals("1.1", "1", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("-1.1", Apfloat.DEFAULT, 10, false); assertEquals("-1.1", "-1", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("999999999.999999999999999999", Apfloat.INFINITE, 10, false); assertEquals("999999999.999999999999999999", "999999999", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("-999999999.999999999999999999", Apfloat.INFINITE, 10, false); assertEquals("-999999999.999999999999999999", "-999999999", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("1000000000.0000000001", Apfloat.INFINITE, 10, false); assertEquals("1000000000.0000000001", "1000000000", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("-1000000000.0000000001", Apfloat.INFINITE, 10, false); assertEquals("-1000000000.0000000001", "-1000000000", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("10000000000000000000000000000000000000000000000000000000000000000000000", Apfloat.INFINITE, 10, false); assertEquals("1e70", "10000000000000000000000000000000000000000000000000000000000000000000000", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("-10000000000000000000000000000000000000000000000000000000000000000000000", Apfloat.INFINITE, 10, false); assertEquals("-1e70", "-10000000000000000000000000000000000000000000000000000000000000000000000", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("0.1", Apfloat.INFINITE, 10, false); assertEquals("0.1", "0", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("-0.1", Apfloat.INFINITE, 10, false); assertEquals("-0.1", "0", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("1e-50", Apfloat.INFINITE, 10, false); assertEquals("1e-50", "0", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("-1e-50", Apfloat.INFINITE, 10, false); assertEquals("-1e-50", "0", impl.absFloor().toString(true)); impl = new RawtypeApfloatImpl("200000000000000", Apfloat.INFINITE, 10, false); assertEquals("200000000000000 infinite", "200000000000000", impl.absFloor().toString(true)); assertEquals("200000000000000 infinite, prec", Apfloat.INFINITE, impl.absFloor().precision()); impl = new RawtypeApfloatImpl("200000000000000", 50, 10, false); assertEquals("200000000000000 50", "200000000000000", impl.absFloor().toString(true)); assertEquals("200000000000000 50, prec", Apfloat.INFINITE, impl.absFloor().precision()); impl = new RawtypeApfloatImpl("200000000000000.1", Apfloat.INFINITE, 10, false).precision(15); assertEquals("200000000000000.1 15", "200000000000000", impl.absFloor().toString(true)); assertEquals("200000000000000.1 15, prec", Apfloat.INFINITE, impl.absFloor().precision()); } public static void testAbsCeil() { ApfloatImpl impl; impl = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); assertEquals("zero", "0", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl(1, 1, 10); assertEquals("one precision", Apfloat.INFINITE, impl.absCeil().precision()); assertEquals("one", "1", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl(-1, 1, 10); assertEquals("minus one precision", Apfloat.INFINITE, impl.absCeil().precision()); assertEquals("minus one", "-1", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("1.1", Apfloat.DEFAULT, 10, false); assertEquals("1.1", "2", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("-1.1", Apfloat.DEFAULT, 10, false); assertEquals("-1.1", "-2", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("999999999.999999999999999999", Apfloat.INFINITE, 10, false); assertEquals("999999999.999999999999999999", "1000000000", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("-999999999.999999999999999999", Apfloat.INFINITE, 10, false); assertEquals("-999999999.999999999999999999", "-1000000000", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("1000000000.0000000001", Apfloat.INFINITE, 10, false); assertEquals("1000000000.0000000001", "1000000001", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("-1000000000.0000000001", Apfloat.INFINITE, 10, false); assertEquals("-1000000000.0000000001", "-1000000001", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("10000000000000000000000000000000000000000000000000000000000000000000000", Apfloat.INFINITE, 10, false); assertEquals("1e70", "10000000000000000000000000000000000000000000000000000000000000000000000", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("-10000000000000000000000000000000000000000000000000000000000000000000000", Apfloat.INFINITE, 10, false); assertEquals("-1e70", "-10000000000000000000000000000000000000000000000000000000000000000000000", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("0.1", Apfloat.INFINITE, 10, false); assertEquals("0.1", "1", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("-0.1", Apfloat.INFINITE, 10, false); assertEquals("-0.1", "-1", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("1e-50", Apfloat.INFINITE, 10, false); assertEquals("1e-50", "1", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("-1e-50", Apfloat.INFINITE, 10, false); assertEquals("-1e-50", "-1", impl.absCeil().toString(true)); impl = new RawtypeApfloatImpl("200000000000000", Apfloat.INFINITE, 10, false); assertEquals("200000000000000 infinite", "200000000000000", impl.absCeil().toString(true)); assertEquals("200000000000000 infinite, prec", Apfloat.INFINITE, impl.absCeil().precision()); impl = new RawtypeApfloatImpl("200000000000000", 50, 10, false); assertEquals("200000000000000 50", "200000000000000", impl.absCeil().toString(true)); assertEquals("200000000000000 50, prec", Apfloat.INFINITE, impl.absCeil().precision()); impl = new RawtypeApfloatImpl("200000000000000.1", Apfloat.INFINITE, 10, false).precision(15); assertEquals("200000000000000.1 15", "200000000000000", impl.absCeil().toString(true)); assertEquals("200000000000000.1 15, prec", Apfloat.INFINITE, impl.absCeil().precision()); } public static void testFrac() { ApfloatImpl impl; impl = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); assertEquals("zero", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl(1, 1, 10); assertEquals("one", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl(-1, 1, 10); assertEquals("minus one", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("1.1", Apfloat.DEFAULT, 10, false); assertEquals("1.1 precision", 1, impl.frac().precision()); assertEquals("1.1", "0.1", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("-1.1", Apfloat.DEFAULT, 10, false); assertEquals("-1.1 precision", 1, impl.frac().precision()); assertEquals("-1.1", "-0.1", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("999999999.999999999999999999", Apfloat.INFINITE, 10, false); assertEquals("999999999.999999999999999999 precision", Apfloat.INFINITE, impl.frac().precision()); assertEquals("999999999.999999999999999999", "0.999999999999999999", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("-999999999.999999999999999999", Apfloat.INFINITE, 10, false); assertEquals("-999999999.999999999999999999 precision", Apfloat.INFINITE, impl.frac().precision()); assertEquals("-999999999.999999999999999999", "-0.999999999999999999", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("1000000000.0000000001", Apfloat.DEFAULT, 10, false); assertEquals("1000000000.0000000001 precision", 1, impl.frac().precision()); assertEquals("1000000000.0000000001", "0.0000000001", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("-1000000000.0000000001", Apfloat.DEFAULT, 10, false); assertEquals("-1000000000.0000000001 precision", 1, impl.frac().precision()); assertEquals("-1000000000.0000000001", "-0.0000000001", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("10000000000000000000000000000000000000000000000000000000000000000000000", Apfloat.INFINITE, 10, false); assertEquals("1e70", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("-10000000000000000000000000000000000000000000000000000000000000000000000", Apfloat.INFINITE, 10, false); assertEquals("-1e70", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("0.1", Apfloat.INFINITE, 10, false); assertEquals("0.1", "0.1", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("-0.1", Apfloat.INFINITE, 10, false); assertEquals("-0.1", "-0.1", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("1e-50", Apfloat.INFINITE, 10, false); assertEquals("1e-50", "1e-50", impl.frac().toString(false)); impl = new RawtypeApfloatImpl("-1e-50", Apfloat.INFINITE, 10, false); assertEquals("-1e-50", "-1e-50", impl.frac().toString(false)); impl = new RawtypeApfloatImpl("100000000000000.0000000001", Apfloat.INFINITE, 10, false).precision(5); assertEquals("100000000000000.0000000001 5", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("100000000000000.0000000001", Apfloat.INFINITE, 10, false).precision(25); assertEquals("100000000000000.0000000001 25", "0.0000000001", impl.frac().toString(true)); assertEquals("100000000000000.0000000001 25, prec", 1, impl.frac().precision()); impl = new RawtypeApfloatImpl("100000000000000.0000000001", Apfloat.INFINITE, 10, false).precision(24); assertEquals("100000000000000.0000000001 24", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("100000000000000.000000001", Apfloat.INFINITE, 10, false).precision(24); assertEquals("100000000000000.000000001 24", "0.000000001", impl.frac().toString(true)); assertEquals("100000000000000.000000001 24, prec", 1, impl.frac().precision()); impl = new RawtypeApfloatImpl("100000000000000.000000001", Apfloat.INFINITE, 10, false).precision(23); assertEquals("100000000000000.000000001 23", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("10000000000000.000000001", Apfloat.INFINITE, 10, false).precision(23); assertEquals("10000000000000.000000001 23", "0.000000001", impl.frac().toString(true)); assertEquals("10000000000000.000000001 23, prec", 1, impl.frac().precision()); impl = new RawtypeApfloatImpl("10000000000000.000000001", Apfloat.INFINITE, 10, false).precision(22); assertEquals("10000000000000.000000001 22", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("1000000000.0000000001", Apfloat.INFINITE, 10, false).precision(1); assertEquals("1000000000.0000000001 1", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("1000000000.0000000001", Apfloat.INFINITE, 10, false).precision(9); assertEquals("1000000000.0000000001 9", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("1000000000.0000000001", Apfloat.INFINITE, 10, false).precision(10); assertEquals("1000000000.0000000001 10", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("1000000000.0000000001", Apfloat.INFINITE, 10, false).precision(11); assertEquals("1000000000.0000000001 11", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("1000000000.0000000001", Apfloat.INFINITE, 10, false).precision(19); assertEquals("1000000000.0000000001 19", "0", impl.frac().toString(true)); impl = new RawtypeApfloatImpl("1000000000.0000000001", Apfloat.INFINITE, 10, false).precision(20); assertEquals("1000000000.0000000001 20", "0.0000000001", impl.frac().toString(true)); assertEquals("1000000000.0000000001 20, prec", 1, impl.frac().precision()); } public static void testSize() { ApfloatImpl impl = new RawtypeApfloatImpl(1010000, Apfloat.INFINITE, 10); assertEquals("1010000", 3, impl.size()); impl = new RawtypeApfloatImpl("10000000000000000000000000000000000000001", Apfloat.INFINITE, 10, true); assertEquals("10000000000000000000000000000000000000001", 41, impl.size()); impl = impl.precision(40); assertEquals("10000000000000000000000000000000000000001 prec 40", 1, impl.size()); } public static void testNegate() { ApfloatImpl impl = new RawtypeApfloatImpl(5, Apfloat.INFINITE, 10); assertEquals("-5", "-5", impl.negate().toString(true)); impl = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); assertEquals("0", "0", impl.negate().toString(true)); } public static void testDoubleValue() { ApfloatImpl impl; double e1 = 1.0 - 2.0 * Math.ulp(1.0); // 1 minus two epsilons for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { impl = new RawtypeApfloatImpl(0, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " zero", 0.0, impl.doubleValue(), 0.0); impl = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " one", 1.0, impl.doubleValue(), 2e-15); impl = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " minus one", -1.0, impl.doubleValue(), 2e-15); impl = new RawtypeApfloatImpl(e1 * Double.MAX_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " max", Double.MAX_VALUE, impl.doubleValue(), 2e293); impl = new RawtypeApfloatImpl(-e1 * Double.MAX_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " -max", -Double.MAX_VALUE, impl.doubleValue(), 2e293); impl = new RawtypeApfloatImpl(Double.MIN_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " min", Double.MIN_VALUE, impl.doubleValue(), Double.MIN_VALUE); impl = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.1", 1.0 + 1.0 / radix, impl.doubleValue(), 2e-15); impl = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " -1.1", -1.0 - 1.0 / radix, impl.doubleValue(), 2e-15); if (radix < 15) { impl = new RawtypeApfloatImpl("1e10000", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e10000", Double.POSITIVE_INFINITY, impl.doubleValue(), 0.0); impl = new RawtypeApfloatImpl("-1e10000", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " -1e10000", Double.NEGATIVE_INFINITY, impl.doubleValue(), 0.0); } } impl = new RawtypeApfloatImpl("1.797693134862317E308", Apfloat.INFINITE, 10, false); assertEquals("max+1", Double.POSITIVE_INFINITY, impl.doubleValue(), 0.0); impl = new RawtypeApfloatImpl("-1.797693134862317E308", Apfloat.INFINITE, 10, false); assertEquals("-max+1", Double.NEGATIVE_INFINITY, impl.doubleValue(), 0.0); impl = new RawtypeApfloatImpl("2.4E-324", Apfloat.INFINITE, 10, false); assertEquals("min-1", 0.0, impl.doubleValue(), 0.0); } public static void testLongValue() { ApfloatImpl impl; for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { impl = new RawtypeApfloatImpl(0, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " zero", 0, impl.longValue()); impl = new RawtypeApfloatImpl(1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " one", 1, impl.longValue()); impl = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " minus one", -1, impl.longValue()); impl = new RawtypeApfloatImpl(Long.MAX_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " max", Long.MAX_VALUE, impl.longValue()); impl = new RawtypeApfloatImpl(Long.MIN_VALUE, Apfloat.INFINITE, radix); assertEquals("radix " + radix + " min", Long.MIN_VALUE, impl.longValue()); impl = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1.1", 1, impl.longValue()); impl = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " -1.1", -1, impl.longValue()); impl = new RawtypeApfloatImpl("10000000000000000000000000000000000000000000000000000000000000000000000", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1e70", Long.MAX_VALUE, impl.longValue()); impl = new RawtypeApfloatImpl("-10000000000000000000000000000000000000000000000000000000000000000000000", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " -1e70", Long.MIN_VALUE, impl.longValue()); impl = new RawtypeApfloatImpl("11111111111111111111111111111111111111111111111111111111111111111111111", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " 1x70", Long.MAX_VALUE, impl.longValue()); impl = new RawtypeApfloatImpl("-11111111111111111111111111111111111111111111111111111111111111111111111", Apfloat.INFINITE, radix, false); assertEquals("radix " + radix + " -1x70", Long.MIN_VALUE, impl.longValue()); } impl = new RawtypeApfloatImpl("9223372036854775808", Apfloat.INFINITE, 10, true); assertEquals("max+1", Long.MAX_VALUE, impl.longValue()); impl = new RawtypeApfloatImpl("-9223372036854775809", Apfloat.INFINITE, 10, true); assertEquals("min-1", Long.MIN_VALUE, impl.longValue()); impl = new RawtypeApfloatImpl("-9223372036854775810", Apfloat.INFINITE, 10, true); assertEquals("min-2", Long.MIN_VALUE, impl.longValue()); } public static void testEqualDigits() { ApfloatImpl a, b; a = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); assertEquals("0 eqd 0", Apfloat.INFINITE, a.equalDigits(b)); a = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("0 eqd 1", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("-1 eqd 1", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(10, Apfloat.INFINITE, 10); assertEquals("1 eqd 10", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(10, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("10 eqd 1", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(100, Apfloat.INFINITE, 10); assertEquals("1 eqd 100", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(100, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("100 eqd 1", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); assertEquals("1 eqd 2", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("2 eqd 1", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(-2, Apfloat.INFINITE, 10); assertEquals("-1 eqd -2", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(-2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); assertEquals("-2 eqd -1", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("1 eqd 1", Apfloat.INFINITE, a.equalDigits(b)); a = new RawtypeApfloatImpl(1, 25, 10); b = new RawtypeApfloatImpl(1, 55, 10); assertEquals("1 eqd 1, prec", 25, a.equalDigits(b)); a = new RawtypeApfloatImpl(10, 1, 10); b = new RawtypeApfloatImpl(11, 1, 10); assertEquals("1(0) eqd 1(1)", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl(11, 1, 10); b = new RawtypeApfloatImpl(10, 1, 10); assertEquals("1(1) eqd 1(0)", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl(10, 2, 10); b = new RawtypeApfloatImpl(11, 1, 10); assertEquals("10 eqd 1(1)", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl(11, 1, 10); b = new RawtypeApfloatImpl(10, 2, 10); assertEquals("1(1) eqd 10", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl("1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); assertEquals("1 eqd 1.1", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1", Apfloat.INFINITE, 10, false); assertEquals("1.1 eqd 1", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl("-1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, 10, false); assertEquals("-1 eqd -1.1", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("-1", Apfloat.INFINITE, 10, false); assertEquals("-1.1 eqd -1", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl(123456789, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(123456788, Apfloat.INFINITE, 10); assertEquals("123456789 eqd 123456788", 8, a.equalDigits(b)); a = new RawtypeApfloatImpl(123456788, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(123456789, Apfloat.INFINITE, 10); assertEquals("123456788 eqd 123456789", 8, a.equalDigits(b)); a = new RawtypeApfloatImpl(123456789, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(223456789, Apfloat.INFINITE, 10); assertEquals("123456789 eqd 223456789", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(223456789, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(123456789, Apfloat.INFINITE, 10); assertEquals("223456789 eqd 123456789", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(1234567890L, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1234567891L, Apfloat.INFINITE, 10); assertEquals("1234567890 eqd 1234567891", 9, a.equalDigits(b)); a = new RawtypeApfloatImpl(1234567891L, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1234567890L, Apfloat.INFINITE, 10); assertEquals("1234567891 eqd 1234567890", 9, a.equalDigits(b)); a = new RawtypeApfloatImpl(1234567890L, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(2234567890L, Apfloat.INFINITE, 10); assertEquals("1234567890 eqd 2234567890", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(2234567890L, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1234567890L, Apfloat.INFINITE, 10); assertEquals("2234567890 eqd 1234567890", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(1234567890L, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1334567890L, Apfloat.INFINITE, 10); assertEquals("1234567890 eqd 1334567890", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl(1334567890L, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1234567890L, Apfloat.INFINITE, 10); assertEquals("1334567890 eqd 1234567890", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl(10000000000L, 10, 10); b = new RawtypeApfloatImpl(10000000001L, 10, 10); assertEquals("1000000000(0) eqd 1000000000(1)", 10, a.equalDigits(b)); a = new RawtypeApfloatImpl(10000000001L, 10, 10); b = new RawtypeApfloatImpl(10000000000L, 10, 10); assertEquals("1000000000(1) eqd 1000000000(0)", 10, a.equalDigits(b)); a = new RawtypeApfloatImpl(10000000000L, 11, 10); b = new RawtypeApfloatImpl(10000000001L, 10, 10); assertEquals("10000000000 eqd 1000000000(1)", 10, a.equalDigits(b)); a = new RawtypeApfloatImpl(10000000001L, 10, 10); b = new RawtypeApfloatImpl(10000000000L, 11, 10); assertEquals("1000000000(1) eqd 10000000000", 10, a.equalDigits(b)); a = new RawtypeApfloatImpl("1000000000000000000", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("999999999999999999", Apfloat.DEFAULT, 10, false); assertEquals("1000000000000000000 eqd 999999999999999999", 17, a.equalDigits(b)); a = new RawtypeApfloatImpl("999999999999999999", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("1000000000000000000", Apfloat.DEFAULT, 10, false); assertEquals("999999999999999999 eqd 1000000000000000000", 17, a.equalDigits(b)); a = new RawtypeApfloatImpl("1000000007000000000", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("999999999999999999", Apfloat.DEFAULT, 10, false); assertEquals("1000000007000000000 eqd 999999999999999999", 8, a.equalDigits(b)); a = new RawtypeApfloatImpl("999999999999999999", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("1000000007000000000", Apfloat.DEFAULT, 10, false); assertEquals("999999999999999999 eqd 1000000007000000000", 8, a.equalDigits(b)); a = new RawtypeApfloatImpl("1000000000", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("900000000", Apfloat.DEFAULT, 10, false); assertEquals("1000000000 eqd 900000000", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl("900000000", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("1000000000", Apfloat.DEFAULT, 10, false); assertEquals("900000000 eqd 1000000000", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl("1000000000", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("990000000", Apfloat.DEFAULT, 10, false); assertEquals("1000000000 eqd 990000000", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl("990000000", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("1000000000", Apfloat.DEFAULT, 10, false); assertEquals("990000000 eqd 1000000000", 1, a.equalDigits(b)); a = new RawtypeApfloatImpl(10, 5, 10); b = new RawtypeApfloatImpl(9, 5, 10); assertEquals("10 eqd 9", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl(9, 5, 10); b = new RawtypeApfloatImpl(10, 5, 10); assertEquals("9 eqd 10", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl("123456789000100000000000000000000000", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("123456789000099999999999999999999425", Apfloat.DEFAULT, 10, false); assertEquals("123456789000100000000000000000000000 eqd 123456789000099999999999999999999425", 33, a.equalDigits(b)); a = new RawtypeApfloatImpl("123456789000099999999999999999999425", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("123456789000100000000000000000000000", Apfloat.DEFAULT, 10, false); assertEquals("123456789000099999999999999999999425 eqd 123456789000100000000000000000000000", 33, a.equalDigits(b)); a = new RawtypeApfloatImpl("12000100000123456789", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("12000099999234567890", Apfloat.DEFAULT, 10, false); assertEquals("12000100000123456789 eqd 12000099999234567890", 11, a.equalDigits(b)); a = new RawtypeApfloatImpl("12000099999234567890", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("12000100000123456789", Apfloat.DEFAULT, 10, false); assertEquals("12000099999234567890 eqd 12000100000123456789", 11, a.equalDigits(b)); a = new RawtypeApfloatImpl("12000100000234567890", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("12000099999123456789", Apfloat.DEFAULT, 10, false); assertEquals("12000100000234567890 eqd 12000099999123456789", 10, a.equalDigits(b)); a = new RawtypeApfloatImpl("12000099999123456789", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("12000100000234567890", Apfloat.DEFAULT, 10, false); assertEquals("12000099999123456789 eqd 12000100000234567890", 10, a.equalDigits(b)); a = new RawtypeApfloatImpl("0.15", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("0.04", Apfloat.DEFAULT, 10, false); assertEquals("0.15 eq 0.04", 0, a.equalDigits(b)); a = new RawtypeApfloatImpl("2.0", Apfloat.DEFAULT, 10, false); b = new RawtypeApfloatImpl("0.9", Apfloat.DEFAULT, 10, false); assertEquals("2.0 eq 0.9", 0, a.equalDigits(b)); assertEquals("0.9 eq 2.0", 0, b.equalDigits(a)); a = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 2, false); b = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 3, false); try { a.equalDigits(b); fail("No radix mismatch"); } catch (RadixMismatchException rme) { // OK: overflow } b = (RawType.TYPE.equals(Integer.TYPE) ? new LongApfloatImpl(0, Apfloat.INFINITE, 10) : new IntApfloatImpl(0, Apfloat.INFINITE, 10)); try { a.equalDigits(b); fail("No implementation mismatch"); } catch (ImplementationMismatchException ime) { // OK: wrong implementation class } } public static void testCompareTo() { ApfloatImpl a, b; a = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); assertEquals("0 == 0", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("0 < 1", -1, a.compareTo(b)); a = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("-1 < 1", -1, a.compareTo(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); assertEquals("1 > -1", 1, a.compareTo(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(10, Apfloat.INFINITE, 10); assertEquals("1 < 10", -1, a.compareTo(b)); a = new RawtypeApfloatImpl(10, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("10 > 1", 1, a.compareTo(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); assertEquals("1 < 2", -1, a.compareTo(b)); a = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("2 > 1", 1, a.compareTo(b)); a = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(-2, Apfloat.INFINITE, 10); assertEquals("-1 > -2", 1, a.compareTo(b)); a = new RawtypeApfloatImpl(-2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); assertEquals("-2 < -1", -1, a.compareTo(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertEquals("1 == 1", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(1, 25, 10); b = new RawtypeApfloatImpl(1, 55, 10); assertEquals("1 == 1, prec", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(10, 1, 10); b = new RawtypeApfloatImpl(11, 1, 10); assertEquals("1(0) == 1(1)", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(11, 1, 10); b = new RawtypeApfloatImpl(10, 1, 10); assertEquals("1(1) == 1(0)", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(10, 2, 10); b = new RawtypeApfloatImpl(11, 1, 10); assertEquals("10 == 1(1)", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(11, 1, 10); b = new RawtypeApfloatImpl(10, 2, 10); assertEquals("1(1) == 10", 0, a.compareTo(b)); a = new RawtypeApfloatImpl("1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); assertEquals("1 < 1.1", -1, a.compareTo(b)); a = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1", Apfloat.INFINITE, 10, false); assertEquals("1.1 > 1", 1, a.compareTo(b)); a = new RawtypeApfloatImpl("-1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, 10, false); assertEquals("-1 > -1.1", 1, a.compareTo(b)); a = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("-1", Apfloat.INFINITE, 10, false); assertEquals("-1.1 < -1", -1, a.compareTo(b)); a = new RawtypeApfloatImpl(10000000000L, 10, 10); b = new RawtypeApfloatImpl(10000000001L, 10, 10); assertEquals("1000000000(0) == 1000000000(1)", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(10000000001L, 10, 10); b = new RawtypeApfloatImpl(10000000000L, 10, 10); assertEquals("1000000000(1) == 1000000000(0)", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(10000000000L, 11, 10); b = new RawtypeApfloatImpl(10000000001L, 10, 10); assertEquals("10000000000 == 1000000000(1)", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(10000000001L, 10, 10); b = new RawtypeApfloatImpl(10000000000L, 11, 10); assertEquals("1000000000(1) == 10000000000", 0, a.compareTo(b)); a = new RawtypeApfloatImpl(10000000001L, 11, 10); b = new RawtypeApfloatImpl(10000000001L, 11, 10); assertEquals("10000000001 == 10000000001", 0, a.compareTo(b)); a = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 2, false); b = new RawtypeApfloatImpl("1e5", Apfloat.INFINITE, 3, false); try { a.compareTo(b); fail("No radix mismatch"); } catch (RadixMismatchException rme) { // OK: overflow } b = (RawType.TYPE.equals(Integer.TYPE) ? new LongApfloatImpl(0, Apfloat.INFINITE, 10) : new IntApfloatImpl(0, Apfloat.INFINITE, 10)); try { a.compareTo(b); fail("No implementation mismatch"); } catch (ImplementationMismatchException ime) { // OK: wrong implementation class } } public static void testEquals() { ApfloatImpl a, b; a = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); assertTrue("0 == 0", a.equals(b)); a = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("0 =! 1", !a.equals(b)); a = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("-1 != 1", !a.equals(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(10, Apfloat.INFINITE, 10); assertTrue("1 != 10", !a.equals(b)); a = new RawtypeApfloatImpl(10, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("10 != 1", !a.equals(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); assertTrue("1 != 2", !a.equals(b)); a = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("2 != 1", !a.equals(b)); a = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(-2, Apfloat.INFINITE, 10); assertTrue("-1 != -2", !a.equals(b)); a = new RawtypeApfloatImpl(-2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); assertTrue("-2 != -1", !a.equals(b)); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("1 == 1", a.equals(b)); a = new RawtypeApfloatImpl(1, 25, 10); b = new RawtypeApfloatImpl(1, 55, 10); assertTrue("1 == 1, prec", a.equals(b)); a = new RawtypeApfloatImpl(10, 1, 10); b = new RawtypeApfloatImpl(11, 1, 10); assertTrue("1(0) == 1(1)", a.equals(b)); a = new RawtypeApfloatImpl(11, 1, 10); b = new RawtypeApfloatImpl(10, 1, 10); assertTrue("1(1) == 1(0)", a.equals(b)); a = new RawtypeApfloatImpl(10, 2, 10); b = new RawtypeApfloatImpl(11, 1, 10); assertTrue("10 == 1(1)", a.equals(b)); a = new RawtypeApfloatImpl(11, 1, 10); b = new RawtypeApfloatImpl(10, 2, 10); assertTrue("1(1) == 10", a.equals(b)); a = new RawtypeApfloatImpl("1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); assertTrue("1 != 1.1", !a.equals(b)); a = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1", Apfloat.INFINITE, 10, false); assertTrue("1.1 != 1", !a.equals(b)); a = new RawtypeApfloatImpl("-1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, 10, false); assertTrue("-1 != -1.1", !a.equals(b)); a = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("-1", Apfloat.INFINITE, 10, false); assertTrue("-1.1 != -1", !a.equals(b)); a = new RawtypeApfloatImpl(10000000000L, 10, 10); b = new RawtypeApfloatImpl(10000000001L, 10, 10); assertTrue("1000000000(0) == 1000000000(1)", a.equals(b)); a = new RawtypeApfloatImpl(10000000001L, 10, 10); b = new RawtypeApfloatImpl(10000000000L, 10, 10); assertTrue("1000000000(1) == 1000000000(0)", a.equals(b)); a = new RawtypeApfloatImpl(10000000000L, 11, 10); b = new RawtypeApfloatImpl(10000000001L, 10, 10); assertTrue("10000000000 == 1000000000(1)", a.equals(b)); a = new RawtypeApfloatImpl(10000000001L, 10, 10); b = new RawtypeApfloatImpl(10000000000L, 11, 10); assertTrue("1000000000(1) == 10000000000", a.equals(b)); assertFalse("wrong type", a.equals("Bogus")); a = new RawtypeApfloatImpl("2", Apfloat.INFINITE, 3, false); b = new RawtypeApfloatImpl("2", Apfloat.INFINITE, 4, false); assertFalse("wrong radix", a.equals(b)); a = new RawtypeApfloatImpl("2", Apfloat.INFINITE, 3, false); b = (RawType.TYPE.equals(Integer.TYPE) ? new LongApfloatImpl(0, Apfloat.INFINITE, 10) : new IntApfloatImpl(0, Apfloat.INFINITE, 10)); assertFalse("wrong implementation", a.equals(b)); } public static void testHashCode() { ApfloatImpl a, b; a = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); assertTrue("0 == 0", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl(0, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("0 =! 1", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("-1 != 1", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(10, Apfloat.INFINITE, 10); assertTrue("1 != 10", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl(10, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("10 != 1", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); assertTrue("1 != 2", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl(2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("2 != 1", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(-2, Apfloat.INFINITE, 10); assertTrue("-1 != -2", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl(-2, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(-1, Apfloat.INFINITE, 10); assertTrue("-2 != -1", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); b = new RawtypeApfloatImpl(1, Apfloat.INFINITE, 10); assertTrue("1 == 1", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl(1, 25, 10); b = new RawtypeApfloatImpl(1, 55, 10); assertTrue("1 == 1, prec", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl(10, 1, 10); b = new RawtypeApfloatImpl(11, 1, 10); assertTrue("1(0) == 1(1)", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl(11, 1, 10); b = new RawtypeApfloatImpl(10, 1, 10); assertTrue("1(1) == 1(0)", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl(10, 2, 10); b = new RawtypeApfloatImpl(11, 1, 10); assertTrue("10 == 1(1)", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl(11, 1, 10); b = new RawtypeApfloatImpl(10, 2, 10); assertTrue("1(1) == 10", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl("1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); assertTrue("1 != 1.1", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl("1.1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("1", Apfloat.INFINITE, 10, false); assertTrue("1.1 != 1", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl("-1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, 10, false); assertTrue("-1 != -1.1", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl("-1.1", Apfloat.INFINITE, 10, false); b = new RawtypeApfloatImpl("-1", Apfloat.INFINITE, 10, false); assertTrue("-1.1 != -1", a.hashCode() != b.hashCode()); a = new RawtypeApfloatImpl(10000000000L, 10, 10); b = new RawtypeApfloatImpl(10000000001L, 10, 10); assertTrue("1000000000(0) == 1000000000(1)", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl(10000000001L, 10, 10); b = new RawtypeApfloatImpl(10000000000L, 10, 10); assertTrue("1000000000(1) == 1000000000(0)", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl(10000000000L, 11, 10); b = new RawtypeApfloatImpl(10000000001L, 10, 10); assertTrue("10000000000 == 1000000000(1)", a.hashCode() == b.hashCode()); a = new RawtypeApfloatImpl(10000000001L, 10, 10); b = new RawtypeApfloatImpl(10000000000L, 11, 10); assertTrue("1000000000(1) == 10000000000", a.hashCode() == b.hashCode()); } public static void testToString() { ApfloatImpl a = new RawtypeApfloatImpl("1234560.01", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1234560.01", a.toString(true)); a = new RawtypeApfloatImpl("123456000000000.01", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "123456000000000.01", a.toString(true)); a = new RawtypeApfloatImpl("1234560000000000.01", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1234560000000000.01", a.toString(true)); a = new RawtypeApfloatImpl("1234560000000001.01", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1234560000000001.01", a.toString(true)); a = new RawtypeApfloatImpl("1234560000000001.101", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1234560000000001.101", a.toString(true)); a = new RawtypeApfloatImpl("123456", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1.23456e5", a.toString(false)); a = new RawtypeApfloatImpl("123456789", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1.23456789e8", a.toString(false)); a = new RawtypeApfloatImpl("1234567890", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1.23456789e9", a.toString(false)); a = new RawtypeApfloatImpl("12345.6", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1.23456e4", a.toString(false)); a = new RawtypeApfloatImpl("1.23456", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1.23456", a.toString(false)); a = new RawtypeApfloatImpl("123456780", 8, 10, false); assertEquals("unpretty", "1.2345678e8", a.toString(false)); a = new RawtypeApfloatImpl("1234567890", 9, 10, false); assertEquals("unpretty", "1.23456789e9", a.toString(false)); a = new RawtypeApfloatImpl("0.1", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1e-1", a.toString(false)); a = new RawtypeApfloatImpl("0.000000001", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1e-9", a.toString(false)); a = new RawtypeApfloatImpl("0.12", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1.2e-1", a.toString(false)); a = new RawtypeApfloatImpl("0.0000000012", Apfloat.INFINITE, 10, false); assertEquals("unpretty", "1.2e-9", a.toString(false)); for (int radix = Character.MIN_RADIX; radix < 15; radix++) { for (int i = 1; i < 400; i++) { a = new RawtypeApfloatImpl("1e" + (Long.MIN_VALUE + i), Apfloat.INFINITE, radix, false); a.toString(false); try { a.toString(true); } catch (ApfloatRuntimeException are) { // OK if number doesn't fit to a string } } } } public static void testWriteTo() throws IOException { ApfloatImpl a = new RawtypeApfloatImpl("123450", 5, 10, true); StringWriter writer = new StringWriter(); a.writeTo(writer, true); assertEquals("pretty", "123450", writer.toString()); writer = new StringWriter(); a.writeTo(writer, false); assertEquals("unpretty", "1.2345e5", writer.toString()); writer = new StringWriter(); a = new RawtypeApfloatImpl("0", 5, 10, true); a.writeTo(writer, false); assertEquals("zero", "0", writer.toString()); } public static void testSerialization() throws IOException, ClassNotFoundException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(buffer); ApfloatImpl a = new RawtypeApfloatImpl(5, Apfloat.INFINITE, 10); out.writeObject(a); out.close(); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray())); ApfloatImpl b = (ApfloatImpl) in.readObject(); assertEquals("5 equals", a, b); assertTrue("5 !=", a != b); a = new RawtypeApfloatImpl(getString('a', 1000000), Apfloat.DEFAULT, 12, false); buffer.reset(); out = new ObjectOutputStream(buffer); out.writeObject(a); out.close(); in = new ObjectInputStream(new ByteArrayInputStream(buffer.toByteArray())); b = (ApfloatImpl) in.readObject(); assertEquals("1000000 equals", a, b); assertTrue("1000000 !=", a != b); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeBaseMathTest.java000066400000000000000000000430611461767713300310510ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import static org.junit.Assert.assertArrayEquals; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.lang.reflect.Method; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeBaseMathTest extends RawtypeTestCase implements RawtypeRadixConstants { public RawtypeBaseMathTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeBaseMathTest("testAdd")); suite.addTest(new RawtypeBaseMathTest("testSubtract")); suite.addTest(new RawtypeBaseMathTest("testMultiplyAdd")); suite.addTest(new RawtypeBaseMathTest("testDivide")); suite.addTest(new RawtypeBaseMathTest("testSerialization")); return suite; } private static DataStorage createDataStorage(rawtype[] data) { int size = data.length; ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); DataStorage dataStorage = dataStorageBuilder.createDataStorage(size * RawType.BYTES); dataStorage.setSize(size); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, size)) { System.arraycopy(data, 0, arrayAccess.getData(), arrayAccess.getOffset(), size); } return dataStorage; } private static void check(String message, int radix, rawtype[] expected, DataStorage actual) { try (ArrayAccess arrayAccess = actual.getArray(DataStorage.READ, 0, expected.length)) { assertEquals("radix " + radix + " " + message + " length", expected.length, arrayAccess.getLength()); for (int i = 0; i < arrayAccess.getLength(); i++) { assertEquals("radix " + radix + " " + message + " [" + i + "]", (long) expected[i], (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + i]); } } } public static void testAdd() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 0, (rawtype) 1, (rawtype) 2, (rawtype) 3 }), src2 = createDataStorage(new rawtype[] { (rawtype) 4, (rawtype) 5, (rawtype) 6, (rawtype) 7 }), src9 = createDataStorage(new rawtype[] { b1, b1, b1, b1 }), dst = createDataStorage(new rawtype[4]); RawtypeBaseMath math = new RawtypeBaseMath(radix); rawtype carry = 0; carry = math.baseAdd(src1.iterator(DataStorage.READ, 0, 4), src2.iterator(DataStorage.READ, 0, 4), carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " both carry", 0, (long) carry); check("both", radix, new rawtype[] { (rawtype) 4, (rawtype) 6, (rawtype) 8, (rawtype) 10 }, dst); carry = (rawtype) 1; carry = math.baseAdd(src9.iterator(DataStorage.READ, 0, 4), src9.iterator(DataStorage.READ, 0, 4), carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " max carry", 1, (long) carry); check("max", radix, new rawtype[] { b1, b1, b1, b1 }, dst); carry = 0; carry = math.baseAdd(src1.iterator(DataStorage.READ, 0, 4), null, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " src1 carry", 0, (long) carry); check("src1", radix, new rawtype[] { (rawtype) 0, (rawtype) 1, (rawtype) 2, (rawtype) 3 }, dst); carry = 0; carry = math.baseAdd(null, src2.iterator(DataStorage.READ, 0, 4), carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " src2 carry", 0, (long) carry); check("src2", radix, new rawtype[] { (rawtype) 4, (rawtype) 5, (rawtype) 6, (rawtype) 7 }, dst); carry = 0; carry = math.baseAdd(null, null, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " nulls carry", 0, (long) carry); check("nulls", radix, new rawtype[] { 0, 0, 0, 0 }, dst); } } public static void testSubtract() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 4, (rawtype) 5, (rawtype) 6, (rawtype) 7 }), src2 = createDataStorage(new rawtype[] { (rawtype) 0, (rawtype) 1, (rawtype) 2, (rawtype) 3 }), src9 = createDataStorage(new rawtype[] { b1, b1, b1, b1 }), dst = createDataStorage(new rawtype[4]); RawtypeBaseMath math = new RawtypeBaseMath(radix); rawtype carry = 0; carry = math.baseSubtract(src1.iterator(DataStorage.READ, 0, 4), src2.iterator(DataStorage.READ, 0, 4), carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " both carry", 0, (long) carry); check("both", radix, new rawtype[] { (rawtype) 4, (rawtype) 4, (rawtype) 4, (rawtype) 4 }, dst); carry = (rawtype) 1; carry = math.baseSubtract(src9.iterator(DataStorage.READ, 0, 4), src9.iterator(DataStorage.READ, 0, 4), carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " max carry", 1, (long) carry); check("max", radix, new rawtype[] { b1, b1, b1, b1 }, dst); carry = 0; carry = math.baseSubtract(src1.iterator(DataStorage.READ, 0, 4), null, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " src1 carry", 0, (long) carry); check("src1", radix, new rawtype[] { (rawtype) 4, (rawtype) 5, (rawtype) 6, (rawtype) 7 }, dst); carry = 0; carry = math.baseSubtract(null, src2.iterator(DataStorage.READ, 4, 0), carry, dst.iterator(DataStorage.WRITE, 4, 0), 4); assertEquals("radix " + radix + " src2 carry", 1, (long) carry); check("src2", radix, new rawtype[] { BASE[radix] - (rawtype) 1, BASE[radix] - (rawtype) 2, BASE[radix] - (rawtype) 3, BASE[radix] - (rawtype) 3 }, dst); carry = 1; carry = math.baseSubtract(null, null, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " nulls carry", 1, (long) carry); check("nulls", radix, new rawtype[] { b1, b1, b1, b1 }, dst); } } public static void testMultiplyAdd() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4 }), src2 = createDataStorage(new rawtype[] { (rawtype) 5, (rawtype) 6, (rawtype) 7, (rawtype) 8 }), src9 = createDataStorage(new rawtype[] { b1, b1, b1, b1 }), dst = createDataStorage(new rawtype[4]); RawtypeBaseMath math = new RawtypeBaseMath(radix); rawtype carry = 0; carry = math.baseMultiplyAdd(src1.iterator(DataStorage.READ, 0, 4), src2.iterator(DataStorage.READ, 0, 4), (rawtype) 9, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " both carry", 0, (long) carry); check("both", radix, new rawtype[] { (rawtype) 14, (rawtype) 24, (rawtype) 34, (rawtype) 44 }, dst); carry = 0; carry = math.baseMultiplyAdd(src9.iterator(DataStorage.READ, 4, 0), src9.iterator(DataStorage.READ, 4, 0), b1, carry, dst.iterator(DataStorage.WRITE, 4, 0), 4); assertEquals("radix " + radix + " max2 carry", (long) b1, (long) carry); check("max2", radix, new rawtype[] { b1, b1, b1, 0 }, dst); carry = b1; carry = math.baseMultiplyAdd(src9.iterator(DataStorage.READ, 4, 0), null, b1, carry, dst.iterator(DataStorage.WRITE, 4, 0), 4); assertEquals("radix " + radix + " max1 carry", (long) b1, (long) carry); check("max1", radix, new rawtype[] { 0, 0, 0, 0 }, dst); carry = 0; carry = math.baseMultiplyAdd(src1.iterator(DataStorage.READ, 0, 4), null, (rawtype) 9, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " src1 carry", 0, (long) carry); check("src1", radix, new rawtype[] { (rawtype) 9, (rawtype) 18, (rawtype) 27, (rawtype) 36 }, dst); } } public static void testDivide() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 0, (rawtype) 2, (rawtype) 4, (rawtype) 7 }), src9 = createDataStorage(new rawtype[] { b1, b1, b1, b1 }), dst = createDataStorage(new rawtype[4]); RawtypeBaseMath math = new RawtypeBaseMath(radix); rawtype carry = 0; carry = math.baseDivide(src1.iterator(DataStorage.READ, 0, 4), (rawtype) 2, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " both carry", 1, (long) carry); check("both", radix, new rawtype[] { (rawtype) 0, (rawtype) 1, (rawtype) 2, (rawtype) 3 }, dst); carry = b1 - (rawtype) 1; carry = math.baseDivide(src9.iterator(DataStorage.READ, 0, 4), b1, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); assertEquals("radix " + radix + " max carry", (long) b1 - 1, (long) carry); check("max", radix, new rawtype[] { b1, b1, b1, b1 }, dst); carry = (rawtype) 1; carry = math.baseDivide(null, (rawtype) 2, carry, dst.iterator(DataStorage.WRITE, 0, 4), 4); if ((radix & 1) == 0) { assertEquals("radix " + radix + " src1 carry", 0, (long) carry); check("src1", radix, new rawtype[] { BASE[radix] / (rawtype) 2, 0, 0, 0 }, dst); } else { assertEquals("radix " + radix + " src1 carry", 1, (long) carry); check("src1", radix, new rawtype[] { b1 / (rawtype) 2, b1 / (rawtype) 2, b1 / (rawtype) 2, b1 / (rawtype) 2 }, dst); } } } public void testSerialization() throws Exception { if (RawType.TYPE.getName().equals("long")) { String className = RawtypeBaseMath.class.getName(); Java9ClassLoader classLoader = new Java9ClassLoader(getClass().getClassLoader()); Class baseMathClass = classLoader.loadJava9Class(className); Object baseMath = baseMathClass.getConstructor(Integer.TYPE).newInstance(10); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try (ObjectOutputStream out = new ObjectOutputStream(buffer)) { out.writeObject(baseMath); } byte[] java9Data = buffer.toByteArray(); buffer = new ByteArrayOutputStream(); try (ObjectOutputStream out = new ObjectOutputStream(buffer)) { out.writeObject(new RawtypeBaseMath(10)); } byte[] java8Data = buffer.toByteArray(); assertArrayEquals("Serialized data", java8Data, java9Data); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(java8Data)) { @Override public Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String name = desc.getName(); return classLoader.loadClass(name); } }; baseMath = in.readObject(); Method method = baseMath.getClass().getMethod("baseMultiplyAdd", DataStorage.Iterator.class, DataStorage.Iterator.class, Long.TYPE, Long.TYPE, DataStorage.Iterator.class, Long.TYPE); DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 10 }), src2 = createDataStorage(new rawtype[] { (rawtype) 20 }), dst = createDataStorage(new rawtype[1]); rawtype src3 = (rawtype) 30, carry = (rawtype) 0; carry = (RawType) method.invoke(baseMath, src1.iterator(DataStorage.READ, 0, 1), src2.iterator(DataStorage.READ, 0, 1), src3, carry, dst.iterator(DataStorage.WRITE, 0, 1), 1L); ArrayAccess arrayAccess = dst.getArray(DataStorage.READ, 0, 1); assertEquals("Deserialized java 9 classloader", classLoader, baseMath.getClass().getClassLoader()); assertEquals("Deserialized java 9 carry", (rawtype) 0, carry); assertEquals("Deserialized java 9 result", (rawtype) 320, arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeBuilderFactoryTest.java000066400000000000000000000075021461767713300323030ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.lang.reflect.Array; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeBuilderFactoryTest extends RawtypeTestCase { public RawtypeBuilderFactoryTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeBuilderFactoryTest("testBuilders")); return suite; } public static void testBuilders() { BuilderFactory builderFactory = new RawtypeBuilderFactory(); assertTrue("ApfloatBuilder", builderFactory.getApfloatBuilder() instanceof ApfloatBuilder); assertTrue("DataStorageBuilder", builderFactory.getDataStorageBuilder() instanceof DataStorageBuilder); assertTrue("AdditionBuilder", builderFactory.getAdditionBuilder(RawType.TYPE) instanceof AdditionBuilder); assertTrue("ConvolutionBuilder", builderFactory.getConvolutionBuilder() instanceof ConvolutionBuilder); assertTrue("NTTBuilder", builderFactory.getNTTBuilder() instanceof NTTBuilder); assertTrue("MatrixBuilder", builderFactory.getMatrixBuilder() instanceof MatrixBuilder); assertTrue("CarryCRTBuilder", builderFactory.getCarryCRTBuilder(rawtype[].class) instanceof CarryCRTBuilder); assertEquals("getElementType()", RawType.TYPE, builderFactory.getElementType()); assertEquals("getElementArrayType()", rawtype[].class, builderFactory.getElementArrayType()); assertEquals("getElementSize()", RawType.BYTES, builderFactory.getElementSize()); Class[] types = { Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE }; for (Class type : types) { if (!type.equals(RawType.TYPE)) { try { builderFactory.getAdditionBuilder(type); fail("Invalid AdditonStrategy type accepted"); } catch (IllegalArgumentException iae) { // OK: should not be allowed } try { builderFactory.getCarryCRTBuilder(Array.newInstance(type, 0).getClass()); fail("Invalid CarryCRTBuilder type accepted"); } catch (IllegalArgumentException iae) { // OK: should not be allowed } } } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeCRTMathTest.java000066400000000000000000000211131461767713300306210ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import static org.junit.Assert.assertArrayEquals; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamClass; import java.lang.reflect.Method; import junit.framework.TestSuite; /** * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeCRTMathTest extends RawtypeTestCase implements RawtypeModConstants { public RawtypeCRTMathTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeCRTMathTest("testMultiply")); suite.addTest(new RawtypeCRTMathTest("testCompare")); suite.addTest(new RawtypeCRTMathTest("testAdd")); suite.addTest(new RawtypeCRTMathTest("testSubtract")); suite.addTest(new RawtypeCRTMathTest("testDivide")); suite.addTest(new RawtypeCRTMathTest("testSerialization")); return suite; } public static void testMultiply() { rawtype b1 = MAX_POWER_OF_TWO_BASE - (rawtype) 1; rawtype[] src = { b1, b1 }; rawtype[] dst = new rawtype[3]; new RawtypeCRTMath(2).multiply(src, b1, dst); assertEquals("max[0]", (long) b1 - 1, (long) dst[0]); assertEquals("max[1]", (long) b1, (long) dst[1]); assertEquals("max[2]", (long) 1, (long) dst[2]); src = new rawtype[] { (rawtype) 2, (rawtype) 4 }; new RawtypeCRTMath(2).multiply(src, (rawtype) 3, dst); assertEquals("normal[0]", 0, (long) dst[0]); assertEquals("normal[1]", 6, (long) dst[1]); assertEquals("normal[2]", 12, (long) dst[2]); } public static void testCompare() { rawtype b1 = MAX_POWER_OF_TWO_BASE - (rawtype) 1; rawtype result = new RawtypeCRTMath(2).compare(new rawtype[] { (rawtype) 1, (rawtype) 1, (rawtype) 1 }, new rawtype[] { (rawtype) 2, (rawtype) 1, (rawtype) 1 }); assertTrue("1st", result < 0); result = new RawtypeCRTMath(2).compare(new rawtype[] { (rawtype) 1, (rawtype) 2, (rawtype) 1 }, new rawtype[] { (rawtype) 1, (rawtype) 1, (rawtype) 1 }); assertTrue("2nd", result > 0); result = new RawtypeCRTMath(2).compare(new rawtype[] { (rawtype) 1, (rawtype) 1, (rawtype) 0 }, new rawtype[] { (rawtype) 1, (rawtype) 1, (rawtype) b1 }); assertTrue("3rd", result < 0); result = new RawtypeCRTMath(2).compare(new rawtype[] { (rawtype) 1, (rawtype) 1, (rawtype) 1 }, new rawtype[] { (rawtype) 1, (rawtype) 1, (rawtype) 1 }); assertTrue("equal", result == 0); } public static void testAdd() { rawtype b1 = MAX_POWER_OF_TWO_BASE - (rawtype) 1; rawtype[] src = { b1, b1, b1 }; rawtype[] srcDst = { b1, b1, b1 }; rawtype carry = new RawtypeCRTMath(2).add(src, srcDst); assertEquals("max carry", 1, (long) carry); assertEquals("max[0]", (long) b1, (long) srcDst[0]); assertEquals("max[1]", (long) b1, (long) srcDst[1]); assertEquals("max[2]", (long) b1 - 1, (long) srcDst[2]); src = new rawtype[] { (rawtype) 2, (rawtype) 4, (rawtype) 6 }; srcDst = new rawtype[] { (rawtype) 3, (rawtype) 5, (rawtype) 7 }; carry = new RawtypeCRTMath(2).add(src, srcDst); assertEquals("normal carry", 0, (long) carry); assertEquals("normal[0]", 5, (long) srcDst[0]); assertEquals("normal[1]", 9, (long) srcDst[1]); assertEquals("normal[2]", 13, (long) srcDst[2]); } public static void testSubtract() { rawtype b1 = MAX_POWER_OF_TWO_BASE - (rawtype) 1; rawtype[] src = { b1, b1, b1 }; rawtype[] srcDst = { b1, b1, b1 }; new RawtypeCRTMath(2).subtract(src, srcDst); assertEquals("max[0]", 0, (long) srcDst[0]); assertEquals("max[1]", 0, (long) srcDst[1]); assertEquals("max[2]", 0, (long) srcDst[2]); src = new rawtype[] { 0, 0, (rawtype) 1 }; srcDst = new rawtype[] { (rawtype) 1, 0, 0 }; new RawtypeCRTMath(2).subtract(src, srcDst); assertEquals("normal[0]", 0, (long) srcDst[0]); assertEquals("normal[1]", (long) b1, (long) srcDst[1]); assertEquals("normal[2]", (long) b1, (long) srcDst[2]); } public static void testDivide() { rawtype[] srcDst = new rawtype[] { (rawtype) 1, 0, 1 }; rawtype remainder = new RawtypeCRTMath(2).divide(srcDst); assertEquals("normal remainder", 1, (long) remainder); assertEquals("normal[0]", 0, (long) srcDst[0]); assertEquals("normal[1]", 2, (long) srcDst[1]); assertEquals("normal[2]", 0, (long) srcDst[2]); } public void testSerialization() throws Exception { if (RawType.TYPE.getName().equals("long")) { String className = RawtypeCRTMath.class.getName(); Java9ClassLoader classLoader = new Java9ClassLoader(getClass().getClassLoader()); classLoader.loadJava9Class(RawtypeBaseMath.class.getName()); // Load base class Java 9 specific version also Class crtMathClass = classLoader.loadJava9Class(className); Object crtMath = crtMathClass.getConstructor(Integer.TYPE).newInstance(2); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try (ObjectOutputStream out = new ObjectOutputStream(buffer)) { out.writeObject(crtMath); } byte[] java9Data = buffer.toByteArray(); buffer = new ByteArrayOutputStream(); try (ObjectOutputStream out = new ObjectOutputStream(buffer)) { out.writeObject(new RawtypeCRTMath(2)); } byte[] java8Data = buffer.toByteArray(); assertArrayEquals("Serialized data", java8Data, java9Data); ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(java8Data)) { @Override public Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { String name = desc.getName(); return classLoader.loadClass(name); } }; crtMath = in.readObject(); Method method = crtMath.getClass().getMethod("divide", rawtype[].class); rawtype[] srcDst = { (rawtype) 1, (rawtype) 0, (rawtype) 1 }; rawtype remainder = (RawType) method.invoke(crtMath, srcDst); assertEquals("Deserialized java 9 classloader", classLoader, crtMath.getClass().getClassLoader()); assertEquals("Deserialized java 9 remainder", (rawtype) 1, remainder); assertEquals("Deserialized java 9 result [0]", (rawtype) 0, srcDst[0]); assertEquals("Deserialized java 9 result [1]", (rawtype) 2, srcDst[1]); assertEquals("Deserialized java 9 result [2]", (rawtype) 0, srcDst[2]); } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeCarryCRTStrategyTest.java000066400000000000000000000206271461767713300325440ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.math.BigInteger; import java.util.concurrent.ExecutorService; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeCarryCRTStrategyTest extends RawtypeTestCase implements RawtypeModConstants, RawtypeRadixConstants { public RawtypeCarryCRTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeCarryCRTStrategyTest("testFullLength")); suite.addTest(new RawtypeCarryCRTStrategyTest("testTruncatedLength")); suite.addTest(new RawtypeCarryCRTStrategyTest("testBigFullLength")); suite.addTest(new RawtypeCarryCRTStrategyTest("testBigFullLengthParallel")); return suite; } private static DataStorage createDataStorage(rawtype[] data) { int size = data.length; ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); DataStorage dataStorage = dataStorageBuilder.createDataStorage(size * RawType.BYTES); dataStorage.setSize(size); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, size)) { System.arraycopy(data, 0, arrayAccess.getData(), arrayAccess.getOffset(), size); } return dataStorage; } private static void check(String message, int radix, rawtype[] expected, DataStorage actual) { try (ArrayAccess arrayAccess = actual.getArray(DataStorage.READ, 0, expected.length)) { assertEquals("radix " + radix + " " + message + " length", expected.length, arrayAccess.getLength()); for (int i = 0; i < arrayAccess.getLength(); i++) { assertEquals("radix " + radix + " " + message + " [" + i + "]", (long) expected[i], (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + i]); } } } public static void testFullLength() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { BigInteger base = BigInteger.valueOf((long) BASE[radix]), m0 = BigInteger.valueOf((long) MODULUS[0]), m1 = BigInteger.valueOf((long) MODULUS[1]), m2 = BigInteger.valueOf((long) MODULUS[2]), value = BigInteger.valueOf(1).multiply(base).add(BigInteger.valueOf(2)).multiply(base).add(BigInteger.valueOf(3)); DataStorage src0 = createDataStorage(new rawtype[] { 0, value.mod(m0).rawtypeValue(), value.mod(m0).rawtypeValue(), 0 }), src1 = createDataStorage(new rawtype[] { 0, value.mod(m1).rawtypeValue(), value.mod(m1).rawtypeValue(), 0 }), src2 = createDataStorage(new rawtype[] { 0, value.mod(m2).rawtypeValue(), value.mod(m2).rawtypeValue(), 0 }); StepCarryCRTStrategy crt = new StepCarryCRTStrategy(radix); DataStorage dst = crt.carryCRT(src0, src1, src2, 4); check("normal", radix, new rawtype[] {(rawtype) 1, (rawtype) 3, (rawtype) 5, (rawtype) 3 }, dst); } } public static void testTruncatedLength() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { BigInteger base = BigInteger.valueOf((long) BASE[radix]), m0 = BigInteger.valueOf((long) MODULUS[0]), m1 = BigInteger.valueOf((long) MODULUS[1]), m2 = BigInteger.valueOf((long) MODULUS[2]), value = BigInteger.valueOf(1).multiply(base).add(BigInteger.valueOf(2)).multiply(base).add(BigInteger.valueOf(3)); DataStorage src0 = createDataStorage(new rawtype[] { 0, value.mod(m0).rawtypeValue(), (rawtype) 1, 0 }), src1 = createDataStorage(new rawtype[] { 0, value.mod(m1).rawtypeValue(), (rawtype) 1, 0 }), src2 = createDataStorage(new rawtype[] { 0, value.mod(m2).rawtypeValue(), (rawtype) 1, 0 }); StepCarryCRTStrategy crt = new StepCarryCRTStrategy(radix); DataStorage dst = crt.carryCRT(src0, src1, src2, 1); check("normal", radix, new rawtype[] {(rawtype) 1 }, dst); } } public static void testBigFullLength() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(1); runBig(); ctx.setNumberOfProcessors(numberOfProcessors); } public static void testBigFullLengthParallel() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ExecutorService executorService = ctx.getExecutorService(); ctx.setNumberOfProcessors(4); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); runBig(); ctx.setNumberOfProcessors(numberOfProcessors); ctx.setExecutorService(executorService); } private static void runBig() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { BigInteger base = BigInteger.valueOf((long) BASE[radix]), bm1 = BigInteger.valueOf((long) BASE[radix] - 1), bm2 = BigInteger.valueOf((long) BASE[radix] - 2), m0 = BigInteger.valueOf((long) MODULUS[0]), m1 = BigInteger.valueOf((long) MODULUS[1]), m2 = BigInteger.valueOf((long) MODULUS[2]), value = bm2.multiply(base).add(bm1).multiply(base).add(BigInteger.valueOf(1)); final int SIZE = 500; rawtype[] data0 = new rawtype[SIZE], data1 = new rawtype[SIZE], data2 = new rawtype[SIZE], expected = new rawtype[SIZE]; rawtype value0 = value.mod(m0).rawtypeValue(), value1 = value.mod(m1).rawtypeValue(), value2 = value.mod(m2).rawtypeValue(); for (int i = 1; i < SIZE - 1; i++) { data0[i] = value0; data1[i] = value1; data2[i] = value2; expected[i] = BASE[radix] - (rawtype) 1; } expected[0] = BASE[radix] - (rawtype) 1; expected[1] = BASE[radix] - (rawtype) 2; expected[SIZE - 2] = 0; expected[SIZE - 1] = (rawtype) 1; DataStorage src0 = createDataStorage(data0), src1 = createDataStorage(data1), src2 = createDataStorage(data2); StepCarryCRTStrategy crt = new StepCarryCRTStrategy(radix); DataStorage dst = crt.carryCRT(src0, src1, src2, SIZE); check("normal", radix, expected, dst); } } } RawtypeConvolutionStrategyTestCase.java000066400000000000000000000053611461767713300341450ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; /** * @version 1.9.0 * @author Mikko Tommila */ public abstract class RawtypeConvolutionStrategyTestCase extends RawtypeTestCase implements RawtypeRadixConstants { protected RawtypeConvolutionStrategyTestCase(String methodName) { super(methodName); } protected static DataStorage createDataStorage(rawtype[] data) { int size = data.length; ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); DataStorage dataStorage = dataStorageBuilder.createDataStorage(size * RawType.BYTES); dataStorage.setSize(size); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, size)) { System.arraycopy(data, 0, arrayAccess.getData(), arrayAccess.getOffset(), size); } return dataStorage; } protected static void check(String message, int radix, rawtype[] expected, DataStorage actual) { try (ArrayAccess arrayAccess = actual.getArray(DataStorage.READ, 0, expected.length)) { assertEquals("radix " + radix + " " + message + " length", expected.length, arrayAccess.getLength()); for (int i = 0; i < arrayAccess.getLength(); i++) { assertEquals("radix " + radix + " " + message + " [" + i + "]", (long) expected[i], (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + i]); } } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeDataStorageBuilderTest.java000066400000000000000000000053321461767713300330710ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.8.0 * @author Mikko Tommila */ public class RawtypeDataStorageBuilderTest extends RawtypeTestCase { public RawtypeDataStorageBuilderTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeDataStorageBuilderTest("testCreate")); return suite; } public static void testCreate() { DataStorageBuilder dataStorageBuilder = new RawtypeDataStorageBuilder(); assertTrue("Normal", dataStorageBuilder.createDataStorage(1) instanceof DataStorage); DataStorage dataStorage = dataStorageBuilder.createCachedDataStorage(1); assertTrue("Cached", dataStorage.isCached()); ApfloatContext ctx = ApfloatContext.getContext(); long memoryThreshold = ctx.getMemoryThreshold(); ctx.setMemoryThreshold(65536); dataStorage.setSize(ctx.getMemoryThreshold() + 1); dataStorage = dataStorageBuilder.createDataStorage(dataStorage); assertFalse("Not cached", dataStorage.isCached()); dataStorage = dataStorageBuilder.createCachedDataStorage(ctx.getMemoryThreshold() + 1); assertTrue("Not cached although might", dataStorage.isCached()); ctx.setMemoryThreshold(memoryThreshold); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeDataStorageTestCase.java000066400000000000000000000643571461767713300323720ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.lang.reflect.Array; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.7.0 * @author Mikko Tommila */ public abstract class RawtypeDataStorageTestCase extends RawtypeTestCase { protected RawtypeDataStorageTestCase() { } protected RawtypeDataStorageTestCase(String methodName) { super(methodName); } public TestSuite realSuite() { TestSuite suite = new TestSuite(); suite.addTest(createTestCase("testGetArray")); suite.addTest(createTestCase("testSubsequence")); suite.addTest(createTestCase("testSubsequenceSubArray")); suite.addTest(createTestCase("testReadOnly")); suite.addTest(createTestCase("testCopyFrom")); suite.addTest(createTestCase("testCopyFromSelf")); suite.addTest(createTestCase("testCopyFromBig")); suite.addTest(createTestCase("testIterator")); suite.addTest(createTestCase("testIteratorBig")); suite.addTest(createTestCase("testSubsequenceIterator")); suite.addTest(createTestCase("testUnsupportedIterator")); suite.addTest(createTestCase("testGenericIterator")); return suite; } public abstract TestCase createTestCase(String methodName); public abstract DataStorage createDataStorage() throws ApfloatRuntimeException; public void testGetArray() { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(4); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, 4); assertEquals("data length", 4, dataStorage.getSize()); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("write array length", 4, arrayAccess.getLength()); arrayAccess.getRawtypeData()[arrayAccess.getOffset()] = (rawtype) 1; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1] = (rawtype) 2; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 2] = (rawtype) 3; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3] = (rawtype) 4; arrayAccess.close(); arrayAccess = dataStorage.getArray(DataStorage.READ, 1, 2); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("[0]", 2, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("[1]", 3, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1]); assertEquals("read array length", 2, arrayAccess.getLength()); } public void testSubsequence() { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(4); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, 4); arrayAccess.getRawtypeData()[arrayAccess.getOffset()] = (rawtype) 1; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1] = (rawtype) 2; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 2] = (rawtype) 3; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3] = (rawtype) 4; arrayAccess.close(); assertEquals("data length", 4, dataStorage.getSize()); assertEquals("not yet subsequenced", false, dataStorage.isSubsequenced()); DataStorage newDataStorage = dataStorage.subsequence(1, 2); assertEquals("base subsequenced", true, dataStorage.isSubsequenced()); assertEquals("subsequence subsequenced", true, newDataStorage.isSubsequenced()); assertEquals("base data length", 4, dataStorage.getSize()); assertEquals("subsequence data length", 2, newDataStorage.getSize()); arrayAccess = newDataStorage.getArray(DataStorage.READ_WRITE, 0, 2); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("sub[0]", 2, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("sub[1]", 3, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1]); assertEquals("subsequence array length", 2, arrayAccess.getLength()); arrayAccess.close(); DataStorage newNewDataStorage = newDataStorage.subsequence(1, 1); arrayAccess = newNewDataStorage.getArray(DataStorage.READ_WRITE, 0, 1); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("subsub[0]", 3, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("subsubsequence array length", 1, arrayAccess.getLength()); } public void testSubsequenceSubArray() { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(8); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, 8); arrayAccess.getRawtypeData()[arrayAccess.getOffset()] = (rawtype) 1; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1] = (rawtype) 2; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 2] = (rawtype) 3; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3] = (rawtype) 4; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 4] = (rawtype) 5; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 5] = (rawtype) 6; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 6] = (rawtype) 7; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 7] = (rawtype) 8; arrayAccess.close(); DataStorage newDataStorage = dataStorage.subsequence(1, 6); arrayAccess = newDataStorage.getArray(DataStorage.READ_WRITE, 1, 4); ArrayAccess newArrayAccess = arrayAccess.subsequence(1, 2); assertEquals("sub[0]", 4, (int) newArrayAccess.getRawtypeData()[newArrayAccess.getOffset()]); assertEquals("sub[1]", 5, (int) newArrayAccess.getRawtypeData()[newArrayAccess.getOffset() + 1]); newArrayAccess.getRawtypeData()[newArrayAccess.getOffset()] = (rawtype) -1; newArrayAccess.getRawtypeData()[newArrayAccess.getOffset() + 1] = (rawtype) -2; newArrayAccess.close(); arrayAccess.close(); newArrayAccess = newDataStorage.getArray(DataStorage.READ, 0, 6); assertEquals("[0]", 2, (int) newArrayAccess.getRawtypeData()[newArrayAccess.getOffset()]); assertEquals("[1]", 3, (int) newArrayAccess.getRawtypeData()[newArrayAccess.getOffset() + 1]); assertEquals("[2]", -1, (int) newArrayAccess.getRawtypeData()[newArrayAccess.getOffset() + 2]); assertEquals("[3]", -2, (int) newArrayAccess.getRawtypeData()[newArrayAccess.getOffset() + 3]); assertEquals("[4]", 6, (int) newArrayAccess.getRawtypeData()[newArrayAccess.getOffset() + 4]); assertEquals("[5]", 7, (int) newArrayAccess.getRawtypeData()[newArrayAccess.getOffset() + 5]); } public void testReadOnly() { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(4); assertEquals("data length", 4, dataStorage.getSize()); DataStorage newDataStorage = dataStorage.subsequence(1, 2); assertEquals("base data length", 4, dataStorage.getSize()); assertEquals("subsequence data length", 2, newDataStorage.getSize()); assertEquals("base writable", false, dataStorage.isReadOnly()); assertEquals("subsequence writable", false, newDataStorage.isReadOnly()); newDataStorage.setReadOnly(); assertTrue("1 base read-only", dataStorage.isReadOnly()); assertTrue("1 subsequence read-only", newDataStorage.isReadOnly()); assertEquals("1 read-only base data length", 4, dataStorage.getSize()); assertEquals("1 read-only subsequence data length", 2, newDataStorage.getSize()); dataStorage = createDataStorage(); dataStorage.setSize(4); newDataStorage = dataStorage.subsequence(1, 2); dataStorage.setReadOnly(); assertTrue("2 base read-only", dataStorage.isReadOnly()); assertTrue("2 subsequence read-only", newDataStorage.isReadOnly()); assertEquals("2 read-only base data length", 4, dataStorage.getSize()); assertEquals("2 read-only subsequence data length", 2, newDataStorage.getSize()); } public void testCopyFrom() { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(4); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, 4); arrayAccess.getRawtypeData()[arrayAccess.getOffset()] = (rawtype) 1; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1] = (rawtype) 2; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 2] = (rawtype) 3; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3] = (rawtype) 4; arrayAccess.close(); DataStorage newDataStorage = createDataStorage(); newDataStorage.copyFrom(dataStorage, 2); assertEquals("data length 1", 2, newDataStorage.getSize()); arrayAccess = newDataStorage.getArray(DataStorage.READ, 0, 2); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("[0]", 1, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("[1]", 2, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1]); assertEquals("array length 1", 2, arrayAccess.getLength()); arrayAccess.close(); newDataStorage.copyFrom(dataStorage); assertEquals("data length 2", 4, newDataStorage.getSize()); arrayAccess = newDataStorage.getArray(DataStorage.READ, 0, 4); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("[0]", 1, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("[3]", 4, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3]); assertEquals("array length 2", 4, arrayAccess.getLength()); arrayAccess.close(); newDataStorage.copyFrom(dataStorage, 6); assertEquals("data length 3", 6, newDataStorage.getSize()); arrayAccess = newDataStorage.getArray(DataStorage.READ, 0, 6); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("[0]", 1, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("[3]", 4, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3]); assertEquals("[4]", 0, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 4]); assertEquals("[5]", 0, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 5]); assertEquals("array length 3", 6, arrayAccess.getLength()); arrayAccess.close(); dataStorage = dataStorage.subsequence(2, 2); newDataStorage.copyFrom(dataStorage, 2); assertEquals("data length 4", 2, newDataStorage.getSize()); arrayAccess = newDataStorage.getArray(DataStorage.READ, 0, 2); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("[0]", 3, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("[1]", 4, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1]); assertEquals("array length 4", 2, arrayAccess.getLength()); arrayAccess.close(); newDataStorage.copyFrom(dataStorage, 4); assertEquals("data length 5", 4, newDataStorage.getSize()); arrayAccess = newDataStorage.getArray(DataStorage.READ, 0, 4); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("[0]", 3, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("[1]", 4, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1]); assertEquals("[2]", 0, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 2]); assertEquals("[3]", 0, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3]); assertEquals("array length 5", 4, arrayAccess.getLength()); arrayAccess.close(); } public void testCopyFromSelf() { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(4); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, 4); arrayAccess.getRawtypeData()[arrayAccess.getOffset()] = (rawtype) 1; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1] = (rawtype) 2; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 2] = (rawtype) 3; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3] = (rawtype) 4; arrayAccess.close(); dataStorage.copyFrom(dataStorage, 2); assertEquals("data length 2", 2, dataStorage.getSize()); arrayAccess = dataStorage.getArray(DataStorage.READ, 0, 2); assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("[0]", 1, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("[1]", 2, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1]); assertEquals("array length 1", 2, arrayAccess.getLength()); arrayAccess.close(); } public void testCopyFromBig() { ApfloatContext ctx = ApfloatContext.getContext(); int size = ctx.getBlockSize() / RawType.BYTES * 7 / 2; DataStorage dataStorage = createDataStorage(); dataStorage.setSize(size); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, size); for (int i = 0; i < size; i++) { arrayAccess.getRawtypeData()[arrayAccess.getOffset() + i] = (rawtype) (i + 1); } arrayAccess.close(); size = ctx.getBlockSize() / RawType.BYTES * 5 / 2; DataStorage newDataStorage = createDataStorage(); newDataStorage.copyFrom(dataStorage, size); assertEquals("data length", size, newDataStorage.getSize()); arrayAccess = newDataStorage.getArray(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("[" + i + "]", i + 1, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + i]); } arrayAccess.close(); } public void testIterator() { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(4); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.WRITE, 0, 4); try { iterator.getRawtype(); fail("Write iterator can be read"); } catch (IllegalStateException ise) { // OK; no read access } iterator.setRawtype((rawtype) 1); iterator.next(); iterator.setRawtype((rawtype) 2); iterator.next(); iterator.setRawtype((rawtype) 3); iterator.next(); iterator.setRawtype((rawtype) 4); iterator.next(); assertEquals("write iterator end", false, iterator.hasNext()); iterator = dataStorage.iterator(DataStorage.READ, 1, 3); try { iterator.setRawtype((rawtype) 5); fail("Read iterator can be written"); } catch (IllegalStateException ise) { // OK; no write access } assertEquals("1st forward read", 2, (int) iterator.getRawtype()); iterator.next(); assertEquals("2nd forward read", 3, (int) iterator.getRawtype()); iterator.next(); assertEquals("1st forward read iterator end", false, iterator.hasNext()); iterator = dataStorage.iterator(DataStorage.READ, 3, 1); assertEquals("1st reverse read", 3, (int) iterator.getRawtype()); iterator.next(); assertEquals("2nd reverse read", 2, (int) iterator.getRawtype()); iterator.next(); assertEquals("1st reverse read iterator end", false, iterator.hasNext()); iterator = dataStorage.iterator(DataStorage.READ, 4, 0); assertEquals("1st full reverse read", 4, (int) iterator.getRawtype()); iterator.next(); assertEquals("2nd full reverse read", 3, (int) iterator.getRawtype()); iterator.next(); assertEquals("3rd full reverse read", 2, (int) iterator.getRawtype()); iterator.next(); assertEquals("4th full reverse read", 1, (int) iterator.getRawtype()); iterator.next(); assertEquals("2nd reverse read iterator end", false, iterator.hasNext()); try { iterator.next(); fail("Iterate past end"); } catch (IllegalStateException ise) { // OK; at end } try { dataStorage.iterator(0, 0, 4); fail("No-access iterator accepted"); } catch (IllegalArgumentException iae) { // OK; no access mode } } public void testIteratorBig() { ApfloatContext ctx = ApfloatContext.getContext(); int size = ctx.getBlockSize() / RawType.BYTES * 7 / 2; DataStorage dataStorage = createDataStorage(); dataStorage.setSize(size); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.WRITE, 0, size); for (int i = 0; i < size; i++) { iterator.setRawtype((rawtype) i + 1); iterator.next(); } assertEquals("write iterator end", false, iterator.hasNext()); size = ctx.getBlockSize() / RawType.BYTES * 2; iterator = dataStorage.iterator(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("[" + i + "]", i + 1, (int) iterator.getRawtype()); iterator.next(); } assertEquals("read iterator end", false, iterator.hasNext()); } public void testSubsequenceIterator() { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(6); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, 6); arrayAccess.getRawtypeData()[arrayAccess.getOffset()] = (rawtype) 1; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1] = (rawtype) 2; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 2] = (rawtype) 3; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3] = (rawtype) 4; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 4] = (rawtype) 5; arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 5] = (rawtype) 6; arrayAccess.close(); dataStorage = dataStorage.subsequence(1, 4); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 1, 3); assertEquals("1st forward read", 3, (int) iterator.getRawtype()); iterator.next(); assertEquals("2nd forward read", 4, (int) iterator.getRawtype()); iterator.next(); assertEquals("forward read iterator end", false, iterator.hasNext()); iterator = dataStorage.iterator(DataStorage.READ, 4, 0); assertEquals("1st reverse read", 5, (int) iterator.getRawtype()); iterator.next(); assertEquals("2nd reverse read", 4, (int) iterator.getRawtype()); iterator.next(); assertEquals("3rd reverse read", 3, (int) iterator.getRawtype()); iterator.next(); assertEquals("4th reverse read", 2, (int) iterator.getRawtype()); iterator.next(); assertEquals("reverse read iterator end", false, iterator.hasNext()); dataStorage = dataStorage.subsequence(1, 2); iterator = dataStorage.iterator(DataStorage.READ, 1, 2); assertEquals("1st subsub read", 4, (int) iterator.getRawtype()); iterator.next(); assertEquals("subsub iterator end", false, iterator.hasNext()); } public void testGenericIterator() { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(1); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.WRITE, 0, 1); iterator.set(RawType.TYPE, (rawtype) 1); iterator.next(); iterator = dataStorage.iterator(DataStorage.READ, 0, 1); assertEquals("read", (rawtype) 1, (rawtype) iterator.get(RawType.TYPE)); iterator.next(); } public void testUnsupportedIterator() throws Exception { DataStorage dataStorage = createDataStorage(); dataStorage.setSize(1); Class[] types = { Integer.TYPE, Long.TYPE, Float.TYPE, Double.TYPE }; for (Class type : types) { if (!type.equals(RawType.TYPE)) { runUnsupportedIterator(type, dataStorage); } } if (!Integer.TYPE.equals(RawType.TYPE)) { try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); iterator.getInt(); fail("Get as int allowed"); } catch (UnsupportedOperationException uoe) { // OK } try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.WRITE, 0, 1); iterator.setInt(1); fail("Set as int allowed"); } catch (UnsupportedOperationException uoe) { // OK } } if (!Long.TYPE.equals(RawType.TYPE)) { try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); iterator.getLong(); fail("Get as long allowed"); } catch (UnsupportedOperationException uoe) { // OK } try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.WRITE, 0, 1); iterator.setLong(1L); fail("Set as long allowed"); } catch (UnsupportedOperationException uoe) { // OK } } if (!Float.TYPE.equals(RawType.TYPE)) { try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); iterator.getFloat(); fail("Get as float allowed"); } catch (UnsupportedOperationException uoe) { // OK } try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.WRITE, 0, 1); iterator.setFloat(1.0f); fail("Set as float allowed"); } catch (UnsupportedOperationException uoe) { // OK } } if (!Double.TYPE.equals(RawType.TYPE)) { try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); iterator.getDouble(); fail("Get as double allowed"); } catch (UnsupportedOperationException uoe) { // OK } try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.WRITE, 0, 1); iterator.setDouble(1.0); fail("Set as double allowed"); } catch (UnsupportedOperationException uoe) { // OK } } } private void runUnsupportedIterator(Class type, DataStorage dataStorage) throws Exception { try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); iterator.get(type); fail("Generic get as " + type.getName() + " allowed"); } catch (UnsupportedOperationException uoe) { // OK } try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.WRITE, 0, 1); @SuppressWarnings("unchecked") T value = (T) RawType.class.getMethod("valueOf", String.class).invoke(null, "0"); iterator.set(type, value); fail("Generic set as " + type.getName() + " allowed"); } catch (UnsupportedOperationException uoe) { // OK } try { DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.WRITE, 0, 1); @SuppressWarnings("unchecked") Class correctType = (Class) RawType.TYPE; Object array = Array.newInstance(type, 1); @SuppressWarnings("unchecked") T value = (T) Array.get(array, 0); iterator.set(correctType, value); fail("Generic set with value type " + type.getName() + " allowed"); } catch (IllegalArgumentException iae) { // OK } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeDiskDataStorageTest.java000066400000000000000000000170341461767713300323770ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeDiskDataStorageTest extends RawtypeDataStorageTestCase { private RawtypeDiskDataStorageTest() { } public RawtypeDiskDataStorageTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new RawtypeDiskDataStorageTest().realSuite(); suite.addTest(new RawtypeDiskDataStorageTest("testGetPartialArray")); suite.addTest(new RawtypeDiskDataStorageTest("testGetPartialArrayBig")); suite.addTest(new RawtypeDiskDataStorageTest("testGetPartialArrayWide")); suite.addTest(new RawtypeDiskDataStorageTest("testGetPartialArrayWideBig")); suite.addTest(new RawtypeDiskDataStorageTest("testGetTransposedArray")); suite.addTest(new RawtypeDiskDataStorageTest("testGetTransposedArrayBig")); suite.addTest(new RawtypeDiskDataStorageTest("testGetTransposedArrayWide")); suite.addTest(new RawtypeDiskDataStorageTest("testGetTransposedArrayWideBig")); suite.addTest(new RawtypeDiskDataStorageTest("testIsCached")); return suite; } @Override public TestCase createTestCase(String methodName) { return new RawtypeDiskDataStorageTest(methodName); } @Override public DataStorage createDataStorage() throws ApfloatRuntimeException { return new RawtypeDiskDataStorage(); } public static void testGetPartialArray() { runGetPartialArray(64, 128, 8); } public static void testGetPartialArrayBig() { runGetPartialArray(1024, 2048, 32); } public static void testGetPartialArrayWide() { runGetPartialArray(8, 64, 16); } public static void testGetPartialArrayWideBig() { runGetPartialArray(32, 2048, 128); } public static void testGetTransposedArray() { runGetTransposedArray(64, 128, 8); } public static void testGetTransposedArrayBig() { runGetTransposedArray(1024, 2048, 32); } public static void testGetTransposedArrayWide() { runGetTransposedArray(8, 64, 16); } public static void testGetTransposedArrayWideBig() { runGetTransposedArray(32, 2048, 128); } public static void testIsCached() { assertFalse(new RawtypeDiskDataStorage().isCached()); } private static void runGetPartialArray(int n1, int n2, int b) { int size = n1 * n2; DataStorage dataStorage = new RawtypeDiskDataStorage(); dataStorage.setSize(size + 5); dataStorage = dataStorage.subsequence(5, size); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, size); for (int i = 0; i < size; i++) { arrayAccess.getRawtypeData()[arrayAccess.getOffset() + i] = (rawtype) (i + 1); } arrayAccess.close(); arrayAccess = dataStorage.getArray(DataStorage.READ_WRITE, 2 * b, b, n1); assertEquals("array size", n1 * b, arrayAccess.getLength()); for (int i = 0; i < n1; i++) { for (int j = 0; j < b; j++) { rawtype value = arrayAccess.getRawtypeData()[arrayAccess.getOffset() + b * i + j]; assertEquals("[" + i + "][" + j + "]", n2 * i + 2 * b + j + 1, (int) value); arrayAccess.getRawtypeData()[arrayAccess.getOffset() + b * i + j] = -value; } } arrayAccess.close(); arrayAccess = dataStorage.getArray(DataStorage.READ, 0, size); for (int i = 0; i < n1; i++) { for (int j = 0; j < n2; j++) { rawtype value = arrayAccess.getRawtypeData()[arrayAccess.getOffset() + n2 * i + j], expectedValue = n2 * i + j + 1; if (j >= 2 * b && j < 3 * b) { assertEquals("[" + i + "][" + j + "]", (int) -expectedValue, (int) value); } else { assertEquals("[" + i + "][" + j + "]", (int) expectedValue, (int) value); } } } arrayAccess.close(); } private static void runGetTransposedArray(int n1, int n2, int b) { int size = n1 * n2; DataStorage dataStorage = new RawtypeDiskDataStorage(); dataStorage.setSize(size + 5); dataStorage = dataStorage.subsequence(5, size); ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, size); for (int i = 0; i < size; i++) { arrayAccess.getRawtypeData()[arrayAccess.getOffset() + i] = (rawtype) (i + 1); } arrayAccess.close(); arrayAccess = dataStorage.getTransposedArray(DataStorage.READ_WRITE, 2 * b, b, n1); assertEquals("array size", b * n1, arrayAccess.getLength()); for (int i = 0; i < b; i++) { for (int j = 0; j < n1; j++) { rawtype value = arrayAccess.getRawtypeData()[arrayAccess.getOffset() + n1 * i + j]; assertEquals("[" + i + "][" + j + "]", n2 * j + 2 * b + i + 1, (int) value); arrayAccess.getRawtypeData()[arrayAccess.getOffset() + n1 * i + j] = -value; } } arrayAccess.close(); arrayAccess = dataStorage.getArray(DataStorage.READ, 0, size); for (int i = 0; i < n1; i++) { for (int j = 0; j < n2; j++) { rawtype value = arrayAccess.getRawtypeData()[arrayAccess.getOffset() + n2 * i + j], expectedValue = n2 * i + j + 1; if (j >= 2 * b && j < 3 * b) { assertEquals("[" + i + "][" + j + "]", (int) -expectedValue, (int) value); } else { assertEquals("[" + i + "][" + j + "]", (int) expectedValue, (int) value); } } } arrayAccess.close(); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeElementaryModMathTest.java000066400000000000000000000112471461767713300327450ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Random; import java.math.BigInteger; import junit.framework.TestSuite; /** * @version 1.0 * @author Mikko Tommila */ public class RawtypeElementaryModMathTest extends RawtypeTestCase implements RawtypeModConstants { public RawtypeElementaryModMathTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeElementaryModMathTest("testMultiply")); suite.addTest(new RawtypeElementaryModMathTest("testAdd")); suite.addTest(new RawtypeElementaryModMathTest("testSubtract")); return suite; } public static void testMultiply() { RawtypeElementaryModMath math = new RawtypeElementaryModMath(); Random random = new Random(); for (int modulus = 0; modulus < 3; modulus++) { math.setModulus(MODULUS[modulus]); BigInteger m = BigInteger.valueOf((long) MODULUS[modulus]); long lm = (long) MODULUS[modulus]; runOneMultiply(math, 0, 0, m); runOneMultiply(math, 1, 0, m); runOneMultiply(math, 0, 1, m); runOneMultiply(math, 0, lm - 1, m); runOneMultiply(math, lm - 1, 0, m); runOneMultiply(math, 1, lm - 1, m); runOneMultiply(math, lm - 1, 1, m); runOneMultiply(math, lm - 1, lm - 1, m); for (int i = 0; i < 1000; i++) { long x = Math.abs(random.nextLong()) % lm, y = Math.abs(random.nextLong()) % lm; runOneMultiply(math, x, y, m); runOneMultiply(math, x, lm - 1, m); runOneMultiply(math, lm - 1, x, m); } } } private static void runOneMultiply(RawtypeElementaryModMath math, long x, long y, BigInteger m) { long r = (long) math.modMultiply((rawtype) x, (rawtype) y); BigInteger xTrue = BigInteger.valueOf(x), yTrue = BigInteger.valueOf(y), rTrue = xTrue.multiply(yTrue).mod(m); assertEquals(x + " * " + y + " % " + m, rTrue.longValue(), r); } public static void testAdd() { RawtypeElementaryModMath math = new RawtypeElementaryModMath(); math.setModulus(MODULUS[0]); assertEquals("no overflow", (long) MODULUS[0] - 5, (long) math.modAdd(MODULUS[0] - (rawtype) 8, (rawtype) 3)); assertEquals("just no overflow", (long) MODULUS[0] - 1, (long) math.modAdd(MODULUS[0] - (rawtype) 4, (rawtype) 3)); assertEquals("just overflow", 0, (long) math.modAdd(MODULUS[0] - (rawtype) 3, (rawtype) 3)); assertEquals("overflow", 5, (long) math.modAdd(MODULUS[0] - (rawtype) 3, (rawtype) 8)); } public static void testSubtract() { RawtypeElementaryModMath math = new RawtypeElementaryModMath(); math.setModulus(MODULUS[0]); assertEquals("no overflow", 5, (long) math.modSubtract((rawtype) 8, (rawtype) 3)); assertEquals("just no overflow", 0, (long) math.modSubtract((rawtype) 3, (rawtype) 3)); assertEquals("just overflow", (long) MODULUS[0] - 1, (long) math.modSubtract((rawtype) 3, (rawtype) 4)); assertEquals("overflow", (long) MODULUS[0] - 5, (long) math.modSubtract((rawtype) 3, (rawtype) 8)); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeFactor3NTTStrategyTest.java000066400000000000000000000164051461767713300330010ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Arrays; import java.util.concurrent.ExecutorService; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.8.0 * @author Mikko Tommila */ public class RawtypeFactor3NTTStrategyTest extends RawtypeNTTStrategyTestCase { public RawtypeFactor3NTTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeFactor3NTTStrategyTest("testForward")); suite.addTest(new RawtypeFactor3NTTStrategyTest("testRoundTrip")); suite.addTest(new RawtypeFactor3NTTStrategyTest("testRoundTripParallel")); suite.addTest(new RawtypeFactor3NTTStrategyTest("testRoundTrip2")); suite.addTest(new RawtypeFactor3NTTStrategyTest("testRoundTrip2Parallel")); return suite; } public static void testForward() { for (int modulus = 0; modulus < 3; modulus++) { int size = 3 * 2048; DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); rawtype[] data = getPlainArray(dataStorage), expectedTransform = ntt(data, modulus); Arrays.sort(expectedTransform); NTTStrategy nttStrategy = new Factor3NTTStrategy(new RawtypeTableFNTStrategy()); nttStrategy.transform(dataStorage, modulus); rawtype[] actualTransform = getPlainArray(dataStorage); Arrays.sort(actualTransform); assertEquals("expected length", size, expectedTransform.length); assertEquals("actual length", size, actualTransform.length); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], [" + i + "]", (long) expectedTransform[i], (long) actualTransform[i]); } } } public static void testRoundTrip() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(1); runRoundTrip(); ctx.setNumberOfProcessors(numberOfProcessors); } public static void testRoundTripParallel() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ExecutorService executorService = ctx.getExecutorService(); ctx.setNumberOfProcessors(4); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); runRoundTrip(); ctx.setNumberOfProcessors(numberOfProcessors); ctx.setExecutorService(executorService); } private static void runRoundTrip() { int size = (int) Math.min(3 * 1048576, RawtypeModConstants.MAX_TRANSFORM_LENGTH); // Will use six-step transform DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); for (int modulus = 0; modulus < 3; modulus++) { Factor3NTTStrategy nttStrategy = new Factor3NTTStrategy(new SixStepFNTStrategy()); nttStrategy.transform(dataStorage, modulus); assertEquals("transformed size", size, dataStorage.getSize()); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); assertTrue("transformed [0]", 6 != (long) iterator.getRawtype()); iterator.close(); nttStrategy.inverseTransform(dataStorage, modulus, size); assertEquals("inverse transformed size", size, dataStorage.getSize()); iterator = dataStorage.iterator(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], round-tripped [" + i + "]", i + 6, (long) iterator.getRawtype()); iterator.next(); } } } public static void testRoundTrip2() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(1); runRoundTrip2(); ctx.setNumberOfProcessors(numberOfProcessors); } public static void testRoundTrip2Parallel() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ExecutorService executorService = ctx.getExecutorService(); ctx.setNumberOfProcessors(4); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); runRoundTrip2(); ctx.setNumberOfProcessors(numberOfProcessors); ctx.setExecutorService(executorService); } private static void runRoundTrip2() { int size = 2048; // Will fall back to the power-of-two length transform DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); for (int modulus = 0; modulus < 3; modulus++) { Factor3NTTStrategy nttStrategy = new Factor3NTTStrategy(new RawtypeTableFNTStrategy()); nttStrategy.transform(dataStorage, modulus); assertEquals("transformed size", size, dataStorage.getSize()); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); assertTrue("transformed [0]", 6 != (long) iterator.getRawtype()); iterator.close(); nttStrategy.inverseTransform(dataStorage, modulus, size); assertEquals("inverse transformed size", size, dataStorage.getSize()); iterator = dataStorage.iterator(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], round-tripped [" + i + "]", i + 6, (long) iterator.getRawtype()); iterator.next(); } } } } RawtypeKaratsubaConvolutionStrategyTest.java000066400000000000000000000073501461767713300352070ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.4 * @author Mikko Tommila */ public class RawtypeKaratsubaConvolutionStrategyTest extends RawtypeConvolutionStrategyTestCase implements RawtypeRadixConstants { public RawtypeKaratsubaConvolutionStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeKaratsubaConvolutionStrategyTest("testFull")); return suite; } public static void testFull() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4, (rawtype) 5, (rawtype) 6, (rawtype) 7, (rawtype) 8 }), src2 = createDataStorage(new rawtype[] { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4, (rawtype) 5, (rawtype) 6 }), src9 = createDataStorage(new rawtype[] { b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1 }), src99 = createDataStorage(new rawtype[] { b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1 }); ConvolutionStrategy convolutionStrategy = new RawtypeKaratsubaConvolutionStrategy(radix); // Will only test Karatsuba actually if CUTOFF_POINT is set to at most 6 DataStorage result = convolutionStrategy.convolute(src1, src2, 14); check("normal", radix, new rawtype[] { 0, (rawtype) 1, (rawtype) 4, (rawtype) 10, (rawtype) 20, (rawtype) 35, (rawtype) 56, (rawtype) 77, (rawtype) 98, (rawtype) 110, (rawtype) 112, (rawtype) 103, (rawtype) 82, (rawtype) 48 }, result); // Will only test Karatsuba actually if CUTOFF_POINT is set to at most 18 result = convolutionStrategy.convolute(src9, src99, 63); check("max", radix, new rawtype[] { b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1 - (rawtype) 1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, b1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (rawtype) 1 }, result); } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeMatrixStrategyTest.java000066400000000000000000000247361461767713300323640ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeMatrixStrategyTest extends RawtypeTestCase { public RawtypeMatrixStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeMatrixStrategyTest("testTransposeSquare")); suite.addTest(new RawtypeMatrixStrategyTest("testTransposeSquarePart")); suite.addTest(new RawtypeMatrixStrategyTest("testTransposeWide")); suite.addTest(new RawtypeMatrixStrategyTest("testTransposeTall")); suite.addTest(new RawtypeMatrixStrategyTest("testPermuteToDoubleWidth")); suite.addTest(new RawtypeMatrixStrategyTest("testPermuteToHalfWidth")); return suite; } private static ArrayAccess getArray(int count) { rawtype[] data = new rawtype[count + 5]; ArrayAccess arrayAccess = new RawtypeMemoryArrayAccess(data, 5, count); for (int i = 0; i < count; i++) { data[i + 5] = (rawtype) (i + 1); } return arrayAccess; } public static void testTransposeSquare() { ArrayAccess arrayAccess = getArray(16); new RawtypeMatrixStrategy().transpose(arrayAccess, 4, 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("16 elem [" + i + "][" + j + "]", 4 * j + i + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 4 * i + j]); } } arrayAccess = getArray(18).subsequence(1, 16); new RawtypeMatrixStrategy().transpose(arrayAccess, 4, 4); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("16 elem sub [" + i + "][" + j + "]", 4 * j + i + 2, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 4 * i + j]); } } ApfloatContext ctx = ApfloatContext.getContext(); int cacheBurstBlockSize = Util.round2down(ctx.getCacheBurst() / RawType.BYTES), // Cache burst in rawtypes cacheL1Size = Util.sqrt4down(ctx.getCacheL1Size() / RawType.BYTES), // To fit in processor L1 cache cacheL2Size = Util.sqrt4down(ctx.getCacheL2Size() / RawType.BYTES), // To fit in processor L2 cache bigSize = cacheL2Size * 2; // To not fit in processor L2 cache arrayAccess = getArray(cacheBurstBlockSize * cacheBurstBlockSize); new RawtypeMatrixStrategy().transpose(arrayAccess, cacheBurstBlockSize, cacheBurstBlockSize); for (int i = 0; i < cacheBurstBlockSize; i++) { for (int j = 0; j < cacheBurstBlockSize; j++) { assertEquals("cacheBurstBlockSize [" + i + "][" + j + "]", cacheBurstBlockSize * j + i + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + cacheBurstBlockSize * i + j]); } } arrayAccess = getArray(cacheL1Size * cacheL1Size); new RawtypeMatrixStrategy().transpose(arrayAccess, cacheL1Size, cacheL1Size); for (int i = 0; i < cacheL1Size; i++) { for (int j = 0; j < cacheL1Size; j++) { assertEquals("cacheL1Size [" + i + "][" + j + "]", cacheL1Size * j + i + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + cacheL1Size * i + j]); } } arrayAccess = getArray(cacheL2Size * cacheL2Size); new RawtypeMatrixStrategy().transpose(arrayAccess, cacheL2Size, cacheL2Size); for (int i = 0; i < cacheL2Size; i++) { for (int j = 0; j < cacheL2Size; j++) { assertEquals("cacheL2Size [" + i + "][" + j + "]", cacheL2Size * j + i + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + cacheL2Size * i + j]); } } arrayAccess = getArray(bigSize * bigSize); new RawtypeMatrixStrategy().transpose(arrayAccess, bigSize, bigSize); for (int i = 0; i < bigSize; i++) { for (int j = 0; j < bigSize; j++) { assertEquals("bigSize [" + i + "][" + j + "]", bigSize * j + i + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + bigSize * i + j]); } } } public static void testTransposeSquarePart() { ArrayAccess arrayAccess = getArray(32); new RawtypeMatrixStrategy().transposeSquare(arrayAccess, 4, 8); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("1st transposed [" + i + "][" + j + "]", 8 * j + i + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 8 * i + j]); } for (int j = 4; j < 8; j++) { assertEquals("1st untransposed [" + i + "][" + j + "]", 8 * i + j + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 8 * i + j]); } } arrayAccess = getArray(32); new RawtypeMatrixStrategy().transposeSquare(arrayAccess.subsequence(4, 28), 4, 8); for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { assertEquals("2nd untransposed [" + i + "][" + j + "]", 8 * i + j + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 8 * i + j]); } for (int j = 4; j < 8; j++) { assertEquals("2nd transposed [" + i + "][" + j + "]", 8 * (j - 4) + (i + 4) + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 8 * i + j]); } } } public static void testTransposeWide() { ApfloatContext ctx = ApfloatContext.getContext(); int cacheL2Size = Util.sqrt4down(ctx.getCacheL2Size() / RawType.BYTES), // To fit in processor L2 cache bigSize = cacheL2Size * 2; // To not fit in processor L2 cache ArrayAccess arrayAccess = getArray(2 * bigSize * bigSize + 5).subsequence(5, 2 * bigSize * bigSize); new RawtypeMatrixStrategy().transpose(arrayAccess, bigSize, 2 * bigSize); for (int i = 0; i < 2 * bigSize; i++) { for (int j = 0; j < bigSize; j++) { assertEquals("transposed [" + i + "][" + j + "]", 2 * bigSize * j + i + 6, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + bigSize * i + j]); } } } public static void testTransposeTall() { ApfloatContext ctx = ApfloatContext.getContext(); int cacheL2Size = Util.sqrt4down(ctx.getCacheL2Size() / RawType.BYTES), // To fit in processor L2 cache bigSize = cacheL2Size * 2; // To not fit in processor L2 cache ArrayAccess arrayAccess = getArray(2 * bigSize * bigSize + 5).subsequence(5, 2 * bigSize * bigSize); new RawtypeMatrixStrategy().transpose(arrayAccess, 2 * bigSize, bigSize); for (int i = 0; i < bigSize; i++) { for (int j = 0; j < 2 * bigSize; j++) { assertEquals("transposed [" + i + "][" + j + "]", bigSize * j + i + 6, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 2 * bigSize * i + j]); } } } public static void testPermuteToDoubleWidth() { ArrayAccess arrayAccess = getArray(256); new RawtypeMatrixStrategy().permuteToDoubleWidth(arrayAccess, 8, 32); for (int i = 0; i < 4; i++) { for (int j = 0; j < 32; j++) { assertEquals("permuted to double width [" + i + "][" + j + "]", 32 * i + j + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 64 * i + j]); } for (int j = 32; j < 64; j++) { assertEquals("permuted to double width [" + i + "][" + j + "]", 32 * i + j - 32 + 128 + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 64 * i + j]); } } } public static void testPermuteToHalfWidth() { ArrayAccess arrayAccess = getArray(256); new RawtypeMatrixStrategy().permuteToHalfWidth(arrayAccess, 4, 64); for (int i = 0; i < 4; i++) { for (int j = 0; j < 32; j++) { assertEquals("permuted to half width [" + i + "][" + j + "]", 64 * i + j + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 32 * i + j]); } } for (int i = 4; i < 8; i++) { for (int j = 0; j < 32; j++) { assertEquals("permuted to half width [" + i + "][" + j + "]", 64 * (i - 4) + j + 32 + 1, (long) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 32 * i + j]); } } } } RawtypeMediumConvolutionStrategyTest.java000066400000000000000000000056621461767713300345160ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.0 * @author Mikko Tommila */ public class RawtypeMediumConvolutionStrategyTest extends RawtypeConvolutionStrategyTestCase implements RawtypeRadixConstants { public RawtypeMediumConvolutionStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeMediumConvolutionStrategyTest("testFull")); return suite; } public static void testFull() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4 }), src2 = createDataStorage(new rawtype[] { (rawtype) 5, (rawtype) 6 }), src9 = createDataStorage(new rawtype[] { b1, b1, b1 }), src99 = createDataStorage(new rawtype[] { b1, b1, b1, b1, b1, b1 }); ConvolutionStrategy convolutionStrategy = new RawtypeMediumConvolutionStrategy(radix); DataStorage result = convolutionStrategy.convolute(src1, src2, 6); check("normal", radix, new rawtype[] { 0, (rawtype) 5, (rawtype) 16, (rawtype) 27, (rawtype) 38, (rawtype) 24 }, result); result = convolutionStrategy.convolute(src9, src99, 9); check("max", radix, new rawtype[] { b1, b1, b1 - (rawtype) 1, b1, b1, b1, 0, 0, (rawtype) 1 }, result); } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeMemoryArrayAccessTest.java000066400000000000000000000063761461767713300327660ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeMemoryArrayAccessTest extends RawtypeTestCase { public RawtypeMemoryArrayAccessTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeMemoryArrayAccessTest("testGet")); suite.addTest(new RawtypeMemoryArrayAccessTest("testSubsequence")); return suite; } public static void testGet() { rawtype[] data = { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4 }; try (ArrayAccess arrayAccess = new RawtypeMemoryArrayAccess(data, 0, 4)) { assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("[0]", 1, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("[1]", 2, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1]); assertEquals("[2]", 3, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 2]); assertEquals("[3]", 4, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 3]); assertEquals("length", 4, arrayAccess.getLength()); } } public static void testSubsequence() { rawtype[] data = { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4 }; try (ArrayAccess baseArrayAccess = new RawtypeMemoryArrayAccess(data, 0, 4); ArrayAccess arrayAccess = baseArrayAccess.subsequence(1, 2)) { assertTrue("class", arrayAccess.getData() instanceof rawtype[]); assertEquals("[0]", 2, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset()]); assertEquals("[1]", 3, (int) arrayAccess.getRawtypeData()[arrayAccess.getOffset() + 1]); assertEquals("length", 2, arrayAccess.getLength()); } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeMemoryDataStorageTest.java000066400000000000000000000045261461767713300327570ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestCase; import junit.framework.TestSuite; /** * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeMemoryDataStorageTest extends RawtypeDataStorageTestCase { private RawtypeMemoryDataStorageTest() { } public RawtypeMemoryDataStorageTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new RawtypeMemoryDataStorageTest().realSuite(); suite.addTest(new RawtypeDiskDataStorageTest("testIsCached")); return suite; } @Override public TestCase createTestCase(String methodName) { return new RawtypeMemoryDataStorageTest(methodName); } @Override public DataStorage createDataStorage() throws ApfloatRuntimeException { return new RawtypeMemoryDataStorage(); } public static void testIsCached() { assertTrue(new RawtypeDiskDataStorage().isCached()); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeModMathTest.java000066400000000000000000000154261461767713300307220ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2024 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Random; import junit.framework.TestSuite; /** * @version 1.13.0 * @author Mikko Tommila */ public class RawtypeModMathTest extends RawtypeTestCase implements RawtypeModConstants { public RawtypeModMathTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeModMathTest("testCreateWTable")); suite.addTest(new RawtypeModMathTest("testGetForwardNthRoot")); suite.addTest(new RawtypeModMathTest("testGetInverseNthRoot")); suite.addTest(new RawtypeModMathTest("testInverse")); suite.addTest(new RawtypeModMathTest("testDivide")); suite.addTest(new RawtypeModMathTest("testNegate")); suite.addTest(new RawtypeModMathTest("testPow")); return suite; } public static void testCreateWTable() { RawtypeModMath math = new RawtypeModMath(); math.setModulus(MODULUS[0]); rawtype[] wTable = math.createWTable((rawtype) 2, 5); assertEquals("[0]", 1, (long) wTable[0]); assertEquals("[1]", 2, (long) wTable[1]); assertEquals("[2]", 4, (long) wTable[2]); assertEquals("[3]", 8, (long) wTable[3]); assertEquals("[4]", 16, (long) wTable[4]); } public static void testGetForwardNthRoot() { RawtypeModMath math = new RawtypeModMath(); math.setModulus(MODULUS[0]); rawtype w = math.getForwardNthRoot(PRIMITIVE_ROOT[0], 4); assertEquals("w^(n/2)", (long) MODULUS[0] - 1, (long) math.modMultiply(w, w)); assertEquals("w^n", 1, (long) math.modMultiply(w, math.modMultiply(w, math.modMultiply(w, w)))); } public static void testGetInverseNthRoot() { RawtypeModMath math = new RawtypeModMath(); math.setModulus(MODULUS[0]); rawtype w = math.getInverseNthRoot(PRIMITIVE_ROOT[0], 4); assertEquals("w^(n/2)", (long) MODULUS[0] - 1, (long) math.modMultiply(w, w)); assertEquals("w^n", 1, (long) math.modMultiply(w, math.modMultiply(w, math.modMultiply(w, w)))); assertTrue("inverse vs. forward", math.getForwardNthRoot(PRIMITIVE_ROOT[0], 4) != w); } public static void testInverse() { RawtypeModMath math = new RawtypeModMath(); Random random = new Random(); for (int modulus = 0; modulus < 3; modulus++) { math.setModulus(MODULUS[modulus]); long lm = (long) MODULUS[modulus], x; x = 1; assertEquals(x + " ^ -1 % " + lm, 1L, (long) math.modMultiply(math.modInverse((rawtype) x), (rawtype) x)); x = lm - 1; assertEquals(x + " ^ -1 % " + lm, 1L, (long) math.modMultiply(math.modInverse((rawtype) x), (rawtype) x)); for (int i = 0; i < 1000; i++) { x = Math.abs(random.nextLong()) % (lm - 1) + 1; assertEquals(x + " ^ -1 % " + lm, 1L, (long) math.modMultiply(math.modInverse((rawtype) x), (rawtype) x)); } } } public static void testDivide() { RawtypeModMath math = new RawtypeModMath(); Random random = new Random(); for (int modulus = 0; modulus < 3; modulus++) { math.setModulus(MODULUS[modulus]); long lm = (long) MODULUS[modulus], x, y; x = 0; y = 1; assertEquals(x + " / " + y + " % " + lm, x, (long) math.modMultiply(math.modDivide((rawtype) x, (rawtype) y), (rawtype) y)); x = 0; y = lm - 1; assertEquals(x + " / " + y + " % " + lm, x, (long) math.modMultiply(math.modDivide((rawtype) x, (rawtype) y), (rawtype) y)); x = 1; y = 1; assertEquals(x + " / " + y + " % " + lm, x, (long) math.modMultiply(math.modDivide((rawtype) x, (rawtype) y), (rawtype) y)); x = lm - 1; y = lm - 1; assertEquals(x + " / " + y + " % " + lm, x, (long) math.modMultiply(math.modDivide((rawtype) x, (rawtype) y), (rawtype) y)); x = 1; y = lm - 1; assertEquals(x + " / " + y + " % " + lm, x, (long) math.modMultiply(math.modDivide((rawtype) x, (rawtype) y), (rawtype) y)); x = lm - 1; y = 1; assertEquals(x + " / " + y + " % " + lm, x, (long) math.modMultiply(math.modDivide((rawtype) x, (rawtype) y), (rawtype) y)); for (int i = 0; i < 1000; i++) { x = Math.abs(random.nextLong()) % lm; y = Math.abs(random.nextLong()) % (lm - 1) + 1; assertEquals(x + " / " + y + " % " + lm, x, (long) math.modMultiply(math.modDivide((rawtype) x, (rawtype) y), (rawtype) y)); } } } public static void testNegate() { RawtypeModMath math = new RawtypeModMath(); math.setModulus(MODULUS[0]); assertEquals("zero", 0, (long) math.negate(0)); assertEquals("non-zero", (long) MODULUS[0] - 1, (long) math.negate((rawtype) 1)); } public static void testPow() { RawtypeModMath math = new RawtypeModMath(); math.setModulus(MODULUS[0]); assertEquals("no overflow", 3125, (long) math.modPow((rawtype) 5, (rawtype) 5)); assertEquals("overflow", ((long) MODULUS[0] + 1) / 2, (long) math.modPow((rawtype) 2, (rawtype) -1)); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeNTTBuilderTest.java000066400000000000000000000062121461767713300313360ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.10.0 * @author Mikko Tommila */ public class RawtypeNTTBuilderTest extends RawtypeTestCase { public RawtypeNTTBuilderTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeNTTBuilderTest("testCreate")); return suite; } public static void testCreate() { NTTBuilder nttBuilder = new RawtypeNTTBuilder(); ApfloatContext ctx = ApfloatContext.getContext(); int cacheSize = ctx.getCacheL1Size() / RawType.BYTES; long maxMemoryBlockSize = ctx.getMaxMemoryBlockSize() / RawType.BYTES; assertTrue("Fits in cache", nttBuilder.createNTT(cacheSize / 2) instanceof RawtypeTableFNTStrategy); assertTrue("Fits in memory", nttBuilder.createNTT(Util.round2down(Math.min(maxMemoryBlockSize, Integer.MAX_VALUE))) instanceof SixStepFNTStrategy); assertTrue("Does not fit in memory", nttBuilder.createNTT(Util.round2down(maxMemoryBlockSize * 2)) instanceof TwoPassFNTStrategy); assertTrue("Factor 3", nttBuilder.createNTT(3) instanceof Factor3NTTStrategy); assertTrue("NTTStepStrategy", nttBuilder.createNTTSteps() instanceof NTTStepStrategy); assertTrue("NTTConvolutionStepStrategy", nttBuilder.createNTTConvolutionSteps() instanceof NTTConvolutionStepStrategy); assertTrue("Factor3NTTStepStrategy", nttBuilder.createFactor3NTTSteps() instanceof Factor3NTTStepStrategy); ctx.setMaxMemoryBlockSize(0x80000000L * RawType.BYTES); assertTrue("Does not fit in array", nttBuilder.createNTT(0x80000000L) instanceof TwoPassFNTStrategy); ctx.setMaxMemoryBlockSize(maxMemoryBlockSize * RawType.BYTES); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeNTTStrategyTestCase.java000066400000000000000000000117671461767713300323610ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; /** * @version 1.9.0 * @author Mikko Tommila */ public abstract class RawtypeNTTStrategyTestCase extends RawtypeTestCase implements RawtypeModConstants { protected RawtypeNTTStrategyTestCase(String methodName) { super(methodName); } protected static DataStorage createDataStorage(int size) { ApfloatContext ctx = ApfloatContext.getContext(); DataStorageBuilder dataStorageBuilder = ctx.getBuilderFactory().getDataStorageBuilder(); DataStorage dataStorage = dataStorageBuilder.createDataStorage(size * RawType.BYTES); dataStorage.setSize(size); try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.WRITE, 0, size)) { for (int i = 0; i < size; i++) { arrayAccess.getRawtypeData()[arrayAccess.getOffset() + i] = (rawtype) (i + 1); } } return dataStorage; } protected static rawtype[] getPlainArray(DataStorage dataStorage) { int size = (int) dataStorage.getSize(); rawtype[] data = new rawtype[size]; try (ArrayAccess arrayAccess = dataStorage.getArray(DataStorage.READ, 0, size)) { System.arraycopy(arrayAccess.getRawtypeData(), arrayAccess.getOffset(), data, 0, size); } return data; } protected static rawtype[] ntt(rawtype[] data, int modulus) { RawtypeModMath math = new RawtypeModMath(); math.setModulus(MODULUS[modulus]); rawtype[] transform = new rawtype[data.length]; rawtype w = math.getForwardNthRoot(PRIMITIVE_ROOT[modulus], data.length), wi = (rawtype) 1; for (int i = 0; i < data.length; i++) { rawtype wj = (rawtype) 1; for (int j = 0; j < data.length; j++) { transform[i] = math.modAdd(transform[i], math.modMultiply(wj, data[j])); wj = math.modMultiply(wj, wi); } wi = math.modMultiply(wi, w); } return transform; } protected static rawtype[] inverseNtt(rawtype[] data, int modulus) { RawtypeModMath math = new RawtypeModMath(); math.setModulus(MODULUS[modulus]); rawtype[] transform = new rawtype[data.length]; rawtype w = math.getInverseNthRoot(PRIMITIVE_ROOT[modulus], data.length), wi = (rawtype) 1; for (int i = 0; i < data.length; i++) { rawtype wj = (rawtype) 1; for (int j = 0; j < data.length; j++) { transform[i] = math.modAdd(transform[i], math.modMultiply(wj, data[j])); wj = math.modMultiply(wj, wi); } transform[i] = math.modDivide(transform[i], (rawtype) data.length); wi = math.modMultiply(wi, w); } return transform; } protected static void runRoundTrip(NTTStrategy nttStrategy, int size) { DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); for (int modulus = 0; modulus < 3; modulus++) { nttStrategy.transform(dataStorage, modulus); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); assertTrue("transformed [0]", 6 != (long) iterator.getRawtype()); iterator.close(); nttStrategy.inverseTransform(dataStorage, modulus, size); iterator = dataStorage.iterator(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("round-tripped [" + i + "]", i + 6, (long) iterator.getRawtype()); iterator.next(); } } } } RawtypeParallelThreeNTTConvolutionStrategyTest.java000066400000000000000000000064511461767713300364050ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.concurrent.Future; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @since 1.7.0 * @version 1.9.0 * @author Mikko Tommila */ public class RawtypeParallelThreeNTTConvolutionStrategyTest extends RawtypeThreeNTTConvolutionStrategyTest { public RawtypeParallelThreeNTTConvolutionStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeParallelThreeNTTConvolutionStrategyTest("testFull")); suite.addTest(new RawtypeParallelThreeNTTConvolutionStrategyTest("testTruncated")); suite.addTest(new RawtypeParallelThreeNTTConvolutionStrategyTest("testAuto")); suite.addTest(new RawtypeParallelThreeNTTConvolutionStrategyTest("testFullBig")); suite.addTest(new RawtypeParallelThreeNTTConvolutionStrategyTest("testFullBigParallel")); suite.addTest(new RawtypeParallelThreeNTTConvolutionStrategyTest("testTruncatedBig")); suite.addTest(new RawtypeParallelThreeNTTConvolutionStrategyTest("testAutoBig")); suite.addTest(new RawtypeParallelThreeNTTConvolutionStrategyTest("testAutoBigParallel")); suite.addTest(new RawtypeParallelThreeNTTConvolutionStrategyTest("testSharedMemoryLock")); return suite; } @Override protected ConvolutionStrategy createConvolutionStrategy(int radix, NTTStrategy transform) { return new ParallelThreeNTTConvolutionStrategy(radix, transform); } public void testSharedMemoryLock() throws Exception { ApfloatContext ctx = ApfloatContext.getContext(); long sharedMemoryTreshold = ctx.getSharedMemoryTreshold(); ctx.setSharedMemoryTreshold(16384); Future future = ctx.getExecutorService().submit(this::testFullHugeParallel); testFullHugeParallel(); future.get(); ctx.setSharedMemoryTreshold(sharedMemoryTreshold); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeScrambleTest.java000066400000000000000000000046371461767713300311230ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import junit.framework.TestSuite; /** * @version 1.0 * @author Mikko Tommila */ public class RawtypeScrambleTest extends RawtypeTestCase { public RawtypeScrambleTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeScrambleTest("testScramble")); return suite; } public static void testScramble() { int[] permutationTable = Scramble.createScrambleTable(8); rawtype[] ints = { (rawtype) -1, (rawtype) 0, (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4, (rawtype) 5, (rawtype) 6, (rawtype) 7 }; RawtypeScramble.scramble(ints, 1, permutationTable); assertEquals("[0]", 0, (int) ints[1]); assertEquals("[1]", 4, (int) ints[2]); assertEquals("[2]", 2, (int) ints[3]); assertEquals("[3]", 6, (int) ints[4]); assertEquals("[4]", 1, (int) ints[5]); assertEquals("[5]", 5, (int) ints[6]); assertEquals("[6]", 3, (int) ints[7]); assertEquals("[7]", 7, (int) ints[8]); } } RawtypeShortConvolutionStrategyTest.java000066400000000000000000000062021461767713300343640ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.0 * @author Mikko Tommila */ public class RawtypeShortConvolutionStrategyTest extends RawtypeConvolutionStrategyTestCase implements RawtypeRadixConstants { public RawtypeShortConvolutionStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeShortConvolutionStrategyTest("testFull")); return suite; } public static void testFull() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4 }), src2 = createDataStorage(new rawtype[] { (rawtype) 5 }), src3 = createDataStorage(new rawtype[] { (rawtype) 1 }), src9 = createDataStorage(new rawtype[] { b1 }), src99 = createDataStorage(new rawtype[] { b1, b1, b1, b1 }); ConvolutionStrategy convolutionStrategy = new RawtypeShortConvolutionStrategy(radix); DataStorage result = convolutionStrategy.convolute(src1, src2, 5); check("normal", radix, new rawtype[] { 0, (rawtype) 5, (rawtype) 10, (rawtype) 15, (rawtype) 20 }, result); result = convolutionStrategy.convolute(src9, src99, 5); check("max", radix, new rawtype[] { b1 - (rawtype) 1, b1, b1, b1, (rawtype) 1 }, result); result = convolutionStrategy.convolute(src3, src1, 5); check("one", radix, new rawtype[] { 0, (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4 }, result); } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeSixStepFNTStrategyTest.java000066400000000000000000000115421461767713300330560ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Arrays; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.8.0 * @author Mikko Tommila */ public class RawtypeSixStepFNTStrategyTest extends RawtypeNTTStrategyTestCase { public RawtypeSixStepFNTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeSixStepFNTStrategyTest("testForward")); suite.addTest(new RawtypeSixStepFNTStrategyTest("testForwardBig")); suite.addTest(new RawtypeSixStepFNTStrategyTest("testRoundTrip")); suite.addTest(new RawtypeSixStepFNTStrategyTest("testRoundTripBig")); suite.addTest(new RawtypeSixStepFNTStrategyTest("testRoundTripMultithread")); suite.addTest(new RawtypeSixStepFNTStrategyTest("testRoundTripMultithreadBig")); return suite; } public static void testForward() { runTestForward(1024); } public static void testForwardBig() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMemoryThreshold(8192); runTestForward(4096); } private static void runTestForward(int size) { for (int modulus = 0; modulus < 3; modulus++) { DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); rawtype[] data = getPlainArray(dataStorage), expectedTransform = ntt(data, modulus); RawtypeScramble.scramble(expectedTransform, 0, Scramble.createScrambleTable(size)); Arrays.sort(expectedTransform); AbstractStepFNTStrategy nttStrategy = new SixStepFNTStrategy(); nttStrategy.transform(dataStorage, modulus); rawtype[] actualTransform = getPlainArray(dataStorage); Arrays.sort(actualTransform); assertEquals("expected length", size, expectedTransform.length); assertEquals("actual length", size, actualTransform.length); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], [" + i + "]", (long) expectedTransform[i], (long) actualTransform[i]); } } } public static void testRoundTrip() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(1); runRoundTrip(1024); } public static void testRoundTripBig() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(1); int size = (int) Math.min(1 << 21, RawtypeModConstants.MAX_TRANSFORM_LENGTH & -RawtypeModConstants.MAX_TRANSFORM_LENGTH); runRoundTrip(size); } public static void testRoundTripMultithread() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(3); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); runRoundTrip(1024); } public static void testRoundTripMultithreadBig() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setNumberOfProcessors(3); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); int size = (int) Math.min(1 << 21, RawtypeModConstants.MAX_TRANSFORM_LENGTH & -RawtypeModConstants.MAX_TRANSFORM_LENGTH); runRoundTrip(size); } private static void runRoundTrip(int size) { runRoundTrip(new SixStepFNTStrategy(), size); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeTableFNTStrategyTest.java000066400000000000000000000123171461767713300325070ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Arrays; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.0 * @author Mikko Tommila */ public class RawtypeTableFNTStrategyTest extends RawtypeNTTStrategyTestCase { public RawtypeTableFNTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeTableFNTStrategyTest("testForward")); suite.addTest(new RawtypeTableFNTStrategyTest("testInverse")); suite.addTest(new RawtypeTableFNTStrategyTest("testRoundTrip")); return suite; } public static void testForward() { for (int modulus = 0; modulus < 3; modulus++) { int size = 8192; // Good for memory threshold of 64kB DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); rawtype[] data = getPlainArray(dataStorage), expectedTransform = ntt(data, modulus); RawtypeScramble.scramble(expectedTransform, 0, Scramble.createScrambleTable(size)); //Arrays.sort(expectedTransform); NTTStrategy nttStrategy = new RawtypeTableFNTStrategy(); nttStrategy.transform(dataStorage, modulus); rawtype[] actualTransform = getPlainArray(dataStorage); //Arrays.sort(actualTransform); assertEquals("expected length", size, expectedTransform.length); assertEquals("actual length", size, actualTransform.length); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], [" + i + "]", (long) expectedTransform[i], (long) actualTransform[i]); } } } public static void testInverse() { for (int modulus = 0; modulus < 3; modulus++) { int size = 8192; // Good for memory threshold of 64kB DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); rawtype[] data = getPlainArray(dataStorage); RawtypeScramble.scramble(data, 0, Scramble.createScrambleTable(size)); rawtype[] expectedTransform = inverseNtt(data, modulus); Arrays.sort(expectedTransform); NTTStrategy nttStrategy = new RawtypeTableFNTStrategy(); nttStrategy.inverseTransform(dataStorage, modulus, size); rawtype[] actualTransform = getPlainArray(dataStorage); Arrays.sort(actualTransform); assertEquals("expected length", size, expectedTransform.length); assertEquals("actual length", size, actualTransform.length); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], [" + i + "]", (long) expectedTransform[i], (long) actualTransform[i]); } } } public static void testRoundTrip() { int size = 8192; // Good for memory threshold of 64kB DataStorage dataStorage = createDataStorage(size + 5).subsequence(5, size); for (int modulus = 0; modulus < 3; modulus++) { NTTStrategy nttStrategy = new RawtypeTableFNTStrategy(); nttStrategy.transform(dataStorage, modulus); DataStorage.Iterator iterator = dataStorage.iterator(DataStorage.READ, 0, 1); assertTrue("transformed [0]", 6 != (long) iterator.getRawtype()); iterator.close(); nttStrategy.inverseTransform(dataStorage, modulus, size); iterator = dataStorage.iterator(DataStorage.READ, 0, size); for (int i = 0; i < size; i++) { assertEquals("MODULUS[" + modulus + "], round-tripped [" + i + "]", i + 6, (long) iterator.getRawtype()); iterator.next(); } } } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeTestCase.java000066400000000000000000000034411461767713300302360ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import java.util.Properties; import org.apfloat.*; import junit.framework.TestCase; /** * @version 1.0 * @author Mikko Tommila */ public class RawtypeTestCase extends TestCase { public RawtypeTestCase() { } public RawtypeTestCase(String methodName) { super(methodName); } @Override protected void setUp() { Properties properties = new Properties(); properties.setProperty(ApfloatContext.BUILDER_FACTORY, "org.apfloat.internal.RawtypeBuilderFactory"); ApfloatContext.getContext().setProperties(properties); } } RawtypeThreeNTTConvolutionStrategyTest.java000066400000000000000000000254631461767713300347340ustar00rootroot00000000000000apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeThreeNTTConvolutionStrategyTest extends RawtypeConvolutionStrategyTestCase implements RawtypeRadixConstants { public RawtypeThreeNTTConvolutionStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testFull")); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testTruncated")); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testAuto")); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testFullBig")); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testFullBigParallel")); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testFullHugeParallel")); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testTruncatedBig")); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testAutoBig")); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testAutoBigParallel")); suite.addTest(new RawtypeThreeNTTConvolutionStrategyTest("testAutoHugeParallel")); return suite; } public void testFull() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4 }), src2 = createDataStorage(new rawtype[] { (rawtype) 5, (rawtype) 6 }), src9 = createDataStorage(new rawtype[] { b1, b1, b1 }), src99 = createDataStorage(new rawtype[] { b1, b1, b1, b1, b1, b1 }); ConvolutionStrategy convolutionStrategy = createConvolutionStrategy(radix, new RawtypeTableFNTStrategy()); DataStorage result = convolutionStrategy.convolute(src1, src2, 6); check("normal", radix, new rawtype[] { 0, (rawtype) 5, (rawtype) 16, (rawtype) 27, (rawtype) 38, (rawtype) 24 }, result); result = convolutionStrategy.convolute(src9, src99, 9); check("max", radix, new rawtype[] { b1, b1, b1 - (rawtype) 1, b1, b1, b1, 0, 0, (rawtype) 1 }, result); } } public void testTruncated() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src1 = createDataStorage(new rawtype[] { (rawtype) 1, (rawtype) 2, (rawtype) 3, (rawtype) 4 }), src2 = createDataStorage(new rawtype[] { (rawtype) 5, (rawtype) 6 }), src9 = createDataStorage(new rawtype[] { b1, b1, b1 }), src99 = createDataStorage(new rawtype[] { b1, b1, b1, b1, b1, b1 }); ConvolutionStrategy convolutionStrategy = createConvolutionStrategy(radix, new RawtypeTableFNTStrategy()); DataStorage result = convolutionStrategy.convolute(src1, src2, 3); check("normal", radix, new rawtype[] { 0, (rawtype) 5, (rawtype) 16 }, result); result = convolutionStrategy.convolute(src9, src99, 6); check("max", radix, new rawtype[] { b1, b1, b1 - (rawtype) 1, b1, b1, b1 }, result); } } public void testAuto() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; DataStorage src9 = createDataStorage(new rawtype[] { b1, b1, b1 }); ConvolutionStrategy convolutionStrategy = createConvolutionStrategy(radix, new RawtypeTableFNTStrategy()); DataStorage result = convolutionStrategy.convolute(src9, src9, 6); check("max", radix, new rawtype[] { b1, b1, b1 - (rawtype) 1, 0, 0, (rawtype) 1 }, result); } } public void testFullBig() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(1); runBig(); ctx.setNumberOfProcessors(numberOfProcessors); } public void testFullBigParallel() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(4); runBig(); ctx.setNumberOfProcessors(numberOfProcessors); } public void testFullHugeParallel() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); long maxMemoryBlockSize = ctx.getMaxMemoryBlockSize(); ctx.setNumberOfProcessors(4); ctx.setMaxMemoryBlockSize(65536); runBig(20000, 12000); ctx.setNumberOfProcessors(numberOfProcessors); ctx.setMaxMemoryBlockSize(maxMemoryBlockSize); } private void runBig() { runBig(500, 300); } private void runBig(int size1, int size2) { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; rawtype[] array1 = new rawtype[size1], array2 = new rawtype[size2], array3 = new rawtype[size1 + size2]; for (int i = 0; i < size1; i++) { array1[i] = b1; array3[i] = b1 - (rawtype) (i == size2 - 1 ? 1 : 0); } for (int i = 0; i < size2; i++) { array2[i] = b1; array3[i + size1] = (rawtype) (i == size2 - 1 ? 1 : 0); } DataStorage src9 = createDataStorage(array1), src99 = createDataStorage(array2); ConvolutionStrategy convolutionStrategy = createConvolutionStrategy(radix, new SixStepFNTStrategy()); DataStorage result = convolutionStrategy.convolute(src9, src99, size1 + size2); check("max", radix, array3, result); } } public void testTruncatedBig() { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; int size1 = 500, size2 = 300; rawtype[] array1 = new rawtype[size1], array2 = new rawtype[size2], array3 = new rawtype[size1]; for (int i = 0; i < size1; i++) { array1[i] = b1; array3[i] = b1 - (rawtype) (i == size1 - 1 || i == size2 - 1 ? 1 : 0); } for (int i = 0; i < size2; i++) { array2[i] = b1; } DataStorage src9 = createDataStorage(array1), src99 = createDataStorage(array2); ConvolutionStrategy convolutionStrategy = createConvolutionStrategy(radix, new RawtypeTableFNTStrategy()); DataStorage result = convolutionStrategy.convolute(src99, src9, size1); check("max", radix, array3, result); } } public void testAutoBig() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(1); runAutoBig(); ctx.setNumberOfProcessors(numberOfProcessors); } public void testAutoBigParallel() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); ctx.setNumberOfProcessors(4); runAutoBig(); ctx.setNumberOfProcessors(numberOfProcessors); } public void testAutoHugeParallel() { ApfloatContext ctx = ApfloatContext.getContext(); int numberOfProcessors = ctx.getNumberOfProcessors(); long maxMemoryBlockSize = ctx.getMaxMemoryBlockSize(); ctx.setNumberOfProcessors(4); ctx.setMaxMemoryBlockSize(65536); runAutoBig(20000); ctx.setNumberOfProcessors(numberOfProcessors); ctx.setMaxMemoryBlockSize(maxMemoryBlockSize); } private void runAutoBig() { runAutoBig(500); } private void runAutoBig(int size) { for (int radix = Character.MIN_RADIX; radix <= Character.MAX_RADIX; radix++) { rawtype b1 = BASE[radix] - (rawtype) 1; rawtype[] array1 = new rawtype[size], array2 = new rawtype[2 * size]; for (int i = 0; i < size; i++) { array1[i] = b1; array2[i] = b1 - (rawtype) (i == size - 1 ? 1 : 0); array2[i + size] = (rawtype) (i == size - 1 ? 1 : 0); } DataStorage src9 = createDataStorage(array1); ConvolutionStrategy convolutionStrategy = createConvolutionStrategy(radix, new RawtypeTableFNTStrategy()); DataStorage result = convolutionStrategy.convolute(src9, src9, 2 * size); check("max", radix, array2, result); } } protected ConvolutionStrategy createConvolutionStrategy(int radix, NTTStrategy transform) { return new ThreeNTTConvolutionStrategy(radix, transform); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeTwoPassFNTStrategyTest.java000066400000000000000000000072541461767713300330640ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import org.apfloat.*; import org.apfloat.spi.*; import junit.framework.TestSuite; /** * @version 1.8.0 * @author Mikko Tommila */ public class RawtypeTwoPassFNTStrategyTest extends RawtypeNTTStrategyTestCase { public RawtypeTwoPassFNTStrategyTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeTwoPassFNTStrategyTest("testRoundTrip")); suite.addTest(new RawtypeTwoPassFNTStrategyTest("testRoundTripBig")); suite.addTest(new RawtypeTwoPassFNTStrategyTest("testRoundTripMultithread")); suite.addTest(new RawtypeTwoPassFNTStrategyTest("testRoundTripMultithreadBig")); return suite; } public static void testRoundTrip() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMaxMemoryBlockSize(65536); ctx.setMemoryThreshold(1024); ctx.setBlockSize(256); ctx.setNumberOfProcessors(1); runRoundTrip(131072); } public static void testRoundTripBig() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMaxMemoryBlockSize(65536); ctx.setMemoryThreshold(1024); ctx.setBlockSize(256); ctx.setNumberOfProcessors(1); runRoundTrip((int) Math.min(1 << 21, Util.round2down(RawtypeModConstants.MAX_TRANSFORM_LENGTH))); } public static void testRoundTripMultithread() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMaxMemoryBlockSize(65536); ctx.setMemoryThreshold(1024); ctx.setBlockSize(256); ctx.setNumberOfProcessors(3); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); runRoundTrip(131072); } public static void testRoundTripMultithreadBig() { ApfloatContext ctx = ApfloatContext.getContext(); ctx.setMaxMemoryBlockSize(65536); ctx.setMemoryThreshold(1024); ctx.setBlockSize(256); ctx.setNumberOfProcessors(3); ctx.setExecutorService(ApfloatContext.getDefaultExecutorService()); runRoundTrip((int) Math.min(1 << 21, Util.round2down(RawtypeModConstants.MAX_TRANSFORM_LENGTH))); } private static void runRoundTrip(int size) { runRoundTrip(new TwoPassFNTStrategy(), size); } } apfloat-1.14.0/apfloat/src/test/template/org/apfloat/internal/RawtypeWTablesTest.java000066400000000000000000000055201461767713300307240ustar00rootroot00000000000000/* * MIT License * * Copyright (c) 2002-2023 Mikko Tommila * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package org.apfloat.internal; import junit.framework.TestSuite; /** * @since 1.7.0 * @version 1.7.0 * @author Mikko Tommila */ public class RawtypeWTablesTest extends RawtypeTestCase implements RawtypeModConstants { public RawtypeWTablesTest(String methodName) { super(methodName); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } public static TestSuite suite() { TestSuite suite = new TestSuite(); suite.addTest(new RawtypeWTablesTest("testGetWTable")); suite.addTest(new RawtypeWTablesTest("testGetInverseWTable")); return suite; } public static void testGetWTable() { rawtype[] wTable = RawtypeWTables.getWTable(0, 4); RawtypeModMath math = new RawtypeModMath(); math.setModulus(MODULUS[0]); assertEquals("[0]", 1, (long) wTable[0]); assertEquals("[1]", (long) MODULUS[0] - 1, (long) math.modPow(wTable[1], 2)); assertEquals("[2]", (long) MODULUS[0] - 1, (long) wTable[2]); assertEquals("[3]", (long) MODULUS[0] - 1, (long) math.modPow(wTable[3], 2)); } public static void testGetInverseWTable() { rawtype[] wTable = RawtypeWTables.getInverseWTable(0, 4); RawtypeModMath math = new RawtypeModMath(); math.setModulus(MODULUS[0]); assertEquals("[0]", 1, (long) wTable[0]); assertEquals("[1]", (long) MODULUS[0] - 1, (long) math.modPow(wTable[1], 2)); assertEquals("[2]", (long) MODULUS[0] - 1, (long) wTable[2]); assertEquals("[3]", (long) MODULUS[0] - 1, (long) math.modPow(wTable[3], 2)); } } apfloat-1.14.0/pom.xml000066400000000000000000000345011461767713300145620ustar00rootroot00000000000000 4.0.0 org.apfloat apfloat-parent 1.14.0 pom apfloat-parent Administrative parent pom for apfloat http://www.apfloat.org MIT License https://opensource.org/licenses/MIT repo scm:git:git://github.com/mtommila/apfloat.git scm:git:ssh://github.com:mtommila/apfloat.git https://github.com/mtommila/apfloat 1.14.0 mtommila Mikko Tommila mikko.tommila@apfloat.org UTF-8 UTF-8 true apfloat apfloat-samples apfloat-applet apfloat-calc apfloat-jscience apfloat-aparapi org.jscience jscience 4.3.1 com.aparapi aparapi 3.0.0 junit junit 4.13.2 test org.apfloat apfloat ${project.version} org.apfloat apfloat test-jar ${project.version} org.apfloat apfloat-samples ${project.version} org.apfloat apfloat-aparapi ${project.version} org.apfloat apfloat-calc ${project.version} org.apache.bcel bcel 6.8.1 org.scala-lang scala-library 2.13.12 org.codehaus.mojo build-helper-maven-plugin 3.2.0 org.codehaus.mojo javacc-maven-plugin 3.0.1 org.apache.maven.plugins maven-antrun-plugin 3.1.0 ant-contrib ant-contrib 1.0b3 ant ant org.apache.maven.plugins maven-compiler-plugin 3.11.0 8 ${project.build.sourceEncoding} org.apache.maven.plugins maven-surefire-plugin 2.22.2 false -Djava.locale.providers=COMPAT,SPI -Dcom.aparapi.executionMode=JTP   **/*Test.java org.apache.maven.plugins maven-javadoc-plugin 3.5.0 false ${project.build.sourceEncoding} all,-html Apfloat v. ${project.version} Specification Apfloat Documentation https://docs.oracle.com/en/java/javase/11/docs/api/ https://javadoc.io/doc/org.jscience/jscience/4.3.1/ https://javadoc.io/doc/org.javolution/javolution-core-java/6.0.0/ apfloat.java 1.8 implNote a Implementation notes: org.apache.maven.plugins maven-source-plugin 3.2.1 org.apache.maven.plugins maven-resources-plugin 3.3.0 biz.aQute.bnd bnd-maven-plugin 7.0.0 generate-osgi-manifest bnd-process org.apache.maven.plugins maven-jar-plugin 3.3.0 true true org.apache.maven.plugins maven-jarsigner-plugin 3.0.0 org.apache.maven.plugins maven-shade-plugin 3.4.1 false org.apache.maven.plugins maven-gpg-plugin 3.0.1 sign-artifacts verify sign org.apache.maven.plugins maven-scm-plugin 1.13.0 org.apache.maven.plugins maven-release-plugin 2.5.3 true true false org.apache.maven.plugins maven-gpg-plugin sign-artifacts verify sign org.apache.maven.plugins maven-antrun-plugin release run sonatype-nexus-snapshots Sonatype Nexus Snapshots https://oss.sonatype.org/content/repositories/snapshots/ sonatype-nexus-staging Nexus Release Repository https://oss.sonatype.org/service/local/staging/deploy/maven2/ apfloat-1.14.0/readme.html000066400000000000000000000011441461767713300153650ustar00rootroot00000000000000 Apfloat Readme

Apfloat

Copyright © 2024 Mikko Tommila

This work is licensed under the terms of the MIT license. See the MIT License for more details.

If you have any questions or need a different type of license, please contact the author.

apfloat-1.14.0/src/000077500000000000000000000000001461767713300140315ustar00rootroot00000000000000apfloat-1.14.0/src/main/000077500000000000000000000000001461767713300147555ustar00rootroot00000000000000apfloat-1.14.0/src/main/javadoc/000077500000000000000000000000001461767713300163645ustar00rootroot00000000000000apfloat-1.14.0/src/main/javadoc/overview.html000066400000000000000000000017041461767713300211220ustar00rootroot00000000000000 Apfloat is an arbitrary precision arithmetic library. Most operations e.g. multiplication can be done with O(n log n) complexity. That is, when the number of digits doubles, the execution time only slightly more than doubles.

Apfloat requires Java 8 or later.

The apfloat library has been designed for high performance, but as it is 100% Java, the achievement is somewhat limited compared to various other existing libraries written in C and assembler. For best performance it's recommended to use the fastest Java Virtual Machine available, for example Oracle's or OpenJDK's server VM.

Apfloat is distributed under the terms of the MIT License and comes with NO WARRANTIES.

To report bugs and submit questions or comments, please contact the author Mikko Tommila.

apfloat-1.14.0/src/site/000077500000000000000000000000001461767713300147755ustar00rootroot00000000000000apfloat-1.14.0/src/site/resources/000077500000000000000000000000001461767713300170075ustar00rootroot00000000000000apfloat-1.14.0/src/site/resources/applet.html000066400000000000000000000013431461767713300211630ustar00rootroot00000000000000 Sample Apfloat Applets

Sample Apfloat Applets

Arbitrary precision calculator applet
Unsigned Signed

Pi calculation applet
Single-thread Unsigned Signed
Multi-thread Unsigned Signed

apfloat-1.14.0/src/site/resources/applet/000077500000000000000000000000001461767713300202745ustar00rootroot00000000000000apfloat-1.14.0/src/site/resources/applet/calculator-help.html000066400000000000000000000644121461767713300242500ustar00rootroot00000000000000 Calculator help

Calculator help

Basic usage

Input commands to the input field at the bottom. Execute the command by pressing Enter or by clicking the Calculate button. The large text area shows the history of input and output text.

While in the input field, you can scroll the command history back and forth with the up and down arrow keys.

You can clear the output window and command history by clicking the Clear button.

Operators

The calculator understands basic operations, which are:

+addition
-subtraction
*multiplication
/division
%modulus
^power
!factorial
!!double factorial

For example:

1 + 2 * 3 ^ 4

calculates 1 + 2 * 34, which is 163.

Variables

You can assign values to variables and use variables in expressions, for example:

x = 5
x + 6

Assignment operations can be also combined with the basic operations:

x += 5
x -= 6
x *= 7
x /= 8
x %= 3
x ^= 2

Output format

You can change the output format of floating-point values with the "Floating" and "Fixed" radio buttons. These are for example:

Floating:1.2345e3
Fixed:1234.5

Note that the calculator supports extremely large exponents for floating-point values. Displaying such numbers in the fixed-point format may be impractical.

Functions

The calculator supports many functions.

Basic:

abs(x)Absolute value of x.
cbrt(x)Cube root of x.
ceil(x)Ceiling function (round towards positive infinity) of x. Parameter x must be real.
copySign(x, y)Copies sign of y to the value of x. Both x and y must be real.
doubleFactorial(x)Double factorial of x, that is x!!. Parameter x must be an integer.
factorial(x)Factorial of x, that is x!. Parameter x must be an integer.
floor(x)Floor function (round towards negative infinity) of x. Parameter x must be real.
frac(x)Fractional part of x. Parameter x must be real.
fmod(x, y)Modulus, equivalent to x % y. Both x and y must be real.
hypot(x, y)Equivalent to sqrt(x2 + y2). Both x and y must be real.
inverseRoot(x, y)Equivalent to x-1/y. Parameter y must be an integer.
inverseRoot(x, y, z)Inverse y:th root of x, z:th branch. Parameters y and z must be integers.
max(x, y)Maximum of x and y. Both x and y must be real.
min(x, y)Minimum of x and y. Both x and y must be real.
n(x, y)The value of x to the precision of y digits. Parameter y must be an integer.
nextAfter(x, y)The number adjacent to x in the direction of y. Both x and y must be real.
nextDown(x)The adjacent value closer to negative infinity. Parameter x must be real.
nextUp(x)The adjacent value closer to positive infinity. Parameter x must be real.
random(x)Pseudorandom number with x digits and a uniform distribution from the range [0, 1). Parameter x must be an integer.
randomGaussian(x)Pseudorandom number with x digits and a normal distribution with mean 0 and standard deviation 1. Parameter x must be an integer.
root(x, y)Equivalent to x1/y. Parameter y must be an integer.
root(x, y, z)y:th root of x, z:th branch. Parameters y and z must be integers.
roundToPrecision(x, y)Round x to y digits of precision. Parameter x must be real and y must be an integer. Any exactly half-way values are rounded up.
roundToInteger(x)Round x to nearest integer. Parameter x must be real. Any exactly half-way values are rounded up.
roundToPlaces(x, y)Round x to y decimal places. Parameter x must be real and y must be an integer. Any exactly half-way values are rounded up.
roundToMultiple(x, y)Round x to the nearest integer multiple of y. Parameters x and y must be real. Any exactly half-way values are rounded up.
scale(x, y)Equivalent to x * 10y. Parameter y must be an integer.
sqrt(x)Square root of x.
truncate(x)Nearest integer rounded towards zero of x. Parameter x must be real.
toDegrees(x)Convert radians to degrees. Parameter x must be real.
toRadians(x)Convert degrees to radians. Parameter x must be real.
ulp(x)Unit in the last place.

Trigonometric:

acos(x)Arc cosine of x.
acosh(x)Hyperbolic arc cosine of x.
asin(x)Arc sine of x.
asinh(x)Hyperbolic arc sine of x.
atan(x)Arc tangent of x.
atan2(x, y)Angle of the point (y, x). Both x and y must be real.
atanh(x)Hyperbolic arc tangent of x.
cos(x)Cosine of x.
cosh(x)Hyperbolic cosine of x.
exp(x)Exponent function of x, that is ex.
log(x)Natural logarithm of x.
log(x, y)Base-y logarithm of x.
sin(x)Sine of x.
sinh(x)Hyperbolic sine of x.
tan(x)Tangent of x.
tanh(x)Hyperbolic tangent of x.

Complex manipulation:

arg(x)Angle on the complex plane of x.
conj(x)Complex conjugate of x.
imag(x)Imaginary part of x.
real(x)Real part of x.

Advanced:

agm(x, y)Arithmetic-geometric mean of x and y.
airyAi(x)Airy function Ai(x). Note that the implementation is slow.
airyAiPrime(x)Derivative of the Airy function Ai, i.e. Ai′(x). Note that the implementation is slow.
airyBi(x)Airy function Bi(x). Note that the implementation is slow.
airyBiPrime(x)Derivative of the Airy function Bi, i.e. Bi′(x). Note that the implementation is slow.
bernoulli(x)Bernoulli number Bx.
bernoulliB(n, x)Bernoulli polynomial Bn(x). Parameter n must be a nonnegative integer. Note that the implementation is slow.
besselI(ν, x)Bessel function Iν(x). Note that the implementation is slow.
besselJ(ν, x)Bessel function Jν(x). Note that the implementation is slow.
besselK(ν, x)Bessel function Kν(x). Note that the implementation is slow.
besselY(ν, x)Bessel function Yν(x). Note that the implementation is slow.
beta(a, b)Beta function. Note that the implementation is slow.
beta(x, a, b)Incomplete beta function Bx(a, b). Note that the implementation is slow.
beta(x1, x2, a, b)Generalized incomplete beta function B(x1, x2)(a, b). Note that the implementation is slow.
binomial(x, y)Binomial coefficient, i.e. (xy).
catalan(x)Catalan's constant G calculated to x digits of precision. Parameter x must be an integer.
chebyshevT(ν, x)Chebyshev polynomial of the first kind Tν(x). Note that the implementation is slow.
chebyshevU(ν, x)Chebyshev polynomial of the second kind Uν(x). Note that the implementation is slow.
cosIntegral(x)Cosine integral i.e. Ci(x). Note that the implementation is slow.
coshIntegral(x)Hyperbolic cosine integral i.e. Chi(x). Note that the implementation is slow.
digamma(x)Digamma function, i.e. ψ(x). Note that the implementation is slow.
e(x)e calculated to x digits of precision. Parameter x must be an integer.
ellipticE(x)Elliptic integral E(x). Note that the implementation is slow.
ellipticK(x)Elliptic integral K(x).
erf(x)Error function. Note that the implementation is slow.
erfc(x)Complementary error function. Note that the implementation is slow.
erfi(x)Imaginary error function. Note that the implementation is slow.
euler(x)γ calculated to x digits of precision. Parameter x must be an integer.
eulerE(n, x)Euler polynomial En(x). Parameter n must be a nonnegative integer. Note that the implementation is slow.
expIntegralE(ν, x)Exponential integral Eν(x). Note that the implementation is slow.
expIntegralEi(x)Exponential integral Ei(x). Note that the implementation is slow.
fibonacci(ν, x)Fibonacci polynomial Fν(x). Note that the implementation is slow.
fresnelC(x)Fresnel integral C, i.e. C(x). Note that the implementation is slow.
fresnelS(x)Fresnel integral S, i.e. S(x). Note that the implementation is slow.
gamma(x)Gamma function, i.e. Γ(x). Note that the implementation is slow.
gamma(a, x)Incomplete gamma function, i.e. Γ(a, x). Note that the implementation is slow.
gamma(a, x1, x2)Generalized incomplete gamma function, i.e. Γ(a, x1, x2). Note that the implementation is slow.
gcd(x, y)Greatest common divisor of x and y. Both x and y must be integers.
gegenbauerC(ν, x)Renormalized Gegenbauer function Cν(0)(x). Note that the implementation is slow.
gegenbauerC(ν, λ, x)Gegenbauer polynomial Cνλ(x). Note that the implementation is slow.
glaisher(x)The Glaisher-Kinkelin constant A calculated to x digits of precision. Parameter x must be an integer.
jacobiP(ν, a, b, x)Jacobi polynomial Pν(a,b)(x). Note that the implementation is slow.
harmonicNumber(x)Harmonic number Hx. Note that the implementation is slow.
harmonicNumber(x, r)Generalized harmonic number Hx(r). Note that the implementation is slow.
hermiteH(ν, x)Hermite polynomial Hν(x). Note that the implementation is slow.
hypergeometric0F1(a, x)Hypergeometric function 0F1(;a; x). Note that the implementation is slow.
hypergeometric0F1Regularized(a, x)Regularized hypergeometric function 01. Note that the implementation is slow.
hypergeometric1F1(a, b, x)Hypergeometric function 1F1(a; b; x). Note that the implementation is slow.
hypergeometric1F1Regularized(a, b, x)Regularized hypergeometric function 11. Note that the implementation is slow.
hypergeometric2F1(a, b, c, x)Hypergeometric function 2F1(a, b; c; x). Note that the implementation is slow.
hypergeometric2F1Regularized(a, b, c, x)Regularized hypergeometric function 21. Note that the implementation is slow.
hypergeometricU(a, b, x)Hypergeometric function U. Note that the implementation is slow.
inverseErf(x)Inverse error function i.e. erf−1(x). Parameter x must be between (-1, 1). Note that the implementation is slow.
inverseErfc(x)Inverse complementary error function i.e. erfc−1(x). Parameter x must be between (0, 2). Note that the implementation is slow.
khinchin(x)Khinchin's constant K calculated to x digits of precision. Parameter x must be an integer.
laguerreL(ν, x)Laguerre polynomial Lν(x). Note that the implementation is slow.
laguerreL(ν, λ, x)Generalized Laguerre polynomial Lνλ(x). Note that the implementation is slow.
legendreP(ν, x)Legendre polynomial Pν(x). Note that the implementation is slow.
legendreP(ν, μ, x)Associated Legendre function of the first kind Pνμ(x). Note that the implementation is slow.
legendreQ(ν, x)Legendre function of the second kind Qν(x). Note that the implementation is slow.
legendreQ(ν, μ, x)Associated Legendre function of the second kind Qνμ(x). Note that the implementation is slow.
lcm(x, y)Least common multiple of x and y. Both x and y must be integers.
logGamma(x)Logarithm of the gamma function, logΓ(x). Note that the implementation is slow.
logIntegral(x)Logarithmic integral i.e. li(x). Note that the implementation is slow.
logisticSigmoid(x)Logistic sigmoid function.
pi(x)π calculated to x digits of precision. Parameter x must be an integer.
pochhammer(x, n)Pochhammer symbol i.e. (x)n. Note that the implementation is slow.
polygamma(n, x)Polygamma function i.e. ψ(n)(x). Parameter n must be a nonnegative integer. Note that the implementation is slow.
polylog(ν, x)Polylogarithm Liν(x). Note that the implementation is slow.
sinc(x)Sinc function.
sinIntegral(x)Sine integral i.e. Si(x). Note that the implementation is slow.
sinhIntegral(x)Hyperbolic sine integral i.e. Shi(x). Note that the implementation is slow.
sphericalHarmonicY(ν, μ, ϑ, ϕ)Spherical harmonic function Yλμ(ϑ, ϕ). Note that the implementation is slow.
w(x)Lambert W function, i.e. solution to the equation W eW = x.
w(x, k)Lambert W function, branch k. Parameter k must be an integer.
zeta(x)Riemann zeta function, i.e. ζ(x). Note that the implementation is slow.
zeta(x, y)Hurwitz zeta function, i.e. ζ(x, y). Note that the implementation is slow.

Functional equivalents to the basic operators:

add(x, y)Equivalent to x + y.
subtract(x, y)Equivalent to x - y.
multiply(x, y)Equivalent to x * y.
divide(x, y)Equivalent to x / y.
negate(x)Equivalent to -x.
mod(x, y)Equivalent to x % y.
pow(x, y)Equivalent to x ^ y.

For example:

digits=40
exp(sqrt(n(163, digits)) * pi(digits))

Number types

The calculator supports complex and rational numbers in addition to integers and floating-point values. For example, sqrt(-1.0) returns i. Here i is the imaginary unit and it can be used in input expressions as well. If you don't specify an exponent or a decimal point for a number, it will be treated as an integer. Integers have infinite precision (see below). For example, inputting

2/3

will get you just

2/3,

the rational number. If you want a floating-point calculation instead, use e.g.

2.00 / 3.00

Precision

The calculator can perform calculations to arbitrary precision (actually the precision is currently limited to about 3.5×1015 digits).

Arbitrary input precision

By default, the precision of a floating-point number is the number of significant digits that you specify for it. For example:

2. has a precision of 1 digit,
2.0 has a precision of 2 digits,
2.00000 has a precision of 6 digits

The result of the calculation is only performed to the precision allowed by the precision of the input operands, so for example

sqrt(2.00)

calculates the square root of two to three digits of precision.

Integers have infinite precision. This limits their use in certain operations. For example

sqrt(2)

will give an error that an inexact square root can't be calculated to infinite precision. However, sqrt(4) would work.

If you want to use extreme precision (which this calculator is certainly designed for), you can use the function n(x, y) to specify the precision of a number. For example,

sqrt(n(2, 1000))

would calculate the square root of two with a precision of 1000 digits.

If you set the precision very high, the calculation may take a very long time. During the calculation the calculator may appear unresponsive. For example, calculating

exp(n(1, 1000000))

might take an hour or so, depending on your computer's performance.

Fixed input precision

You can change the input precision of numbers from the above default logic to a fixed number of digits by selecting the "Fixed" radio button in the "Input precision" radio button group and setting the desired number of digits in the input field.

This way, if you e.g. set the input precision to 100 digits, even if you input a number like 0.5 it won't have only one digit of precision but always the fixed precision (e.g. 100 digits).

Note that the fixed precision is set only for the numbers that are input, not for the numbers that are output. In practice, often the two precisions are the same, but not always. For example, if you set a fixed input precision of 20 digits and calculate log(1.00001), the result won't have 20 digits of precision but only 15 digits of precision. This happens because of how the log() function behaves around 1.

If fixed input precision is set, you can omit the argument to the functions that return a constant. For example then pi() would just return π to the specified input precision.

apfloat-1.14.0/src/site/resources/applet/calculator.html000066400000000000000000000017051461767713300233160ustar00rootroot00000000000000 Calculator Applet

Calculator Applet

This is an arbitrary precision calculator applet. It works like any normal calculator, and allows calculating results to millions of digits of precision. In addition, it supports various special mathematical functions.

Calculator help


Your browser is completely ignoring the <applet> tag.
Back to sample apfloat applets.

apfloat-1.14.0/src/site/resources/applet/pi.html000066400000000000000000000014661461767713300216010ustar00rootroot00000000000000 Pi Calculator Applet

Pi Calculator Applet

You can calculate pi to millions of digits of precision with this applet. It supports four algorithms for calculating pi, and any radix between 2 and 36.
Your browser is completely ignoring the <applet> tag.
Back to sample apfloat applets.

apfloat-1.14.0/src/site/resources/applet/piparallel.html000066400000000000000000000013521461767713300233100ustar00rootroot00000000000000 Parallel Pi Calculator Applet

Parallel Pi Calculator Applet

You can calculate pi to millions of digits of precision with this applet. It can use multiple CPUs to perform calculations in parallel.
Your browser is completely ignoring the <applet> tag.
Back to sample apfloat applets.

apfloat-1.14.0/src/site/resources/applet/signedcalculator.html000066400000000000000000000017121461767713300245060ustar00rootroot00000000000000 Signed Calculator Applet

Signed Calculator Applet

This is an arbitrary precision calculator applet. It works like any normal calculator, and allows calculating results to millions of digits of precision. In addition, it supports various special mathematical functions.

Calculator help


Your browser is completely ignoring the <applet> tag.
Back to sample apfloat applets.

apfloat-1.14.0/src/site/resources/applet/signedpi.html000066400000000000000000000014701461767713300227660ustar00rootroot00000000000000 Signed Pi Calculator Applet

Signed Pi Calculator Applet

You can calculate pi to millions of digits of precision with this applet. It supports four algorithms for calculating pi, and any radix between 2 and 36.
Your browser is completely ignoring the <applet> tag.
Back to sample apfloat applets.

apfloat-1.14.0/src/site/resources/applet/signedpiparallel.html000066400000000000000000000013461461767713300245050ustar00rootroot00000000000000 Signed Parallel Pi Calculator Applet

Signed Parallel Pi Calculator Applet

You can calculate pi to millions of digits of precision with this applet. It can use multiple CPUs to perform calculations in parallel.
Your browser is completely ignoring the <applet> tag.
Back to sample apfloat applets.