mirror of
				https://github.com/DanilaFe/abacus
				synced 2025-10-30 17:33:42 -07:00 
			
		
		
		
	Merge branch 'master' of github.com:DanilaFe/abacus
This commit is contained in:
		
						commit
						7dcc80fcae
					
				| @ -128,5 +128,9 @@ public class NaiveNumber extends NumberInterface { | |||||||
|         return Double.toString(Math.round(value * shiftBy) / shiftBy); |         return Double.toString(Math.round(value * shiftBy) / shiftBy); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     @Override | ||||||
|  |     public NumberInterface getMaxError(){ | ||||||
|  |         return new NaiveNumber(Math.pow(10, -18)); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -255,4 +255,11 @@ public abstract class NumberInterface { | |||||||
|         return promoteToInternal(toClass); |         return promoteToInternal(toClass); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Returns the smallest error this instance can tolerate depending | ||||||
|  |      * on its precision and value. | ||||||
|  |      * @return the smallest error that should be permitted in calculations. | ||||||
|  |      */ | ||||||
|  |     public abstract NumberInterface getMaxError(); | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,7 +1,7 @@ | |||||||
| package org.nwapw.abacus.number; | package org.nwapw.abacus.number; | ||||||
| 
 | 
 | ||||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||||
| import java.math.RoundingMode; | import java.math.MathContext; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * A number that uses a BigDecimal to store its value, |  * A number that uses a BigDecimal to store its value, | ||||||
| @ -22,6 +22,21 @@ public class PreciseNumber extends NumberInterface { | |||||||
|      */ |      */ | ||||||
|     public static final PreciseNumber TEN = new PreciseNumber(BigDecimal.TEN); |     public static final PreciseNumber TEN = new PreciseNumber(BigDecimal.TEN); | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * The number of extra significant figures kept in calculations before rounding for output. | ||||||
|  |      */ | ||||||
|  |     private static int numExtraInternalSigFigs = 15; | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * MathContext that is used when rounding a number prior to output. | ||||||
|  |      */ | ||||||
|  |     private static MathContext outputContext = new MathContext(50); | ||||||
|  | 
 | ||||||
|  |     /** | ||||||
|  |      * MathContext that is actually used in calculations. | ||||||
|  |      */ | ||||||
|  |     private static MathContext internalContext = new MathContext(outputContext.getPrecision()+numExtraInternalSigFigs); | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * The value of the PreciseNumber. |      * The value of the PreciseNumber. | ||||||
|      */ |      */ | ||||||
| @ -48,7 +63,7 @@ public class PreciseNumber extends NumberInterface { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public int getMaxPrecision() { |     public int getMaxPrecision() { | ||||||
|         return 65; |         return internalContext.getPrecision(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
| @ -58,7 +73,7 @@ public class PreciseNumber extends NumberInterface { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public NumberInterface divideInternal(NumberInterface divisor) { |     public NumberInterface divideInternal(NumberInterface divisor) { | ||||||
|         return new PreciseNumber(value.divide(((PreciseNumber) divisor).value, this.getMaxPrecision(), RoundingMode.HALF_UP)); |         return new PreciseNumber(value.divide(((PreciseNumber) divisor).value, internalContext)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
| @ -147,7 +162,11 @@ public class PreciseNumber extends NumberInterface { | |||||||
| 
 | 
 | ||||||
|     @Override |     @Override | ||||||
|     public String toString() { |     public String toString() { | ||||||
|         BigDecimal rounded = value.setScale(getMaxPrecision() - 15, RoundingMode.HALF_UP); |         return value.round(outputContext).toString(); | ||||||
|         return rounded.stripTrailingZeros().toPlainString(); |     } | ||||||
|  | 
 | ||||||
|  |     @Override | ||||||
|  |     public NumberInterface getMaxError(){ | ||||||
|  |         return new PreciseNumber(value.ulp()).multiplyInternal(TEN.intPowInternal(value.precision()-internalContext.getPrecision())); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -188,7 +188,7 @@ public class StandardPlugin extends Plugin { | |||||||
|          */ |          */ | ||||||
|         private NumberInterface getLogPartialSum(NumberInterface x) { |         private NumberInterface getLogPartialSum(NumberInterface x) { | ||||||
| 
 | 
 | ||||||
|             NumberInterface maxError = getMaxError(x); |             NumberInterface maxError = x.getMaxError(); | ||||||
|             x = x.subtract(NaiveNumber.ONE.promoteTo(x.getClass())); //Terms used are for log(x+1). |             x = x.subtract(NaiveNumber.ONE.promoteTo(x.getClass())); //Terms used are for log(x+1). | ||||||
|             NumberInterface currentNumerator = x, currentTerm = x, sum = x; |             NumberInterface currentNumerator = x, currentTerm = x, sum = x; | ||||||
|             int n = 1; |             int n = 1; | ||||||
| @ -207,7 +207,7 @@ public class StandardPlugin extends Plugin { | |||||||
|          * @return the value of log(2) with the appropriate precision. |          * @return the value of log(2) with the appropriate precision. | ||||||
|          */ |          */ | ||||||
|         private NumberInterface getLog2(NumberInterface number) { |         private NumberInterface getLog2(NumberInterface number) { | ||||||
|             NumberInterface maxError = getMaxError(number); |             NumberInterface maxError = number.getMaxError(); | ||||||
|             //NumberInterface errorBound = fromInt(number.getClass(), 1); |             //NumberInterface errorBound = fromInt(number.getClass(), 1); | ||||||
|             //We'll use the series \sigma_{n >= 1) ((1/3^n + 1/4^n) * 1/n) |             //We'll use the series \sigma_{n >= 1) ((1/3^n + 1/4^n) * 1/n) | ||||||
|             //In the following, a=1/3^n, b=1/4^n, c = 1/n. |             //In the following, a=1/3^n, b=1/4^n, c = 1/n. | ||||||
| @ -301,16 +301,11 @@ public class StandardPlugin extends Plugin { | |||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
|         protected NumberInterface applyInternal(NumberInterface[] params) { |         protected NumberInterface applyInternal(NumberInterface[] params) { | ||||||
|             NumberInterface maxError = getMaxError(params[0]); |             NumberInterface maxError = params[0].getMaxError(); | ||||||
|             int n = 0; |             int n = 0; | ||||||
|             if (params[0].signum() <= 0) { |             if (params[0].signum() < 0) { | ||||||
|                 NumberInterface currentTerm = NaiveNumber.ONE.promoteTo(params[0].getClass()), sum = currentTerm; |                 NumberInterface[] negatedParams = {params[0].negate()}; | ||||||
|                 while (FUNCTION_ABS.apply(currentTerm).compareTo(maxError) > 0) { |                return fromInt(params[0].getClass(), 1).divide(applyInternal(negatedParams)); | ||||||
|                     n++; |  | ||||||
|                     currentTerm = currentTerm.multiply(params[0]).divide((new NaiveNumber(n)).promoteTo(params[0].getClass())); |  | ||||||
|                     sum = sum.add(currentTerm); |  | ||||||
|                 } |  | ||||||
|                 return sum; |  | ||||||
|             } else { |             } else { | ||||||
|                 //We need n such that x^(n+1) * 3^ceil(x) <= maxError * (n+1)!. |                 //We need n such that x^(n+1) * 3^ceil(x) <= maxError * (n+1)!. | ||||||
|                 //right and left refer to lhs and rhs in the above inequality. |                 //right and left refer to lhs and rhs in the above inequality. | ||||||
| @ -352,7 +347,7 @@ public class StandardPlugin extends Plugin { | |||||||
|                 return NaiveNumber.ONE.promoteTo(params[1].getClass()); |                 return NaiveNumber.ONE.promoteTo(params[1].getClass()); | ||||||
|             //Detect integer bases: |             //Detect integer bases: | ||||||
|             if(params[0].fractionalPart().compareTo(fromInt(params[0].getClass(), 0)) == 0 |             if(params[0].fractionalPart().compareTo(fromInt(params[0].getClass(), 0)) == 0 | ||||||
|                     && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), Integer.MAX_VALUE)) < 0 |                     && FUNCTION_ABS.apply(params[1]).compareTo(fromInt(params[0].getClass(), Integer.MAX_VALUE)) < 0 | ||||||
|                     && FUNCTION_ABS.apply(params[1]).compareTo(fromInt(params[1].getClass(), 1)) >= 0){ |                     && FUNCTION_ABS.apply(params[1]).compareTo(fromInt(params[1].getClass(), 1)) >= 0){ | ||||||
|                 NumberInterface[] newParams = {params[0], params[1].fractionalPart()}; |                 NumberInterface[] newParams = {params[0], params[1].fractionalPart()}; | ||||||
|                 return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(newParams)); |                 return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(newParams)); | ||||||
| @ -476,16 +471,6 @@ public class StandardPlugin extends Plugin { | |||||||
|         return sum; |         return sum; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Returns the maximum error based on the precision of the class of number. |  | ||||||
|      * |  | ||||||
|      * @param number Any instance of the NumberInterface in question (should return an appropriate precision). |  | ||||||
|      * @return the maximum error. |  | ||||||
|      */ |  | ||||||
|     private static NumberInterface getMaxError(NumberInterface number) { |  | ||||||
|         return fromInt(number.getClass(), 10).intPow(-number.getMaxPrecision()); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * A factorial function that uses memoization for each number class; it efficiently |      * A factorial function that uses memoization for each number class; it efficiently | ||||||
|      * computes factorials of non-negative integers. |      * computes factorials of non-negative integers. | ||||||
| @ -517,7 +502,7 @@ public class StandardPlugin extends Plugin { | |||||||
|      */ |      */ | ||||||
|     private static NumberInterface sinTaylor(NumberInterface x) { |     private static NumberInterface sinTaylor(NumberInterface x) { | ||||||
|         NumberInterface power = x, multiplier = x.multiply(x).negate(), currentTerm = x, sum = x; |         NumberInterface power = x, multiplier = x.multiply(x).negate(), currentTerm = x, sum = x; | ||||||
|         NumberInterface maxError = getMaxError(x); |         NumberInterface maxError = x.getMaxError(); | ||||||
|         int n = 1; |         int n = 1; | ||||||
|         do { |         do { | ||||||
|             n += 2; |             n += 2; | ||||||
|  | |||||||
							
								
								
									
										7
									
								
								src/test/java/org/nwapw/abacus/tests/CalculationTests.java
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										7
									
								
								src/test/java/org/nwapw/abacus/tests/CalculationTests.java
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @ -88,8 +88,8 @@ public class CalculationTests { | |||||||
|     public void testExp(){ |     public void testExp(){ | ||||||
|         testOutput("exp0", "exp(0)", "1"); |         testOutput("exp0", "exp(0)", "1"); | ||||||
|         testOutput("exp1", "exp(1)", "2.718281828459045235360287471352662497757247"); |         testOutput("exp1", "exp(1)", "2.718281828459045235360287471352662497757247"); | ||||||
|         testOutput("exp300", "exp(300)", "19424263952412559365842088360176992193662086"); |         testOutput("exp300", "exp(300)", "1.9424263952412559365842088360176992193662086"); | ||||||
|         testOutput("exp300", "exp(300)", "19424263952412559365842088360176992193662086"); |         testOutput("exp(-500)", "exp((500)`)", "7.1245764067412855315491573771227552469277568"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @Test |     @Test | ||||||
| @ -99,6 +99,9 @@ public class CalculationTests { | |||||||
|         testOutput("2^1", "(2^1)", "2"); |         testOutput("2^1", "(2^1)", "2"); | ||||||
|         testOutput("2^-1", "(2^(1)`)", "0.5"); |         testOutput("2^-1", "(2^(1)`)", "0.5"); | ||||||
|         testOutput("2^50", "(2^50)", "112589990684262"); |         testOutput("2^50", "(2^50)", "112589990684262"); | ||||||
|  |         testOutput("7^(-sqrt2*17)", "(7^((sqrt(2)*17))`)", "4.81354609155297814551845300063563"); | ||||||
|  |         testEvalError("0^0", "(0^0)"); | ||||||
|  |         testEvalError("(-13)^.9999", "((13)`^0.9999)"); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user