/* * Copyright (c) 2009-2015 * IT-Consulting Stephan Schloepke (http://www.schloepke.de/) * klemm software consulting Mirko Klemm (http://www.klemm-scs.com/) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package org.jbasics.math.arbitrary; import org.jbasics.testing.Java14LoggingTestCase; import org.junit.Assert; import org.junit.Test; import java.math.BigInteger; import java.util.Random; public class ArbitraryIntegerTest extends Java14LoggingTestCase { private final Random randomizer = new Random(); private final int iterations = 10000; @Test public void testValueOfInt() { Assert.assertTrue(ArbitraryInteger.MINUS_ONE == ArbitraryInteger.valueOf(-1)); Assert.assertTrue(ArbitraryInteger.ZERO == ArbitraryInteger.valueOf(0)); Assert.assertTrue(ArbitraryInteger.ONE == ArbitraryInteger.valueOf(1)); Assert.assertTrue(ArbitraryInteger.TWO == ArbitraryInteger.valueOf(2)); Assert.assertEquals(BigInteger.valueOf(-2), ArbitraryInteger.valueOf(-2).toNumber()); Assert.assertEquals(BigInteger.valueOf(3), ArbitraryInteger.valueOf(3).toNumber()); } @Test public void testValueOfBytes() { Assert.assertTrue(ArbitraryInteger.ZERO == ArbitraryInteger.valueOf(null)); Assert.assertTrue(ArbitraryInteger.MINUS_ONE == ArbitraryInteger.valueOf(BigInteger.valueOf(-1).toByteArray())); Assert.assertTrue(ArbitraryInteger.ZERO == ArbitraryInteger.valueOf(BigInteger.valueOf(0).toByteArray())); Assert.assertTrue(ArbitraryInteger.ONE == ArbitraryInteger.valueOf(BigInteger.valueOf(1).toByteArray())); Assert.assertTrue(ArbitraryInteger.TWO == ArbitraryInteger.valueOf(BigInteger.valueOf(2).toByteArray())); Assert.assertEquals(BigInteger.valueOf(-2), ArbitraryInteger.valueOf(BigInteger.valueOf(-2).toByteArray()).toNumber()); Assert.assertEquals(BigInteger.valueOf(3), ArbitraryInteger.valueOf(BigInteger.valueOf(3).toByteArray()).toNumber()); for (int i = 0; i < this.iterations; i++) { final BigInteger reference = BigInteger.valueOf(this.randomizer.nextLong()).pow(this.randomizer.nextInt(20) + 10); final ArbitraryInteger proband = ArbitraryInteger.valueOf(reference.toByteArray()); Assert.assertEquals(reference, proband.toNumber()); } } @Test public void testCheckFunctions() { Assert.assertFalse(ArbitraryInteger.ZERO.isNegativ()); Assert.assertTrue(ArbitraryInteger.ZERO.isZero()); Assert.assertFalse(ArbitraryInteger.ZERO.isPositiv()); Assert.assertEquals(0, ArbitraryInteger.ZERO.signum()); Assert.assertFalse(ArbitraryInteger.ONE.isNegativ()); Assert.assertFalse(ArbitraryInteger.ONE.isZero()); Assert.assertTrue(ArbitraryInteger.ONE.isPositiv()); Assert.assertEquals(1, ArbitraryInteger.ONE.signum()); Assert.assertTrue(ArbitraryInteger.MINUS_ONE.isNegativ()); Assert.assertFalse(ArbitraryInteger.MINUS_ONE.isZero()); Assert.assertFalse(ArbitraryInteger.MINUS_ONE.isPositiv()); Assert.assertEquals(-1, ArbitraryInteger.MINUS_ONE.signum()); for (int i = 0; i < this.iterations; i++) { final BigInteger reference = BigInteger.valueOf(this.randomizer.nextLong() - Long.MAX_VALUE).pow(this.randomizer.nextInt(20) + 10); final ArbitraryInteger proband = ArbitraryInteger.valueOf(reference.toByteArray()); Assert.assertEquals(reference.signum(), proband.signum()); Assert.assertTrue(reference.signum() < 0 && proband.isNegativ() || reference.signum() > 0 && !proband.isNegativ()); Assert.assertTrue(reference.signum() > 0 && proband.isPositiv() || reference.signum() < 0 && !proband.isPositiv()); Assert.assertTrue(reference.bitLength() == proband.bitLength()); } } @Test public void testUnaryFunctions() { for (int i = 0; i < this.iterations; i++) { final ArbitraryInteger proband = ArbitraryInteger.valueOf(this.randomizer.nextInt()); Assert.assertTrue(proband.signum() * -1 == proband.negate().signum()); final BigInteger t = proband.toNumber(); Assert.assertEquals(t.pow(2), proband.square().toNumber()); Assert.assertTrue(proband.isNegativ() && proband.abs().isPositiv() || proband.isPositiv() && proband.abs().isPositiv()); if (!proband.isZero()) { final ArbitraryRational ratProband = proband.reciprocal(); if (proband.isPositiv()) { Assert.assertTrue(ArbitraryInteger.ONE == ratProband.numerator()); Assert.assertTrue(proband == ratProband.denominator()); } else { Assert.assertTrue(ArbitraryInteger.MINUS_ONE == ratProband.numerator()); Assert.assertEquals(proband.negate().toNumber(), ratProband.denominator().toNumber()); } } Assert.assertEquals(proband.toNumber().add(BigInteger.ONE), proband.increment().toNumber()); Assert.assertEquals(proband.toNumber().subtract(BigInteger.ONE), proband.decrement().toNumber()); } try { final ArbitraryRational ratProband = ArbitraryInteger.ZERO.reciprocal(); Assert.fail("Reciprocal of zero should yield an ArithmeticException"); } catch (final ArithmeticException e) { // thats good } Assert.assertTrue(ArbitraryInteger.ONE == ArbitraryInteger.ZERO.increment()); Assert.assertTrue(ArbitraryInteger.TWO == ArbitraryInteger.ONE.increment()); Assert.assertTrue(ArbitraryInteger.MINUS_ONE == ArbitraryInteger.ZERO.decrement()); Assert.assertTrue(ArbitraryInteger.ONE == ArbitraryInteger.TWO.decrement()); } @Test public void testAddAndSubtract() { for (int i = 0; i < this.iterations; i++) { final BigInteger referenceBase = BigInteger.valueOf(this.randomizer.nextLong()).pow(this.randomizer.nextInt(20) + 10); final BigInteger referenceSummand = BigInteger.valueOf(this.randomizer.nextLong()).pow(this.randomizer.nextInt(20) + 15); final BigInteger referenceSubtrahend = BigInteger.valueOf(this.randomizer.nextLong()).pow(this.randomizer.nextInt(20) + 15); final BigInteger referenceAdd = referenceBase.add(referenceSummand); final BigInteger referenceSubtract = referenceBase.subtract(referenceSubtrahend); try { final ArbitraryInteger base = ArbitraryInteger.valueOf(referenceBase.toByteArray()); final ArbitraryInteger summand = ArbitraryInteger.valueOf(referenceSummand.toByteArray()); final ArbitraryInteger subtrahend = ArbitraryInteger.valueOf(referenceSubtrahend.toByteArray()); final ArbitraryInteger add = base.add(summand); final ArbitraryInteger subtract = base.subtract(subtrahend); // this.logger.log(Level.FINE, "---- Add/Subtract Test Result ----"); // this.logger.log(Level.FINE, "R.Base: {0}", referenceBase.toString()); // this.logger.log(Level.FINE, "Base: {0}", base.toNumber().toString()); // this.logger.log(Level.FINE, "-"); // this.logger.log(Level.FINE, "R.Summand: {0}", referenceSummand.toString()); // this.logger.log(Level.FINE, "Summand: {0}", summand.toNumber().toString()); // this.logger.log(Level.FINE, "R.Add: {0}", referenceAdd.toString()); // this.logger.log(Level.FINE, "Add: {0}", add.toNumber().toString()); // this.logger.log(Level.FINE, "-"); // this.logger.log(Level.FINE, "R.Subtrahend: {0}", referenceSubtrahend.toString()); // this.logger.log(Level.FINE, "Subtrahend: {0}", subtrahend.toNumber().toString()); // this.logger.log(Level.FINE, "R.Subtract: {0}", referenceSubtract.toString()); // this.logger.log(Level.FINE, "Subtract: {0}", subtract.toNumber().toString()); Assert.assertEquals(referenceAdd, add.toNumber()); Assert.assertEquals(referenceSubtract, subtract.toNumber()); } catch (final RuntimeException e) { System.out.println("DEBUG:\n result=" + referenceAdd + "\n base=" + referenceBase + "\n summand=" + referenceSummand); throw e; } } } @Test // @Ignore public void testError() { final BigInteger expected = new BigInteger( "-21879735541154229227791466086683579076280366900663919915753229387157638465447645473796772623668045395740955309606736155779128756008339957572547941535794434578480215038788509096467838347886473545594060505762132643352249899219355437010881930845931383892202505836028226277071210345446100300049491815172291901607412785191595203158765534011920622413229502503599901979001591778273253653797354435151875336398535748044703258181950911024961165427456263081841563451921906420195137198000588366609734090191658141766012035934674383050760060577"); final BigInteger base = new BigInteger( "-3228726627582846843290820710883679623592042640079220481770963323951837510830508501247332136871648166342996470281533856438991004882077331751097465364798487715149826580828393194189282216157367788009073684447495167230378224597373273512771994353269846226315145836570343421376491081492520530677846890344134032578169159149903380796871699729392389100446360276235368676263583346951551589759060277018476364782061697792018900780956155340644583423166768778760902979479131980271876060077060059959663807355136049008039964762632470972224239566848"); final BigInteger summand = new BigInteger( "3206846892041692614063029244796996044515762273178556561855210094564679872365060855773535364247980120947255514971927120283211876126068991793524917423262693280571346365789604685092814377809481314463479623941733034587025974698153918075761112422423914842422943330734315195099419871147074430377797398528961740676561746364711785593712934195380468478033130773731768774284581755173278336105262922583324489445663162043974197522774204429619622257739312515679061416027210073851680922879059471593054073264944390866273952726697796589173479506271"); final BigInteger calculated = ArbitraryInteger.valueOf(base.toByteArray()).add(ArbitraryInteger.valueOf(summand.toByteArray())).toNumber(); Assert.assertEquals(expected, calculated); } @Test public void testDivide() { final BigInteger dividend = BigInteger.valueOf(4566746).pow(4); final BigInteger divisor = dividend.shiftRight(7).subtract(BigInteger.valueOf(245)); System.out.println(dividend + " / " + divisor + " = " + dividend.divide(divisor) + " rem " + dividend.remainder(divisor)); System.out.println("N " + dividend.bitLength() + " - D " + divisor.bitLength() + " = " + (dividend.bitLength() - divisor.bitLength())); System.out.println("Q => " + dividend.divide(divisor).bitLength()); System.out.println("R => " + dividend.remainder(divisor).bitLength()); System.out.println("----"); final int diff = dividend.bitLength() - divisor.bitLength(); final BigInteger n = dividend.shiftRight(divisor.bitLength()); final BigInteger d = divisor.shiftRight(divisor.bitLength() - 1); System.out.println(n + " / " + d + " = " + n.divide(d)); } @Test public void testMulIdentity() { final int x = 4456; // 132982340; final int y = 300; // 198309094; final long z = x * y; final int x0 = x & 0x0000ffff; final int x1 = x >>> 16; final int y0 = y & 0x0000ffff; final int y1 = y >>> 16; final long x0y0 = x0 * y0; final long x1y1 = x1 * y1; final int xx = (x1 - x0) * (y1 - y0); final long p3a = (x1 - x0) * (y0 - y1) + x0y0 + x1y1; final long p3b = (x1 + x0) * (y1 + y0) - x0y0 - x1y1; final long za = (x1y1 << 32) + (p3a << 16) + x0y0; final long zb = (x1y1 << 32) + (p3b << 16) + x0y0; System.out.println("z = " + z); System.out.println("za = " + za); System.out.println("zb = " + zb); System.out.println("p3a = " + p3a); System.out.println("p3b = " + p3b); System.out.println("xx = " + xx); System.out.println("xx = " + (x1 - x0)); System.out.println("xx = " + (y1 - y0)); } }