Skip to content

Commit 4078706

Browse files
committed
update Java version
1 parent 0586e6e commit 4078706

13 files changed

Lines changed: 350 additions & 302 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ project, add the following to the `dependencies` section in your `pom.xml` file:
1919
<dependency>
2020
<groupId>com.github.peteroupc</groupId>
2121
<artifactId>numbers</artifactId>
22-
<version>0.2.0</version>
22+
<version>0.2.1</version>
2323
</dependency>
2424
```
2525

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<groupId>com.github.peteroupc</groupId>
55
<artifactId>numbers</artifactId>
66
<packaging>jar</packaging>
7-
<version>0.2.0</version>
7+
<version>0.2.1</version>
88
<name>Numbers</name>
99
<description>
1010
A Java implementation that supports arbitrary-precision binary and decimal floating-point numbers and rational numbers with arbitrary-precision components, and supports arithmetic with these numbers.

src/main/java/com/upokecenter/numbers/EContext.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ public final class EContext {
191191
private int traps;
192192

193193
/**
194-
* Initializes a new instance of the <see cref='T:PeterO.Numbers.EContext'/>
194+
* Initializes a new instance of the {@link com.upokecenter.numbers.EContext}
195195
* class. <code>HasFlags</code> will be set to false.
196196
* @param precision The parameter {@code precision} is not documented yet.
197197
* @param rounding The parameter {@code rounding} is not documented yet.
@@ -298,7 +298,8 @@ public final EInteger getEMin() {
298298
* method. For example: <code>(this.getFlags() &amp; EContext.FlagInexact) !=
299299
* 0</code> returns TRUE if the Inexact flag is set.
300300
* @return The flags that are set from converting numbers according to this
301-
* arithmetic context. If HasFlags is false, this value will be 0.
301+
* arithmetic context. If {@code HasFlags} is false, this value will be
302+
* 0.
302303
*/
303304
public final int getFlags() {
304305
return this.flags;

src/main/java/com/upokecenter/numbers/EDecimal.java

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -47,52 +47,52 @@
4747
* (NaN) values, and infinity. <b>Negative zero</b> is generally used
4848
* when a negative number is rounded to 0; it has the same mathematical
4949
* value as positive zero. <b>Infinity</b> is generally used when a
50-
* non-zero number is divided by zero, or when a very high number can't
51-
* be represented in a given exponent range. <b>Not-a-number</b> is
52-
* generally used to signal errors.</p> <p>This class implements the
53-
* General Decimal Arithmetic Specification version 1.70 (except part of
54-
* chapter 6): <code>http://speleotrove.com/decimal/decarith.html</code></p>
55-
* <p><b>Errors and Exceptions</b></p> <p>Passing a signaling NaN to any
56-
* arithmetic operation shown here will signal the flag FlagInvalid and
57-
* return a quiet NaN, even if another operand to that operation is a
58-
* quiet NaN, unless noted otherwise.</p> <p>Passing a quiet NaN to any
59-
* arithmetic operation shown here will return a quiet NaN, unless noted
60-
* otherwise. Invalid operations will also return a quiet NaN, as stated
61-
* in the individual methods.</p> <p>Unless noted otherwise, passing a
62-
* null arbitrary-precision decimal argument to any method here will
63-
* throw an exception.</p> <p>When an arithmetic operation signals the
64-
* flag FlagInvalid, FlagOverflow, or FlagDivideByZero, it will not
65-
* throw an exception too, unless the flag's trap is enabled in the
66-
* arithmetic context (see EContext's Traps property).</p> <p>If an
67-
* operation requires creating an intermediate value that might be too
68-
* big to fit in memory (or might require more than 2 gigabytes of
69-
* memory to store -- due to the current use of a 32-bit integer
70-
* internally as a length), the operation may signal an
71-
* invalid-operation flag and return not-a-number (NaN). In certain rare
72-
* cases, the compareTo method may throw OutOfMemoryError (called
73-
* OutOfMemoryError in Java) in the same circumstances.</p>
74-
* <p><b>Serialization</b></p> <p>An arbitrary-precision decimal value
75-
* can be serialized (converted to a stable format) in one of the
76-
* following ways:</p> <ul> <li>By calling the toString() method, which
77-
* will always return distinct strings for distinct arbitrary-precision
78-
* decimal values.</li> <li>By calling the UnsignedMantissa, Exponent,
79-
* and IsNegative properties, and calling the IsInfinity, IsQuietNaN,
80-
* and IsSignalingNaN methods. The return values combined will uniquely
81-
* identify a particular arbitrary-precision decimal value.</li></ul>
82-
* <p><b>Thread safety</b></p> <p>Instances of this class are immutable,
83-
* so they are inherently safe for use by multiple threads. Multiple
84-
* instances of this object with the same properties are
85-
* interchangeable, so they should not be compared using the "=="
86-
* operator (which only checks if each side of the operator is the same
87-
* instance).</p> <p><b>Comparison considerations</b></p> <p>This
88-
* class's natural ordering (under the compareTo method) is not
89-
* consistent with the Equals method. This means that two values that
90-
* compare as equal under the compareTo method might not be equal under
91-
* the Equals method. The compareTo method compares the mathematical
92-
* values of the two instances passed to it (and considers two different
93-
* NaN values as equal), while two instances with the same mathematical
94-
* value, but different exponents, will be considered unequal under the
95-
* Equals method.</p>
50+
* non-zero number is divided by zero, or when a very high or very low
51+
* number can't be represented in a given exponent range.
52+
* <b>Not-a-number</b> is generally used to signal errors.</p> <p>This
53+
* class implements the General Decimal Arithmetic Specification version
54+
* 1.70 (except part of chapter 6):
55+
* <code>http://speleotrove.com/decimal/decarith.html</code></p> <p><b>Errors
56+
* and Exceptions</b></p> <p>Passing a signaling NaN to any arithmetic
57+
* operation shown here will signal the flag FlagInvalid and return a
58+
* quiet NaN, even if another operand to that operation is a quiet NaN,
59+
* unless noted otherwise.</p> <p>Passing a quiet NaN to any arithmetic
60+
* operation shown here will return a quiet NaN, unless noted otherwise.
61+
* Invalid operations will also return a quiet NaN, as stated in the
62+
* individual methods.</p> <p>Unless noted otherwise, passing a null
63+
* arbitrary-precision decimal argument to any method here will throw an
64+
* exception.</p> <p>When an arithmetic operation signals the flag
65+
* FlagInvalid, FlagOverflow, or FlagDivideByZero, it will not throw an
66+
* exception too, unless the flag's trap is enabled in the arithmetic
67+
* context (see EContext's Traps property).</p> <p>If an operation
68+
* requires creating an intermediate value that might be too big to fit
69+
* in memory (or might require more than 2 gigabytes of memory to store
70+
* -- due to the current use of a 32-bit integer internally as a
71+
* length), the operation may signal an invalid-operation flag and
72+
* return not-a-number (NaN). In certain rare cases, the compareTo
73+
* method may throw OutOfMemoryError (called OutOfMemoryError in
74+
* Java) in the same circumstances.</p> <p><b>Serialization</b></p>
75+
* <p>An arbitrary-precision decimal value can be serialized (converted
76+
* to a stable format) in one of the following ways:</p> <ul> <li>By
77+
* calling the toString() method, which will always return distinct
78+
* strings for distinct arbitrary-precision decimal values.</li> <li>By
79+
* calling the UnsignedMantissa, Exponent, and IsNegative properties,
80+
* and calling the IsInfinity, IsQuietNaN, and IsSignalingNaN methods.
81+
* The return values combined will uniquely identify a particular
82+
* arbitrary-precision decimal value.</li></ul> <p><b>Thread
83+
* safety</b></p> <p>Instances of this class are immutable, so they are
84+
* inherently safe for use by multiple threads. Multiple instances of
85+
* this object with the same properties are interchangeable, so they
86+
* should not be compared using the "==" operator (which only checks if
87+
* each side of the operator is the same instance).</p> <p><b>Comparison
88+
* considerations</b></p> <p>This class's natural ordering (under the
89+
* compareTo method) is not consistent with the Equals method. This
90+
* means that two values that compare as equal under the compareTo
91+
* method might not be equal under the Equals method. The compareTo
92+
* method compares the mathematical values of the two instances passed
93+
* to it (and considers two different NaN values as equal), while two
94+
* instances with the same mathematical value, but different exponents,
95+
* will be considered unequal under the Equals method.</p>
9696
*/
9797
public final class EDecimal implements Comparable<EDecimal> {
9898
//----------------------------------------------------------------

src/main/java/com/upokecenter/numbers/EFloat.java

Lines changed: 60 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -2384,94 +2384,43 @@ public double ToDouble() {
23842384
}
23852385
return Extras.IntegersToDouble(nan);
23862386
}
2387-
if (this.isNegative() && this.isZero()) {
2388-
return Extras.IntegersToDouble(new int[] { 0, ((int)(1 << 31)) });
2389-
}
2390-
EInteger bigmant = this.unsignedMantissa.Abs();
2391-
FastInteger bigexponent = FastInteger.FromBig(this.exponent);
2392-
int bitLeftmost = 0;
2393-
int bitsAfterLeftmost = 0;
2394-
if (this.unsignedMantissa.isZero()) {
2395-
return 0.0d;
2387+
EFloat thisValue = this.RoundToPrecision(EContext.Binary64);
2388+
if (!thisValue.isFinite()) {
2389+
return thisValue.ToDouble();
23962390
}
2397-
int[] mantissaBits;
2398-
if (bigmant.compareTo(ValueOneShift52) < 0) {
2399-
mantissaBits = FastInteger.GetLastWords(bigmant, 2);
2400-
// This will be an infinite loop if both elements
2401-
// of the bits array are 0, but the check for
2402-
// 0 was already done above
2403-
while (!NumberUtility.HasBitSet(mantissaBits, 52)) {
2404-
NumberUtility.ShiftLeftOne(mantissaBits);
2405-
bigexponent.Decrement();
2406-
}
2407-
} else {
2408-
BitShiftAccumulator accum = new BitShiftAccumulator(bigmant, 0, 0);
2409-
accum.ShiftToDigitsInt(53);
2410-
bitsAfterLeftmost = accum.getOlderDiscardedDigits();
2411-
bitLeftmost = accum.getLastDiscardedDigit();
2412-
bigexponent.Add(accum.getDiscardedDigitCount());
2413-
mantissaBits = FastInteger.GetLastWords(accum.getShiftedInt(), 2);
2414-
}
2415-
// Round half-even
2416-
if (bitLeftmost > 0 && (bitsAfterLeftmost > 0 ||
2417-
NumberUtility.HasBitSet(mantissaBits, 0))) {
2418-
// Add 1 to the bits
2419-
mantissaBits[0] = ((int)(mantissaBits[0] + 1));
2420-
if (mantissaBits[0] == 0) {
2421-
mantissaBits[1] = ((int)(mantissaBits[1] + 1));
2422-
}
2423-
if (mantissaBits[0] == 0 &&
2424-
mantissaBits[1] == (1 << 21)) { // if mantissa is now 2^53
2425-
mantissaBits[1] >>= 1; // change it to 2^52
2426-
bigexponent.Increment();
2427-
}
2391+
EInteger mant = thisValue.unsignedMantissa;
2392+
if (thisValue.isNegative() && mant.isZero()) {
2393+
return Extras.IntegersToDouble(new int[] { 0, ((int)(1 << 31)) });
2394+
} else if (mant.isZero()) {
2395+
return 0.0;
24282396
}
2397+
// DebugUtility.Log("-->" + (//
2398+
// thisValue.unsignedMantissa.ToRadixString(2)) + ", " + (//
2399+
// thisValue.exponent));
2400+
int bitLength = mant.GetUnsignedBitLength();
2401+
2402+
int expo = thisValue.exponent.ToInt32Checked();
24292403
boolean subnormal = false;
2430-
if (bigexponent.CompareToInt(971) > 0) {
2431-
// exponent too big
2432-
return this.isNegative() ? Double.NEGATIVE_INFINITY :
2433-
Double.POSITIVE_INFINITY;
2434-
}
2435-
if (bigexponent.CompareToInt(-1074) < 0) {
2436-
// subnormal
2437-
subnormal = true;
2438-
// Shift while number remains subnormal
2439-
BitShiftAccumulator accum = new BitShiftAccumulator(
2440-
FastInteger.WordsToEInteger(mantissaBits),
2441-
0,
2442-
0);
2443-
FastInteger fi = bigexponent.Copy().SubtractInt(-1074).Abs();
2444-
accum.ShiftRight(fi);
2445-
bitsAfterLeftmost = accum.getOlderDiscardedDigits();
2446-
bitLeftmost = accum.getLastDiscardedDigit();
2447-
bigexponent.Add(accum.getDiscardedDigitCount());
2448-
mantissaBits = FastInteger.GetLastWords(accum.getShiftedInt(), 2);
2449-
// Round half-even
2450-
if (bitLeftmost > 0 && (bitsAfterLeftmost > 0 ||
2451-
NumberUtility.HasBitSet(mantissaBits, 0))) {
2452-
// Add 1 to the bits
2453-
mantissaBits[0] = ((int)(mantissaBits[0] + 1));
2454-
if (mantissaBits[0] == 0) {
2455-
mantissaBits[1] = ((int)(mantissaBits[1] + 1));
2456-
}
2457-
if (mantissaBits[0] == 0 &&
2458-
mantissaBits[1] == (1 << 21)) { // if mantissa is now 2^53
2459-
mantissaBits[1] >>= 1; // change it to 2^52
2460-
bigexponent.Increment();
2461-
}
2404+
if (bitLength < 53) {
2405+
int diff = 53 - bitLength;
2406+
expo -= diff;
2407+
if (expo < -1074) {
2408+
// DebugUtility.Log("Diff changed from " + diff + " to " + (diff -
2409+
// (-1074 - expo)));
2410+
diff -= -1074 - expo;
2411+
expo = -1074;
2412+
subnormal = true;
24622413
}
2414+
mant = mant.ShiftLeft(diff);
2415+
bitLength += diff;
24632416
}
2464-
if (bigexponent.CompareToInt(-1074) < 0) {
2465-
// exponent too small, so return zero
2466-
return this.isNegative() ?
2467-
Extras.IntegersToDouble(new int[] { 0, ((int)0x80000000) }) :
2468-
0.0d;
2469-
}
2470-
bigexponent.AddInt(1075);
2417+
// DebugUtility.Log("2->" + (mant.ToRadixString(2)) + ", " + expo);
2418+
int[] mantissaBits;
2419+
mantissaBits = FastInteger.GetLastWords(mant, 2);
24712420
// Clear the high bits where the exponent and sign are
24722421
mantissaBits[1] &= 0xfffff;
24732422
if (!subnormal) {
2474-
int smallexponent = bigexponent.AsInt32() << 20;
2423+
int smallexponent = (expo + 1075) << 20;
24752424
mantissaBits[1] |= smallexponent;
24762425
}
24772426
if (this.isNegative()) {
@@ -2728,89 +2677,45 @@ public float ToSingle() {
27282677
}
27292678
return Float.intBitsToFloat(nan);
27302679
}
2731-
if (this.isNegative() && this.isZero()) {
2732-
return Float.intBitsToFloat(1 << 31);
2680+
EFloat thisValue = this.RoundToPrecision(EContext.Binary32);
2681+
if (!thisValue.isFinite()) {
2682+
return thisValue.ToSingle();
27332683
}
2734-
EInteger bigmant = this.unsignedMantissa.Abs();
2735-
FastInteger bigexponent = FastInteger.FromBig(this.exponent);
2736-
int bitLeftmost = 0;
2737-
int bitsAfterLeftmost = 0;
2738-
if (this.unsignedMantissa.isZero()) {
2684+
EInteger mant = thisValue.unsignedMantissa;
2685+
if (thisValue.isNegative() && mant.isZero()) {
2686+
return Float.intBitsToFloat(1 << 31);
2687+
} else if (mant.isZero()) {
27392688
return 0.0f;
27402689
}
2741-
int smallmant = 0;
2742-
FastInteger fastSmallMant;
2743-
if (bigmant.compareTo(ValueOneShift23) < 0) {
2744-
smallmant = bigmant.AsInt32Checked();
2745-
int exponentchange = 0;
2746-
while (smallmant < (1 << 23)) {
2747-
smallmant <<= 1;
2748-
++exponentchange;
2749-
}
2750-
bigexponent.SubtractInt(exponentchange);
2751-
fastSmallMant = new FastInteger(smallmant);
2752-
} else {
2753-
BitShiftAccumulator accum = new BitShiftAccumulator(bigmant, 0, 0);
2754-
accum.ShiftToDigitsInt(24);
2755-
bitsAfterLeftmost = accum.getOlderDiscardedDigits();
2756-
bitLeftmost = accum.getLastDiscardedDigit();
2757-
bigexponent.Add(accum.getDiscardedDigitCount());
2758-
fastSmallMant = accum.getShiftedIntFast();
2759-
}
2760-
// Round half-even
2761-
if (bitLeftmost > 0 && (bitsAfterLeftmost > 0 ||
2762-
!fastSmallMant.isEvenNumber())) {
2763-
fastSmallMant.Increment();
2764-
if (fastSmallMant.CompareToInt(1 << 24) == 0) {
2765-
fastSmallMant = new FastInteger(1 << 23);
2766-
bigexponent.Increment();
2767-
}
2768-
}
2690+
// DebugUtility.Log("-->" + (//
2691+
// thisValue.unsignedMantissa.ToRadixString(2)) + ", " + (//
2692+
// thisValue.exponent));
2693+
int bitLength = mant.GetUnsignedBitLength();
2694+
2695+
int expo = thisValue.exponent.ToInt32Checked();
27692696
boolean subnormal = false;
2770-
if (bigexponent.CompareToInt(104) > 0) {
2771-
// exponent too big
2772-
return this.isNegative() ? Float.NEGATIVE_INFINITY :
2773-
Float.POSITIVE_INFINITY;
2774-
}
2775-
if (bigexponent.CompareToInt(-149) < 0) {
2776-
// subnormal
2777-
subnormal = true;
2778-
// Shift while number remains subnormal
2779-
BitShiftAccumulator accum =
2780-
BitShiftAccumulator.FromInt32(fastSmallMant.AsInt32());
2781-
FastInteger fi = bigexponent.Copy().SubtractInt(-149).Abs();
2782-
accum.ShiftRight(fi);
2783-
bitsAfterLeftmost = accum.getOlderDiscardedDigits();
2784-
bitLeftmost = accum.getLastDiscardedDigit();
2785-
bigexponent.Add(accum.getDiscardedDigitCount());
2786-
fastSmallMant = accum.getShiftedIntFast();
2787-
// Round half-even
2788-
if (bitLeftmost > 0 && (bitsAfterLeftmost > 0 ||
2789-
!fastSmallMant.isEvenNumber())) {
2790-
fastSmallMant.Increment();
2791-
if (fastSmallMant.CompareToInt(1 << 24) == 0) {
2792-
fastSmallMant = new FastInteger(1 << 23);
2793-
bigexponent.Increment();
2794-
}
2697+
if (bitLength < 24) {
2698+
int diff = 24 - bitLength;
2699+
expo -= diff;
2700+
if (expo < -149) {
2701+
// DebugUtility.Log("Diff changed from " + diff + " to " + (diff -
2702+
// (-149 - expo)));
2703+
diff -= -149 - expo;
2704+
expo = -149;
2705+
subnormal = true;
27952706
}
2707+
mant = mant.ShiftLeft(diff);
2708+
bitLength += diff;
27962709
}
2797-
if (bigexponent.CompareToInt(-149) < 0) {
2798-
// exponent too small, so return zero
2799-
return this.isNegative() ?
2800-
Float.intBitsToFloat(1 << 31) :
2801-
Float.intBitsToFloat(0);
2802-
} else {
2803-
int smallexponent = bigexponent.AsInt32();
2804-
smallexponent += 150;
2805-
int smallmantissa = ((int)fastSmallMant.AsInt32()) & 0x7fffff;
2806-
if (!subnormal) {
2807-
smallmantissa |= smallexponent << 23;
2808-
}
2809-
if (this.isNegative()) {
2710+
// DebugUtility.Log("2->" + (mant.ToRadixString(2)) + ", " + expo);
2711+
int smallmantissa = ((int)mant.ToInt32Checked()) & 0x7fffff;
2712+
if (!subnormal) {
2713+
smallmantissa |= (expo + 150) << 23;
2714+
}
2715+
if (this.isNegative()) {
28102716
smallmantissa |= 1 << 31;
2811-
}
2812-
return Float.intBitsToFloat(smallmantissa);
28132717
}
2718+
return Float.intBitsToFloat(smallmantissa);
28142719
}
28152720

28162721
/**

0 commit comments

Comments
 (0)