/** * Extensions for math. * Copyright (C) 2005 Andy Turner, CCG, University of Leeds, UK. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ package uk.ac.leeds.ccg.andyt.ext.math; // java dependencies import java.math.BigDecimal; import java.math.BigInteger; /** * TODO: * 1. docs * 2. generic power function * 3. memory handling * 4. error and exception handling */ //public class BigDecimal0 extends BigDecimal { public class BigDecimal0 { ///** Creates a new instance of BigDecimal0 */ //public BigDecimal0( double d1 ) { // super( d1 ); //} /** Creates a new instance of BigDecimal0 */ public BigDecimal0() {} /** * @param args the command line arguments */ public static void main(String[] args) { // TODO: // code application logic here //BigDecimal bd0 = new BigDecimal( BigInteger.ONE, 0 ); //BigDecimal bd0 = new BigDecimal( BigInteger.ONE, 1 ); //BigDecimal bd0 = new BigDecimal( BigInteger.ONE, 2 ); //BigDecimal bd0 = new BigDecimal( BigInteger.ONE, 3 ); //BigDecimal bd0 = new BigDecimal( BigInteger.ONE, 4 ); //BigDecimal bd0 = new BigDecimal( BigInteger.ONE, 5 ); //System.out.println( "" + bd0 ); //BigDecimal bd1 = new BigDecimal( "128902" ).add( bd0 ); //BigDecimal bd1 = new BigDecimal( "2" ); //BigDecimal bd1 = new BigDecimal( "0.2" ); //BigDecimal bd1 = new BigDecimal( "0.0002" ); BigDecimal bd1 = new BigDecimal( "0.0000000000000000000000000000002" ); int decimalPlaces = 100; sqrt0( bd1, decimalPlaces ); //sqrt1( bd1, decimalPlaces ); } /** * Returns the square root of the input BigDecimal as a BigDecimal. There * are limits to the size of BigDecimals this can handle, but they can have * Integer.MAX_VALUE numbers of digits in their decimal expansion and so * can be enormous! An exception should be thrown and caught if this is the * case but this needs implementing. * @param input * @param decimalPlaces */ public static BigDecimal sqrt0( BigDecimal input, int decimalPlaces ) { // Deal with special cases BigDecimal zero = new BigDecimal( BigInteger.ZERO ); if ( input.compareTo( zero ) == -1 ) { return null; } if ( input.compareTo( BigDecimal.ONE ) == 0 ) { return BigDecimal.ONE; } // Deal with general case ( input > 1 or 0 > input < 1 ) // Calculate number of digits numberOfDigits in result BigInteger b0 = input.toBigInteger(); System.out.println( b0.toString() ); int numberOfDigits = b0.toString().length() / 2; BigInteger b1; if ( numberOfDigits == 0 ) { b1 = BigInteger.ONE; } else { b1 = new BigInteger( "10" ).pow( numberOfDigits - 1 ); } // Calculate value of first digit int i = 1; BigInteger b2 = b1; BigInteger b3 = b2.multiply( new BigInteger( Integer.toString( i ) ) ); BigInteger b4 = null; while ( b0.compareTo( b2 ) == 1 ) { b4 = b3; b3 = b1.multiply( new BigInteger( Integer.toString( i ) ) ); b2 = ( b3 ).pow( 2 ); i ++; } if ( b4 == null ) { b4 = BigInteger.ONE; } //System.out.println( "square root of " + input.toString() + " is between " + b4 + " and " + b3.toString() ); //System.out.println( b4 + " squared is " + b4.pow( 2 ) ); //System.out.println( b3 + " squared is " + b3.pow( 2 ) ); //System.out.println( "Done digit 0" ); // Calculate value of remaining digits that are greater than 1 for ( int ite = 1; ite < numberOfDigits; ite ++ ) { b1 = new BigInteger( "10" ).pow( numberOfDigits - 1 - ite ); i = 1; b2 = b4; b3 = b2.add( b2.multiply( b1 ) ); while ( b0.compareTo( b2 ) == 1 ) { b4 = b3; b3 = b1.multiply( new BigInteger( Integer.toString( i ) ) ); b2 = ( b3 ).pow( 2 ); i ++; } //System.out.println( "square root of " + input.toString() + " is between " + b4.toString() + " and " + b3.toString() ); //System.out.println( b4.toString() + " squared is " + b4.pow( 2 ) ); //System.out.println( b3.toString() + " squared is " + b3.pow( 2 ) ); //System.out.println( "Done digit " + ite ); } // Iteratively approximate fractions until required precision (decimal places) is reached int roundingMode = BigDecimal.ROUND_HALF_DOWN; BigDecimal half = new BigDecimal( 0.5d ); System.out.println("" + half.toString() ); BigDecimal x = new BigDecimal( b4 ); BigDecimal y; int iteScale = decimalPlaces + 1; int divideScale = decimalPlaces + 10; do {//for ( int ite = 0; ite < 10; ite ++ ) { //System.out.println("" + input.toString() + " divide " + x.toString() + " equals " + input.divide( x, scale, roundingMode ).toString() ); y = half.multiply( ( x.add( ( input.divide( x, divideScale, roundingMode ) ) ) ) ); x = y; // System.out.println( "square root of " + input.toString() + " is nearly " + x.toString() ); System.out.println( x.toString() + " squared is " + x.multiply( x ) ); // System.out.println( "" + ( x.multiply( x ) ).setScale( scale, roundingMode ) ); } while ( ( ( x.multiply( x ) ).setScale( decimalPlaces, roundingMode ) ).compareTo( input.setScale( decimalPlaces, roundingMode ) ) != 0 ); roundingMode = BigDecimal.ROUND_DOWN; y = x.setScale( decimalPlaces, roundingMode ); //System.out.println( y + " squared is " + y.multiply( y ) ); BigDecimal smallestDecimalFraction = new BigDecimal( BigInteger.ONE, decimalPlaces ); // Choose closest to return BigDecimal yplus = y.add( smallestDecimalFraction ); //System.out.println( yplus + " squared is " + yplus.multiply( yplus ) ); //BigDecimal yminus = y.subtract( smallestDecimalFraction ); BigDecimal diffplus = ( yplus.multiply( yplus ) ).subtract( input ); BigDecimal diff = ( y.multiply( y ) ).subtract( input ); //BigDecimal diffminus = ( yplus.multiply( yplus ) ).subtract( input ); if ( diffplus.compareTo( diff ) == -1 ) { //if ( diffplus.compareTo( diffminus ) == -1 ) { //System.out.println( "returning " + yplus ); return yplus; //} else { // return yminus; //} } else { //if ( diff.compareTo( diffminus ) == -1 ) { //System.out.println( "returning " + y ); return y; //} else { // return yminus; //} } } ///** // * Returns the square root of the input BigDecimal as a BigDecimal. There // * are limits to the size of BigDecimals this can handle, but they can have // * Integer.MAX_VALUE numbers of digits in their decimal expansion and so // * can be enormous! An exception should be thrown and caught if this is the // * case but this needs implementing. // */ //public static BigDecimal sqrt1( BigDecimal input, int decimalPlaces ) { // System.out.println( "sqrt(" + input + "," + decimalPlaces + ") {"); // BigDecimal result; // int inputScale = input.scale(); // BigInteger bi0 = input.unscaledValue(); // System.out.println( "bi0 " + bi0 ); // int numberOfDigits = ( bi0.toString().length() - 1 ) / 2; // BigInteger bi1 = new BigInteger( "10" ).pow( numberOfDigits ); // // // System.out.println( "bi1 " + bi1 ); // int i = 1; // BigInteger bi2 = bi1; // BigInteger bi3 = bi2.multiply( new BigInteger( Integer.toString( i ) ) ); // BigInteger bi4 = null; // while ( bi0.compareTo( bi2 ) == 1 ) { // bi4 = bi3; // bi3 = bi1.multiply( new BigInteger( Integer.toString( i ) ) ); // bi2 = ( bi3 ).pow( 2 ); // i ++; // } // System.out.println( "square root of " + bi0.toString() + " is between " + bi4.toString() + " and " + bi3.toString() ); // System.out.println( bi4.toString() + " squared is " + bi4.pow( 2 ) ); // System.out.println( bi3.toString() + " squared is " + bi3.pow( 2 ) ); // System.out.println( "Done 0" ); // // for ( int ite = 1; ite < numberOfDigits + 1; ite ++ ) { // bi1 = new BigInteger( "10" ).pow( numberOfDigits - ite ); // i = 1; // bi2 = bi4; // bi3 = bi2.add( bi2.multiply( bi1 ) ); // while ( bi0.compareTo( bi2 ) == 1 ) { // bi4 = bi3; // bi3 = bi1.multiply( new BigInteger( Integer.toString( i ) ) ); // bi2 = ( bi3 ).pow( 2 ); // i ++; // } // System.out.println( "square root of " + bi0.toString() + " is between " + bi4.toString() + " and " + bi3.toString() ); // System.out.println( bi4.toString() + " squared is " + bi4.pow( 2 ) ); // System.out.println( bi3.toString() + " squared is " + bi3.pow( 2 ) ); // System.out.println( "Done " + ite ); // } // // // y = (1/2)(x + a/x). // int roundingMode = BigDecimal.ROUND_HALF_EVEN; // //BigDecimal one = new BigDecimal( BigInteger.ONE ); // //BigDecimal two = new BigDecimal( new BigInteger( "2" ) ); // //BigDecimal half = one.divide( two, scale, roundingMode ); // BigDecimal half = new BigDecimal( 0.5d ); // System.out.println("" + half.toString() ); // BigDecimal x = new BigDecimal( bi4 ); // BigDecimal y; // int divideScale = inputScale * 2; // // do {//for ( int ite = 0; ite < 10; ite ++ ) { // //System.out.println("" + input.toString() + " divide " + x.toString() + " equals " + input.divide( x, scale, roundingMode ).toString() ); // y = half.multiply( ( x.add( ( input.divide( x, divideScale, roundingMode ) ) ) ) ); // x = y; // // System.out.println( "square root of " + input.toString() + " is nearly " + x.toString() ); // // System.out.println( x.toString() + " squared is " + x.multiply( x ) ); // // System.out.println( "" + ( x.multiply( x ) ).setScale( scale, roundingMode ) ); // //} while ( ( ( x.multiply( x ) ).setScale( scale, roundingMode ) ).compareTo( input ) != 0 ); // } while ( ( ( x.multiply( x ) ).setScale( inputScale, roundingMode ) ).compareTo( input ) != 0 ); // y = x.setScale( decimalPlaces, roundingMode ); // System.out.println( y.toString() + " squared is " + y.multiply( y ) ); // // BigDecimal check = new BigDecimal( BigInteger.ONE, decimalPlaces ); // System.out.println( y.add(check).toString() + " squared is " + y.add(check).multiply( y.add(check) ) ); // System.out.println( y.subtract(check).toString() + " squared is " + y.subtract(check).multiply( y.subtract(check) ) ); // //System.out.println( "" + y ); // return y; //} }