OpenJDK / jdk-updates / jdk12u
changeset 34830:efc64ab95152
Merge
author | lana |
---|---|
date | Thu, 24 Dec 2015 10:34:31 -0800 |
parents | 1e2e466a896b 243172880dd3 |
children | dc7f444c7b85 |
files | jdk/src/java.base/share/classes/sun/misc/CompoundEnumeration.java jdk/src/java.base/share/classes/sun/misc/DoubleConsts.java jdk/src/java.base/share/classes/sun/misc/FDBigInteger.java jdk/src/java.base/share/classes/sun/misc/FloatConsts.java jdk/src/java.base/share/classes/sun/misc/FloatingDecimal.java jdk/src/java.base/share/classes/sun/misc/FormattedFloatingDecimal.java jdk/test/java/awt/Mouse/MaximizedFrameTest/MaximizedFrameTest.html jdk/test/javax/sound/midi/MidiDeviceProvider/FakeInfo.java jdk/test/javax/sound/midi/MidiDeviceProvider/NullInfo.java jdk/test/javax/sound/midi/MidiDeviceProvider/UnsupportedInfo.java jdk/test/sun/misc/FloatingDecimal/OldFDBigIntForTest.java jdk/test/sun/misc/FloatingDecimal/OldFloatingDecimalForTest.java jdk/test/sun/misc/FloatingDecimal/TestFDBigInteger.java jdk/test/sun/misc/FloatingDecimal/TestFloatingDecimal.java |
diffstat | 247 files changed, 22387 insertions(+), 10087 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/make/launcher/Launcher-jdk.accessibility.gmk Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/make/launcher/Launcher-jdk.accessibility.gmk Thu Dec 24 10:34:31 2015 -0800 @@ -73,8 +73,9 @@ $$(eval $$(call SetupNativeCompilation, BUILD_JACCESSINSPECTOR$1, \ SRC := $(TOPDIR)/jaccessinspector $(TOPDIR)/common \ $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \ - CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \ - LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib User32.lib, \ + CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 -EHsc, \ + LDFLAGS := $$(LDFLAGS_JDKEXE) -stack:655360, \ + LIBS := advapi32.lib user32.lib, \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccessinspector$1, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \ PROGRAM := jaccessinspector$1, \ @@ -100,8 +101,9 @@ $$(eval $$(call SetupNativeCompilation,BUILD_JACCESSWALKER$1, \ SRC := $(TOPDIR)/jaccesswalker $(TOPDIR)/common \ $(TOPDIR)/toolscommon $(TOPDIR)/include/bridge, \ - CFLAGS :== $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 /EHsc, \ - LDFLAGS := $$(LDFLAGS_JDKEXE) /STACK:655360 Advapi32.lib Comctl32.lib Gdi32.lib User32.lib, \ + CFLAGS := $$(CFLAGS_JDKEXE) $(TOOLS_CFLAGS) -DACCESSBRIDGE_ARCH_$2 -EHsc, \ + LDFLAGS := $$(LDFLAGS_JDKEXE) -stack:655360, \ + LIBS := advapi32.lib comctl32.lib gdi32.lib user32.lib, \ OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/jdk.accessibility/jaccesswalker$1, \ OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_cmds/jdk.accessibility, \ PROGRAM := jaccesswalker$1, \
--- a/jdk/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/linux/classes/sun/nio/ch/EPollSelectorImpl.java Thu Dec 24 10:34:31 2015 -0800 @@ -29,7 +29,6 @@ import java.nio.channels.*; import java.nio.channels.spi.*; import java.util.*; -import sun.misc.*; /** * An implementation of Selector for Linux 2.6+ kernels that uses @@ -50,7 +49,7 @@ private Map<Integer,SelectionKeyImpl> fdToKey; // True if this Selector has been closed - private volatile boolean closed = false; + private volatile boolean closed; // Lock for interrupt triggering and clearing private final Object interruptLock = new Object();
--- a/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java Thu Dec 24 10:34:31 2015 -0800 @@ -93,7 +93,7 @@ // Instance of this provider, so we don't have to call the provider list // to find ourselves or run the risk of not being in the list. - private static volatile SunJCE instance = null; + private static volatile SunJCE instance; // lazy initialize SecureRandom to avoid potential recursion if Sun // provider has not been installed yet
--- a/jdk/src/java.base/share/classes/java/io/File.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/io/File.java Thu Dec 24 10:34:31 2015 -0800 @@ -420,11 +420,11 @@ String scheme = uri.getScheme(); if ((scheme == null) || !scheme.equalsIgnoreCase("file")) throw new IllegalArgumentException("URI scheme is not \"file\""); - if (uri.getAuthority() != null) + if (uri.getRawAuthority() != null) throw new IllegalArgumentException("URI has an authority component"); - if (uri.getFragment() != null) + if (uri.getRawFragment() != null) throw new IllegalArgumentException("URI has a fragment component"); - if (uri.getQuery() != null) + if (uri.getRawQuery() != null) throw new IllegalArgumentException("URI has a query component"); String p = uri.getPath(); if (p.equals(""))
--- a/jdk/src/java.base/share/classes/java/io/PipedInputStream.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/io/PipedInputStream.java Thu Dec 24 10:34:31 2015 -0800 @@ -48,9 +48,9 @@ * @since 1.0 */ public class PipedInputStream extends InputStream { - boolean closedByWriter = false; - volatile boolean closedByReader = false; - boolean connected = false; + boolean closedByWriter; + volatile boolean closedByReader; + boolean connected; /* REMIND: identification of the read and write sides needs to be more sophisticated. Either using thread groups (but what about
--- a/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/AbstractStringBuilder.java Thu Dec 24 10:34:31 2015 -0800 @@ -25,7 +25,7 @@ package java.lang; -import sun.misc.FloatingDecimal; +import jdk.internal.math.FloatingDecimal; import java.util.Arrays; import java.util.Spliterator; import java.util.stream.IntStream;
--- a/jdk/src/java.base/share/classes/java/lang/Class.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/Class.java Thu Dec 24 10:34:31 2015 -0800 @@ -2518,7 +2518,7 @@ // Incremented by the VM on each call to JVM TI RedefineClasses() // that redefines this class or a superclass. - private transient volatile int classRedefinedCount = 0; + private transient volatile int classRedefinedCount; // Lazily create and cache ReflectionData private ReflectionData<T> reflectionData() { @@ -3331,7 +3331,8 @@ * uncloned, cached, and shared by all callers. */ T[] getEnumConstantsShared() { - if (enumConstants == null) { + T[] constants = enumConstants; + if (constants == null) { if (!isEnum()) return null; try { final Method values = getMethod("values"); @@ -3344,16 +3345,16 @@ }); @SuppressWarnings("unchecked") T[] temporaryConstants = (T[])values.invoke(null); - enumConstants = temporaryConstants; + enumConstants = constants = temporaryConstants; } // These can happen when users concoct enum-like classes // that don't comply with the enum spec. catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException ex) { return null; } } - return enumConstants; + return constants; } - private transient volatile T[] enumConstants = null; + private transient volatile T[] enumConstants; /** * Returns a map from simple name to enum constant. This package-private @@ -3363,19 +3364,21 @@ * created lazily on first use. Typically it won't ever get created. */ Map<String, T> enumConstantDirectory() { - if (enumConstantDirectory == null) { + Map<String, T> directory = enumConstantDirectory; + if (directory == null) { T[] universe = getEnumConstantsShared(); if (universe == null) throw new IllegalArgumentException( getName() + " is not an enum type"); - Map<String, T> m = new HashMap<>(2 * universe.length); - for (T constant : universe) - m.put(((Enum<?>)constant).name(), constant); - enumConstantDirectory = m; + directory = new HashMap<>(2 * universe.length); + for (T constant : universe) { + directory.put(((Enum<?>)constant).name(), constant); + } + enumConstantDirectory = directory; } - return enumConstantDirectory; + return directory; } - private transient volatile Map<String, T> enumConstantDirectory = null; + private transient volatile Map<String, T> enumConstantDirectory; /** * Casts an object to the class or interface represented
--- a/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/ClassLoader.java Thu Dec 24 10:34:31 2015 -0800 @@ -45,11 +45,11 @@ import java.util.Set; import java.util.Stack; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Vector; import java.util.Hashtable; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; -import sun.misc.CompoundEnumeration; import sun.misc.Resource; import sun.misc.URLClassPath; import sun.reflect.CallerSensitive; @@ -2206,3 +2206,36 @@ return sys; } } + +/* + * A utility class that will enumerate over an array of enumerations. + */ +final class CompoundEnumeration<E> implements Enumeration<E> { + private final Enumeration<E>[] enums; + private int index; + + public CompoundEnumeration(Enumeration<E>[] enums) { + this.enums = enums; + } + + private boolean next() { + while (index < enums.length) { + if (enums[index] != null && enums[index].hasMoreElements()) { + return true; + } + index++; + } + return false; + } + + public boolean hasMoreElements() { + return next(); + } + + public E nextElement() { + if (!next()) { + throw new NoSuchElementException(); + } + return enums[index].nextElement(); + } +}
--- a/jdk/src/java.base/share/classes/java/lang/Double.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/Double.java Thu Dec 24 10:34:31 2015 -0800 @@ -25,8 +25,8 @@ package java.lang; -import sun.misc.FloatingDecimal; -import sun.misc.DoubleConsts; +import jdk.internal.math.FloatingDecimal; +import jdk.internal.math.DoubleConsts; import jdk.internal.HotSpotIntrinsicCandidate; /**
--- a/jdk/src/java.base/share/classes/java/lang/Float.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/Float.java Thu Dec 24 10:34:31 2015 -0800 @@ -25,9 +25,9 @@ package java.lang; -import sun.misc.FloatingDecimal; -import sun.misc.FloatConsts; -import sun.misc.DoubleConsts; +import jdk.internal.math.FloatingDecimal; +import jdk.internal.math.FloatConsts; +import jdk.internal.math.DoubleConsts; import jdk.internal.HotSpotIntrinsicCandidate; /**
--- a/jdk/src/java.base/share/classes/java/lang/Math.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/Math.java Thu Dec 24 10:34:31 2015 -0800 @@ -26,8 +26,8 @@ package java.lang; import java.util.Random; -import sun.misc.FloatConsts; -import sun.misc.DoubleConsts; +import jdk.internal.math.FloatConsts; +import jdk.internal.math.DoubleConsts; import jdk.internal.HotSpotIntrinsicCandidate; /**
--- a/jdk/src/java.base/share/classes/java/lang/StrictMath.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/StrictMath.java Thu Dec 24 10:34:31 2015 -0800 @@ -26,7 +26,7 @@ package java.lang; import java.util.Random; -import sun.misc.DoubleConsts; +import jdk.internal.math.DoubleConsts; import jdk.internal.HotSpotIntrinsicCandidate; /**
--- a/jdk/src/java.base/share/classes/java/lang/System.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/System.java Thu Dec 24 10:34:31 2015 -0800 @@ -132,7 +132,7 @@ /* The security manager for the system. */ - private static volatile SecurityManager security = null; + private static volatile SecurityManager security; /** * Reassigns the "standard" input stream. @@ -206,7 +206,7 @@ setErr0(err); } - private static volatile Console cons = null; + private static volatile Console cons; /** * Returns the unique {@link java.io.Console Console} object associated * with the current Java virtual machine, if any. @@ -216,12 +216,13 @@ * @since 1.6 */ public static Console console() { - if (cons == null) { + Console c = cons; + if (c == null) { synchronized (System.class) { - cons = SharedSecrets.getJavaIOAccess().console(); + cons = c = SharedSecrets.getJavaIOAccess().console(); } } - return cons; + return c; } /**
--- a/jdk/src/java.base/share/classes/java/lang/Thread.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/Thread.java Thu Dec 24 10:34:31 2015 -0800 @@ -207,12 +207,10 @@ /* For generating thread ID */ private static long threadSeqNumber; - /* Java thread status for tools, - * initialized to indicate thread 'not yet started' + /* + * Java thread status for tools, default indicates thread 'not yet started' */ - - private volatile int threadStatus = 0; - + private volatile int threadStatus; private static synchronized long nextThreadID() { return ++threadSeqNumber;
--- a/jdk/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java Thu Dec 24 10:34:31 2015 -0800 @@ -53,7 +53,7 @@ private static class Lock { }; private Lock lock = new Lock(); - private volatile Reference<? extends T> head = null; + private volatile Reference<? extends T> head; private long queueLength = 0; boolean enqueue(Reference<? extends T> r) { /* Called only by Reference class */
--- a/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/lang/reflect/Parameter.java Thu Dec 24 10:34:31 2015 -0800 @@ -205,7 +205,7 @@ return tmp; } - private transient volatile Type parameterTypeCache = null; + private transient volatile Type parameterTypeCache; /** * Returns a {@code Class} object that identifies the @@ -237,7 +237,7 @@ return executable.getAnnotatedParameterTypes()[index]; } - private transient volatile Class<?> parameterClassCache = null; + private transient volatile Class<?> parameterClassCache; /** * Returns {@code true} if this parameter is implicitly declared
--- a/jdk/src/java.base/share/classes/java/math/BigInteger.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/math/BigInteger.java Thu Dec 24 10:34:31 2015 -0800 @@ -38,8 +38,8 @@ import java.util.Random; import java.util.concurrent.ThreadLocalRandom; -import sun.misc.DoubleConsts; -import sun.misc.FloatConsts; +import jdk.internal.math.DoubleConsts; +import jdk.internal.math.FloatConsts; import jdk.internal.HotSpotIntrinsicCandidate; /**
--- a/jdk/src/java.base/share/classes/java/net/URI.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/net/URI.java Thu Dec 24 10:34:31 2015 -0800 @@ -33,7 +33,6 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; -import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.nio.charset.CharacterCodingException; @@ -490,17 +489,17 @@ private transient String path; // null ==> opaque private transient String query; - // The remaining fields may be computed on demand - - private transient volatile String schemeSpecificPart; - private transient volatile int hash; // Zero ==> undefined - - private transient volatile String decodedUserInfo = null; - private transient volatile String decodedAuthority = null; - private transient volatile String decodedPath = null; - private transient volatile String decodedQuery = null; - private transient volatile String decodedFragment = null; - private transient volatile String decodedSchemeSpecificPart = null; + // The remaining fields may be computed on demand, which is safe even in + // the face of multiple threads racing to initialize them + private transient String schemeSpecificPart; + private transient int hash; // Zero ==> undefined + + private transient String decodedUserInfo; + private transient String decodedAuthority; + private transient String decodedPath; + private transient String decodedQuery; + private transient String decodedFragment; + private transient String decodedSchemeSpecificPart; /** * The string form of this URI. @@ -911,8 +910,7 @@ // either more fields or a more-obscure representation. if ((host != null) || (authority == null)) return this; - defineString(); - new Parser(string).parse(true); + new Parser(toString()).parse(true); return this; } @@ -1144,8 +1142,17 @@ * (never {@code null}) */ public String getRawSchemeSpecificPart() { - defineSchemeSpecificPart(); - return schemeSpecificPart; + String part = schemeSpecificPart; + if (part != null) { + return part; + } + StringBuilder sb = new StringBuilder(); + appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(), + host, port, getPath(), getQuery()); + if (sb.length() == 0) { + return null; + } + return schemeSpecificPart = sb.toString(); } /** @@ -1160,9 +1167,11 @@ * (never {@code null}) */ public String getSchemeSpecificPart() { - if (decodedSchemeSpecificPart == null) - decodedSchemeSpecificPart = decode(getRawSchemeSpecificPart()); - return decodedSchemeSpecificPart; + String part = decodedSchemeSpecificPart; + if (part == null) { + decodedSchemeSpecificPart = part = decode(getRawSchemeSpecificPart()); + } + return part; } /** @@ -1193,9 +1202,11 @@ * or {@code null} if the authority is undefined */ public String getAuthority() { - if (decodedAuthority == null) - decodedAuthority = decode(authority); - return decodedAuthority; + String auth = decodedAuthority; + if ((auth == null) && (authority != null)) { + decodedAuthority = auth = decode(authority); + } + return auth; } /** @@ -1223,9 +1234,11 @@ * or {@code null} if the user information is undefined */ public String getUserInfo() { - if ((decodedUserInfo == null) && (userInfo != null)) - decodedUserInfo = decode(userInfo); - return decodedUserInfo; + String user = decodedUserInfo; + if ((user == null) && (userInfo != null)) { + decodedUserInfo = user = decode(userInfo); + } + return user; } /** @@ -1307,9 +1320,11 @@ * or {@code null} if the path is undefined */ public String getPath() { - if ((decodedPath == null) && (path != null)) - decodedPath = decode(path); - return decodedPath; + String decoded = decodedPath; + if ((decoded == null) && (path != null)) { + decodedPath = decoded = decode(path); + } + return decoded; } /** @@ -1336,9 +1351,11 @@ * or {@code null} if the query is undefined */ public String getQuery() { - if ((decodedQuery == null) && (query != null)) - decodedQuery = decode(query, false); - return decodedQuery; + String decoded = decodedQuery; + if ((decoded == null) && (query != null)) { + decodedQuery = decoded = decode(query, false); + } + return decoded; } /** @@ -1365,9 +1382,11 @@ * or {@code null} if the fragment is undefined */ public String getFragment() { - if ((decodedFragment == null) && (fragment != null)) - decodedFragment = decode(fragment, false); - return decodedFragment; + String decoded = decodedFragment; + if ((decoded == null) && (fragment != null)) { + decodedFragment = decoded = decode(fragment, false); + } + return decoded; } @@ -1453,24 +1472,27 @@ * @return A hash-code value for this URI */ public int hashCode() { - if (hash != 0) - return hash; - int h = hashIgnoringCase(0, scheme); - h = hash(h, fragment); - if (isOpaque()) { - h = hash(h, schemeSpecificPart); - } else { - h = hash(h, path); - h = hash(h, query); - if (host != null) { - h = hash(h, userInfo); - h = hashIgnoringCase(h, host); - h += 1949 * port; + int h = hash; + if (h == 0) { + h = hashIgnoringCase(0, scheme); + h = hash(h, fragment); + if (isOpaque()) { + h = hash(h, schemeSpecificPart); } else { - h = hash(h, authority); + h = hash(h, path); + h = hash(h, query); + if (host != null) { + h = hash(h, userInfo); + h = hashIgnoringCase(h, host); + h += 1949 * port; + } else { + h = hash(h, authority); + } + } + if (h != 0) { + hash = h; } } - hash = h; return h; } @@ -1600,8 +1622,59 @@ * @return The string form of this URI */ public String toString() { - defineString(); - return string; + String s = string; + if (s == null) { + s = defineString(); + } + return s; + } + + private String defineString() { + String s = string; + if (s != null) { + return s; + } + + StringBuilder sb = new StringBuilder(); + if (scheme != null) { + sb.append(scheme); + sb.append(':'); + } + if (isOpaque()) { + sb.append(schemeSpecificPart); + } else { + if (host != null) { + sb.append("//"); + if (userInfo != null) { + sb.append(userInfo); + sb.append('@'); + } + boolean needBrackets = ((host.indexOf(':') >= 0) + && !host.startsWith("[") + && !host.endsWith("]")); + if (needBrackets) sb.append('['); + sb.append(host); + if (needBrackets) sb.append(']'); + if (port != -1) { + sb.append(':'); + sb.append(port); + } + } else if (authority != null) { + sb.append("//"); + sb.append(authority); + } + if (path != null) + sb.append(path); + if (query != null) { + sb.append('?'); + sb.append(query); + } + } + if (fragment != null) { + sb.append('#'); + sb.append(fragment); + } + return string = sb.toString(); } /** @@ -1618,8 +1691,7 @@ * charset */ public String toASCIIString() { - defineString(); - return encode(string); + return encode(toString()); } @@ -1825,7 +1897,7 @@ } } - private void appendAuthority(StringBuffer sb, + private void appendAuthority(StringBuilder sb, String authority, String userInfo, String host, @@ -1875,7 +1947,7 @@ } } - private void appendSchemeSpecificPart(StringBuffer sb, + private void appendSchemeSpecificPart(StringBuilder sb, String opaquePart, String authority, String userInfo, @@ -1916,7 +1988,7 @@ } } - private void appendFragment(StringBuffer sb, String fragment) { + private void appendFragment(StringBuilder sb, String fragment) { if (fragment != null) { sb.append('#'); sb.append(quote(fragment, L_URIC, H_URIC)); @@ -1933,7 +2005,7 @@ String query, String fragment) { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); if (scheme != null) { sb.append(scheme); sb.append(':'); @@ -1945,61 +2017,6 @@ return sb.toString(); } - private void defineSchemeSpecificPart() { - if (schemeSpecificPart != null) return; - StringBuffer sb = new StringBuffer(); - appendSchemeSpecificPart(sb, null, getAuthority(), getUserInfo(), - host, port, getPath(), getQuery()); - if (sb.length() == 0) return; - schemeSpecificPart = sb.toString(); - } - - private void defineString() { - if (string != null) return; - - StringBuilder sb = new StringBuilder(); - if (scheme != null) { - sb.append(scheme); - sb.append(':'); - } - if (isOpaque()) { - sb.append(schemeSpecificPart); - } else { - if (host != null) { - sb.append("//"); - if (userInfo != null) { - sb.append(userInfo); - sb.append('@'); - } - boolean needBrackets = ((host.indexOf(':') >= 0) - && !host.startsWith("[") - && !host.endsWith("]")); - if (needBrackets) sb.append('['); - sb.append(host); - if (needBrackets) sb.append(']'); - if (port != -1) { - sb.append(':'); - sb.append(port); - } - } else if (authority != null) { - sb.append("//"); - sb.append(authority); - } - if (path != null) - sb.append(path); - if (query != null) { - sb.append('?'); - sb.append(query); - } - } - if (fragment != null) { - sb.append('#'); - sb.append(fragment); - } - string = sb.toString(); - } - - // -- Normalization, resolution, and relativization -- // RFC2396 5.2 (6) @@ -2650,13 +2667,13 @@ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; - private static void appendEscape(StringBuffer sb, byte b) { + private static void appendEscape(StringBuilder sb, byte b) { sb.append('%'); sb.append(hexDigits[(b >> 4) & 0x0f]); sb.append(hexDigits[(b >> 0) & 0x0f]); } - private static void appendEncoded(StringBuffer sb, char c) { + private static void appendEncoded(StringBuilder sb, char c) { ByteBuffer bb = null; try { bb = ThreadLocalCoders.encoderFor("UTF-8") @@ -2677,15 +2694,14 @@ // by the given mask pair // private static String quote(String s, long lowMask, long highMask) { - int n = s.length(); - StringBuffer sb = null; + StringBuilder sb = null; boolean allowNonASCII = ((lowMask & L_ESCAPED) != 0); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (c < '\u0080') { if (!match(c, lowMask, highMask)) { if (sb == null) { - sb = new StringBuffer(); + sb = new StringBuilder(); sb.append(s, 0, i); } appendEscape(sb, (byte)c); @@ -2697,7 +2713,7 @@ && (Character.isSpaceChar(c) || Character.isISOControl(c))) { if (sb == null) { - sb = new StringBuffer(); + sb = new StringBuilder(); sb.append(s, 0, i); } appendEncoded(sb, c); @@ -2734,7 +2750,7 @@ assert false; } - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); while (bb.hasRemaining()) { int b = bb.get() & 0xff; if (b >= 0x80) @@ -2865,12 +2881,6 @@ fail("Expected " + expected, p); } - private void failExpecting(String expected, String prior, int p) - throws URISyntaxException - { - fail("Expected " + expected + " following " + prior, p); - } - // -- Simple access to the input string --
--- a/jdk/src/java.base/share/classes/java/net/URL.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/net/URL.java Thu Dec 24 10:34:31 2015 -0800 @@ -310,7 +310,8 @@ * @param host the name of the host. * @param port the port number on the host. * @param file the file on the host - * @exception MalformedURLException if an unknown protocol is specified. + * @exception MalformedURLException if an unknown protocol or the port + * is a negative number other than -1 * @see java.lang.System#getProperty(java.lang.String) * @see java.net.URL#setURLStreamHandlerFactory( * java.net.URLStreamHandlerFactory) @@ -329,9 +330,9 @@ * name, {@code host} name, and {@code file} name. The * default port for the specified protocol is used. * <p> - * This method is equivalent to calling the four-argument - * constructor with the arguments being {@code protocol}, - * {@code host}, {@code -1}, and {@code file}. + * This constructor is equivalent to the four-argument + * constructor with the only difference of using the + * default port for the specified protocol. * * No validation of the inputs is performed by this constructor. * @@ -372,7 +373,8 @@ * @param port the port number on the host. * @param file the file on the host * @param handler the stream handler for the URL. - * @exception MalformedURLException if an unknown protocol is specified. + * @exception MalformedURLException if an unknown protocol or the port + is a negative number other than -1 * @exception SecurityException * if a security manager exists and its * {@code checkPermission} method doesn't allow @@ -446,7 +448,9 @@ * * @param spec the {@code String} to parse as a URL. * @exception MalformedURLException if no protocol is specified, or an - * unknown protocol is found, or {@code spec} is {@code null}. + * unknown protocol is found, or {@code spec} is {@code null}, + * or the parsed URL fails to comply with the specific syntax + * of the associated protocol. * @see java.net.URL#URL(java.net.URL, java.lang.String) */ public URL(String spec) throws MalformedURLException { @@ -493,7 +497,9 @@ * @param context the context in which to parse the specification. * @param spec the {@code String} to parse as a URL. * @exception MalformedURLException if no protocol is specified, or an - * unknown protocol is found, or {@code spec} is {@code null}. + * unknown protocol is found, or {@code spec} is {@code null}, + * or the parsed URL fails to comply with the specific syntax + * of the associated protocol. * @see java.net.URL#URL(java.lang.String, java.lang.String, * int, java.lang.String) * @see java.net.URLStreamHandler @@ -513,7 +519,9 @@ * @param spec the {@code String} to parse as a URL. * @param handler the stream handler for the URL. * @exception MalformedURLException if no protocol is specified, or an - * unknown protocol is found, or {@code spec} is {@code null}. + * unknown protocol is found, or {@code spec} is {@code null}, + * or the parsed URL fails to comply with the specific syntax + * of the associated protocol. * @exception SecurityException * if a security manager exists and its * {@code checkPermission} method doesn't allow
--- a/jdk/src/java.base/share/classes/java/nio/Bits.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/nio/Bits.java Thu Dec 24 10:34:31 2015 -0800 @@ -25,9 +25,7 @@ package java.nio; -import java.security.AccessController; import java.util.concurrent.atomic.AtomicLong; -import java.util.concurrent.atomic.LongAdder; import jdk.internal.misc.JavaNioAccess; import jdk.internal.misc.JavaLangRefAccess; @@ -603,7 +601,8 @@ private static final AtomicLong reservedMemory = new AtomicLong(); private static final AtomicLong totalCapacity = new AtomicLong(); private static final AtomicLong count = new AtomicLong(); - private static volatile boolean memoryLimitSet = false; + private static volatile boolean memoryLimitSet; + // max. number of sleeps during try-reserving with exponentially // increasing delay before throwing OutOfMemoryError: // 1, 2, 4, 8, 16, 32, 64, 128, 256 (total 511 ms ~ 0.5 s)
--- a/jdk/src/java.base/share/classes/java/nio/channels/SelectionKey.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/nio/channels/SelectionKey.java Thu Dec 24 10:34:31 2015 -0800 @@ -26,8 +26,6 @@ package java.nio.channels; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; -import java.io.IOException; - /** * A token representing the registration of a {@link SelectableChannel} with a @@ -363,7 +361,7 @@ // -- Attachments -- - private volatile Object attachment = null; + private volatile Object attachment; private static final AtomicReferenceFieldUpdater<SelectionKey,Object> attachmentUpdater = AtomicReferenceFieldUpdater.newUpdater(
--- a/jdk/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/nio/channels/spi/AbstractInterruptibleChannel.java Thu Dec 24 10:34:31 2015 -0800 @@ -29,11 +29,7 @@ package java.nio.channels.spi; import java.io.IOException; -import java.lang.reflect.Method; -import java.lang.reflect.InvocationTargetException; import java.nio.channels.*; -import java.security.AccessController; -import java.security.PrivilegedAction; import jdk.internal.misc.SharedSecrets; import sun.nio.ch.Interruptible; @@ -90,7 +86,7 @@ { private final Object closeLock = new Object(); - private volatile boolean open = true; + private volatile boolean closed; /** * Initializes a new instance of this class. @@ -110,9 +106,9 @@ */ public final void close() throws IOException { synchronized (closeLock) { - if (!open) + if (closed) return; - open = false; + closed = true; implCloseChannel(); } } @@ -136,7 +132,7 @@ protected abstract void implCloseChannel() throws IOException; public final boolean isOpen() { - return open; + return !closed; } @@ -158,9 +154,9 @@ interruptor = new Interruptible() { public void interrupt(Thread target) { synchronized (closeLock) { - if (!open) + if (closed) return; - open = false; + closed = true; interrupted = target; try { AbstractInterruptibleChannel.this.implCloseChannel(); @@ -202,7 +198,7 @@ this.interrupted = null; throw new ClosedByInterruptException(); } - if (!completed && !open) + if (!completed && closed) throw new AsynchronousCloseException(); }
--- a/jdk/src/java.base/share/classes/java/nio/charset/Charset.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/nio/charset/Charset.java Thu Dec 24 10:34:31 2015 -0800 @@ -276,7 +276,7 @@ /* -- Static methods -- */ - private static volatile String bugLevel = null; + private static volatile String bugLevel; static boolean atBugLevel(String bl) { // package-private String level = bugLevel; @@ -324,8 +324,8 @@ // Cache of the most-recently-returned charsets, // along with the names that were used to find them // - private static volatile Object[] cache1 = null; // "Level 1" cache - private static volatile Object[] cache2 = null; // "Level 2" cache + private static volatile Object[] cache1; // "Level 1" cache + private static volatile Object[] cache2; // "Level 2" cache private static void cache(String charsetName, Charset cs) { cache2 = cache1;
--- a/jdk/src/java.base/share/classes/java/security/SecureRandom.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/security/SecureRandom.java Thu Dec 24 10:34:31 2015 -0800 @@ -124,7 +124,7 @@ private String algorithm; // Seed Generator - private static volatile SecureRandom seedGenerator = null; + private static volatile SecureRandom seedGenerator; /** * Constructs a secure random number generator (RNG) implementing the @@ -522,10 +522,12 @@ * @see #setSeed */ public static byte[] getSeed(int numBytes) { - if (seedGenerator == null) { - seedGenerator = new SecureRandom(); + SecureRandom seedGen = seedGenerator; + if (seedGen == null) { + seedGen = new SecureRandom(); + seedGenerator = seedGen; } - return seedGenerator.generateSeed(numBytes); + return seedGen.generateSeed(numBytes); } /**
--- a/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/text/DateFormatSymbols.java Thu Dec 24 10:34:31 2015 -0800 @@ -630,7 +630,9 @@ hashCode = 11 * hashCode + Arrays.hashCode(ampms); hashCode = 11 * hashCode + Arrays.deepHashCode(getZoneStringsWrapper()); hashCode = 11 * hashCode + Objects.hashCode(localPatternChars); - cachedHashCode = hashCode; + if (hashCode != 0) { + cachedHashCode = hashCode; + } } return hashCode; @@ -670,12 +672,12 @@ private static final ConcurrentMap<Locale, SoftReference<DateFormatSymbols>> cachedInstances = new ConcurrentHashMap<>(3); - private transient int lastZoneIndex = 0; + private transient int lastZoneIndex; /** * Cached hash code */ - transient volatile int cachedHashCode = 0; + transient volatile int cachedHashCode; private void initializeData(Locale desiredLocale) { locale = desiredLocale;
--- a/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/text/DecimalFormatSymbols.java Thu Dec 24 10:34:31 2015 -0800 @@ -42,14 +42,8 @@ import java.io.ObjectInputStream; import java.io.Serializable; import java.text.spi.DecimalFormatSymbolsProvider; -import java.util.ArrayList; import java.util.Currency; -import java.util.List; import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleServiceProviderPool; import sun.util.locale.provider.ResourceBundleBasedAdapter; @@ -875,7 +869,7 @@ // currency; only the ISO code is serialized. private transient Currency currency; - private transient volatile boolean currencyInitialized = false; + private transient volatile boolean currencyInitialized; // Proclaim JDK 1.1 FCS compatibility static final long serialVersionUID = 5772796243397350300L;
--- a/jdk/src/java.base/share/classes/java/text/DigitList.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/text/DigitList.java Thu Dec 24 10:34:31 2015 -0800 @@ -41,7 +41,7 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; -import sun.misc.FloatingDecimal; +import jdk.internal.math.FloatingDecimal; /** * Digit List. Private to DecimalFormat.
--- a/jdk/src/java.base/share/classes/java/time/LocalDate.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/time/LocalDate.java Thu Dec 24 10:34:31 2015 -0800 @@ -147,6 +147,10 @@ * This could be used by an application as a "far future" date. */ public static final LocalDate MAX = LocalDate.of(Year.MAX_VALUE, 12, 31); + /** + * The epoch year {@code LocalDate}, '1970-01-01'. + */ + public static final LocalDate EPOCH = LocalDate.of(1970, 1, 1); /** * Serialization version. @@ -1864,6 +1868,29 @@ return total - DAYS_0000_TO_1970; } + /** + * Converts this {@code LocalDate} to the number of seconds since the epoch + * of 1970-01-01T00:00:00Z. + * <p> + * This combines this local date with the specified time and + * offset to calculate the epoch-second value, which is the + * number of elapsed seconds from 1970-01-01T00:00:00Z. + * Instants on the time-line after the epoch are positive, earlier + * are negative. + * + * @param time the local time, not null + * @param offset the zone offset, not null + * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative + * @since 9 + */ + public long toEpochSecond(LocalTime time, ZoneOffset offset) { + Objects.requireNonNull(time, "time"); + Objects.requireNonNull(offset, "offset"); + long secs = toEpochDay() * SECONDS_PER_DAY + time.toSecondOfDay(); + secs -= offset.getTotalSeconds(); + return secs; + } + //----------------------------------------------------------------------- /** * Compares this date to another date.
--- a/jdk/src/java.base/share/classes/java/time/LocalTime.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/time/LocalTime.java Thu Dec 24 10:34:31 2015 -0800 @@ -1490,6 +1490,30 @@ return total; } + /** + * Converts this {@code LocalTime} to the number of seconds since the epoch + * of 1970-01-01T00:00:00Z. + * <p> + * This combines this local time with the specified date and + * offset to calculate the epoch-second value, which is the + * number of elapsed seconds from 1970-01-01T00:00:00Z. + * Instants on the time-line after the epoch are positive, earlier + * are negative. + * + * @param date the local date, not null + * @param offset the zone offset, not null + * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative + * @since 9 + */ + public long toEpochSecond(LocalDate date, ZoneOffset offset) { + Objects.requireNonNull(date, "date"); + Objects.requireNonNull(offset, "offset"); + long epochDay = date.toEpochDay(); + long secs = epochDay * 86400 + toSecondOfDay(); + secs -= offset.getTotalSeconds(); + return secs; + } + //----------------------------------------------------------------------- /** * Compares this time to another time.
--- a/jdk/src/java.base/share/classes/java/time/OffsetTime.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/time/OffsetTime.java Thu Dec 24 10:34:31 2015 -0800 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1232,6 +1232,28 @@ return nod - offsetNanos; } + /** + * Converts this {@code OffsetTime} to the number of seconds since the epoch + * of 1970-01-01T00:00:00Z. + * <p> + * This combines this offset time with the specified date to calculate the + * epoch-second value, which is the number of elapsed seconds from + * 1970-01-01T00:00:00Z. + * Instants on the time-line after the epoch are positive, earlier + * are negative. + * + * @param date the localdate, not null + * @return the number of seconds since the epoch of 1970-01-01T00:00:00Z, may be negative + * @since 9 + */ + public long toEpochSecond(LocalDate date) { + Objects.requireNonNull(date, "date"); + long epochDay = date.toEpochDay(); + long secs = epochDay * 86400 + time.toSecondOfDay(); + secs -= offset.getTotalSeconds(); + return secs; + } + //----------------------------------------------------------------------- /** * Compares this {@code OffsetTime} to another time.
--- a/jdk/src/java.base/share/classes/java/util/Formatter.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/util/Formatter.java Thu Dec 24 10:34:31 2015 -0800 @@ -60,8 +60,8 @@ import java.time.temporal.TemporalQueries; import java.time.temporal.UnsupportedTemporalTypeException; -import sun.misc.DoubleConsts; -import sun.misc.FormattedFloatingDecimal; +import jdk.internal.math.DoubleConsts; +import jdk.internal.math.FormattedFloatingDecimal; /** * An interpreter for printf-style format strings. This class provides support
--- a/jdk/src/java.base/share/classes/java/util/Locale.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/util/Locale.java Thu Dec 24 10:34:31 2015 -0800 @@ -62,7 +62,6 @@ import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.locale.provider.LocaleResources; import sun.util.locale.provider.LocaleServiceProviderPool; -import sun.util.locale.provider.ResourceBundleBasedAdapter; /** * A <code>Locale</code> object represents a specific geographical, political, @@ -2016,11 +2015,11 @@ /** * Calculated hashcode */ - private transient volatile int hashCodeValue = 0; + private transient volatile int hashCodeValue; private static volatile Locale defaultLocale = initDefault(); - private static volatile Locale defaultDisplayLocale = null; - private static volatile Locale defaultFormatLocale = null; + private static volatile Locale defaultDisplayLocale; + private static volatile Locale defaultFormatLocale; private transient volatile String languageTag; @@ -2207,9 +2206,9 @@ baseLocale.getRegion(), baseLocale.getVariant(), localeExtensions); } - private static volatile String[] isoLanguages = null; + private static volatile String[] isoLanguages; - private static volatile String[] isoCountries = null; + private static volatile String[] isoCountries; private static String convertOldISOCodes(String language) { // we accept both the old and the new ISO codes for the languages whose ISO @@ -2851,7 +2850,7 @@ private final String range; private final double weight; - private volatile int hash = 0; + private volatile int hash; /** * Constructs a {@code LanguageRange} using the given {@code range}. @@ -3108,14 +3107,17 @@ */ @Override public int hashCode() { - if (hash == 0) { - int result = 17; - result = 37*result + range.hashCode(); + int h = hash; + if (h == 0) { + h = 17; + h = 37*h + range.hashCode(); long bitsWeight = Double.doubleToLongBits(weight); - result = 37*result + (int)(bitsWeight ^ (bitsWeight >>> 32)); - hash = result; + h = 37*h + (int)(bitsWeight ^ (bitsWeight >>> 32)); + if (h != 0) { + hash = h; + } } - return hash; + return h; } /**
--- a/jdk/src/java.base/share/classes/java/util/regex/Pattern.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/util/regex/Pattern.java Thu Dec 24 10:34:31 2015 -0800 @@ -950,7 +950,7 @@ * Boolean indicating this Pattern is compiled; this is necessary in order * to lazily compile deserialized Patterns. */ - private transient volatile boolean compiled = false; + private transient volatile boolean compiled; /** * The normalized pattern string. @@ -1332,7 +1332,6 @@ localCount = 0; // if length > 0, the Pattern is lazily compiled - compiled = false; if (pattern.length() == 0) { root = new Start(lastAccept); matchRoot = lastAccept; @@ -1377,7 +1376,6 @@ * equivalences of the characters. */ private void normalize() { - boolean inCharClass = false; int lastCodePoint = -1; // Convert pattern into normalized form @@ -1551,7 +1549,6 @@ // offset maintains the index in code units. loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) { len = countChars(input, offset, 1); - boolean skip = false; for(int y=x-1; y>=0; y--) { if (combClass[y] == combClass[x]) { continue loop; @@ -1566,8 +1563,7 @@ temp[index++] = prefix + sre; } String[] result = new String[index]; - for (int x=0; x<index; x++) - result[x] = temp[x]; + System.arraycopy(temp, 0, result, 0, index); return result; } @@ -1742,9 +1738,11 @@ } Map<String, Integer> namedGroups() { - if (namedGroups == null) - namedGroups = new HashMap<>(2); - return namedGroups; + Map<String, Integer> groups = namedGroups; + if (groups == null) { + namedGroups = groups = new HashMap<>(2); + } + return groups; } /**
--- a/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/java/util/zip/ZipFile.java Thu Dec 24 10:34:31 2015 -0800 @@ -72,7 +72,7 @@ class ZipFile implements ZipConstants, Closeable { private final String name; // zip file name - private volatile boolean closeRequested = false; + private volatile boolean closeRequested; private Source zsrc; private ZipCoder zc; @@ -366,7 +366,7 @@ } private class ZipFileInflaterInputStream extends InflaterInputStream { - private volatile boolean closeRequested = false; + private volatile boolean closeRequested; private boolean eof = false; private final ZipFileInputStream zfin; @@ -653,7 +653,7 @@ * (possibly compressed) zip file entry. */ private class ZipFileInputStream extends InputStream { - private volatile boolean closeRequested = false; + private volatile boolean closeRequested; private long pos; // current position within entry data protected long rem; // number of remaining bytes within entry protected long size; // uncompressed size of this entry
--- a/jdk/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/jdk/internal/logger/LazyLoggers.java Thu Dec 24 10:34:31 2015 -0800 @@ -326,20 +326,22 @@ } // Do not expose this outside of this package. - private static volatile LoggerFinder provider = null; + private static volatile LoggerFinder provider; private static LoggerFinder accessLoggerFinder() { - if (provider == null) { + LoggerFinder prov = provider; + if (prov == null) { // no need to lock: it doesn't matter if we call // getLoggerFinder() twice - since LoggerFinder already caches // the result. // This is just an optimization to avoid the cost of calling // doPrivileged every time. final SecurityManager sm = System.getSecurityManager(); - provider = sm == null ? LoggerFinder.getLoggerFinder() : + prov = sm == null ? LoggerFinder.getLoggerFinder() : AccessController.doPrivileged( (PrivilegedAction<LoggerFinder>)LoggerFinder::getLoggerFinder); + provider = prov; } - return provider; + return prov; } // Avoid using lambda here as lazy loggers could be created early
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/math/DoubleConsts.java Thu Dec 24 10:34:31 2015 -0800 @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.math; + +/** + * This class contains additional constants documenting limits of the + * <code>double</code> type. + * + * @author Joseph D. Darcy + */ + +public class DoubleConsts { + /** + * Don't let anyone instantiate this class. + */ + private DoubleConsts() {} + + public static final double POSITIVE_INFINITY = java.lang.Double.POSITIVE_INFINITY; + public static final double NEGATIVE_INFINITY = java.lang.Double.NEGATIVE_INFINITY; + public static final double NaN = java.lang.Double.NaN; + public static final double MAX_VALUE = java.lang.Double.MAX_VALUE; + public static final double MIN_VALUE = java.lang.Double.MIN_VALUE; + + /** + * A constant holding the smallest positive normal value of type + * <code>double</code>, 2<sup>-1022</sup>. It is equal to the + * value returned by + * <code>Double.longBitsToDouble(0x0010000000000000L)</code>. + * + * @since 1.5 + */ + public static final double MIN_NORMAL = 2.2250738585072014E-308; + + + /** + * The number of logical bits in the significand of a + * <code>double</code> number, including the implicit bit. + */ + public static final int SIGNIFICAND_WIDTH = 53; + + /** + * Maximum exponent a finite <code>double</code> number may have. + * It is equal to the value returned by + * <code>Math.ilogb(Double.MAX_VALUE)</code>. + */ + public static final int MAX_EXPONENT = 1023; + + /** + * Minimum exponent a normalized <code>double</code> number may + * have. It is equal to the value returned by + * <code>Math.ilogb(Double.MIN_NORMAL)</code>. + */ + public static final int MIN_EXPONENT = -1022; + + /** + * The exponent the smallest positive <code>double</code> + * subnormal value would have if it could be normalized.. + */ + public static final int MIN_SUB_EXPONENT = MIN_EXPONENT - + (SIGNIFICAND_WIDTH - 1); + + /** + * Bias used in representing a <code>double</code> exponent. + */ + public static final int EXP_BIAS = 1023; + + /** + * Bit mask to isolate the sign bit of a <code>double</code>. + */ + public static final long SIGN_BIT_MASK = 0x8000000000000000L; + + /** + * Bit mask to isolate the exponent field of a + * <code>double</code>. + */ + public static final long EXP_BIT_MASK = 0x7FF0000000000000L; + + /** + * Bit mask to isolate the significand field of a + * <code>double</code>. + */ + public static final long SIGNIF_BIT_MASK = 0x000FFFFFFFFFFFFFL; + + static { + // verify bit masks cover all bit positions and that the bit + // masks are non-overlapping + assert(((SIGN_BIT_MASK | EXP_BIT_MASK | SIGNIF_BIT_MASK) == ~0L) && + (((SIGN_BIT_MASK & EXP_BIT_MASK) == 0L) && + ((SIGN_BIT_MASK & SIGNIF_BIT_MASK) == 0L) && + ((EXP_BIT_MASK & SIGNIF_BIT_MASK) == 0L))); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/math/FDBigInteger.java Thu Dec 24 10:34:31 2015 -0800 @@ -0,0 +1,1508 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.internal.math; + +import java.math.BigInteger; +import java.util.Arrays; +//@ model import org.jmlspecs.models.JMLMath; + +/** + * A simple big integer package specifically for floating point base conversion. + */ +public /*@ spec_bigint_math @*/ class FDBigInteger { + + // + // This class contains many comments that start with "/*@" mark. + // They are behavourial specification in + // the Java Modelling Language (JML): + // http://www.eecs.ucf.edu/~leavens/JML//index.shtml + // + + /*@ + @ public pure model static \bigint UNSIGNED(int v) { + @ return v >= 0 ? v : v + (((\bigint)1) << 32); + @ } + @ + @ public pure model static \bigint UNSIGNED(long v) { + @ return v >= 0 ? v : v + (((\bigint)1) << 64); + @ } + @ + @ public pure model static \bigint AP(int[] data, int len) { + @ return (\sum int i; 0 <= 0 && i < len; UNSIGNED(data[i]) << (i*32)); + @ } + @ + @ public pure model static \bigint pow52(int p5, int p2) { + @ ghost \bigint v = 1; + @ for (int i = 0; i < p5; i++) v *= 5; + @ return v << p2; + @ } + @ + @ public pure model static \bigint pow10(int p10) { + @ return pow52(p10, p10); + @ } + @*/ + + static final int[] SMALL_5_POW = { + 1, + 5, + 5 * 5, + 5 * 5 * 5, + 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 + }; + + static final long[] LONG_5_POW = { + 1L, + 5L, + 5L * 5, + 5L * 5 * 5, + 5L * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, + }; + + // Maximum size of cache of powers of 5 as FDBigIntegers. + private static final int MAX_FIVE_POW = 340; + + // Cache of big powers of 5 as FDBigIntegers. + private static final FDBigInteger POW_5_CACHE[]; + + // Initialize FDBigInteger cache of powers of 5. + static { + POW_5_CACHE = new FDBigInteger[MAX_FIVE_POW]; + int i = 0; + while (i < SMALL_5_POW.length) { + FDBigInteger pow5 = new FDBigInteger(new int[]{SMALL_5_POW[i]}, 0); + pow5.makeImmutable(); + POW_5_CACHE[i] = pow5; + i++; + } + FDBigInteger prev = POW_5_CACHE[i - 1]; + while (i < MAX_FIVE_POW) { + POW_5_CACHE[i] = prev = prev.mult(5); + prev.makeImmutable(); + i++; + } + } + + // Zero as an FDBigInteger. + public static final FDBigInteger ZERO = new FDBigInteger(new int[0], 0); + + // Ensure ZERO is immutable. + static { + ZERO.makeImmutable(); + } + + // Constant for casting an int to a long via bitwise AND. + private static final long LONG_MASK = 0xffffffffL; + + //@ spec_public non_null; + private int data[]; // value: data[0] is least significant + //@ spec_public; + private int offset; // number of least significant zero padding ints + //@ spec_public; + private int nWords; // data[nWords-1]!=0, all values above are zero + // if nWords==0 -> this FDBigInteger is zero + //@ spec_public; + private boolean isImmutable = false; + + /*@ + @ public invariant 0 <= nWords && nWords <= data.length && offset >= 0; + @ public invariant nWords == 0 ==> offset == 0; + @ public invariant nWords > 0 ==> data[nWords - 1] != 0; + @ public invariant (\forall int i; nWords <= i && i < data.length; data[i] == 0); + @ public pure model \bigint value() { + @ return AP(data, nWords) << (offset*32); + @ } + @*/ + + /** + * Constructs an <code>FDBigInteger</code> from data and padding. The + * <code>data</code> parameter has the least significant <code>int</code> at + * the zeroth index. The <code>offset</code> parameter gives the number of + * zero <code>int</code>s to be inferred below the least significant element + * of <code>data</code>. + * + * @param data An array containing all non-zero <code>int</code>s of the value. + * @param offset An offset indicating the number of zero <code>int</code>s to pad + * below the least significant element of <code>data</code>. + */ + /*@ + @ requires data != null && offset >= 0; + @ ensures this.value() == \old(AP(data, data.length) << (offset*32)); + @ ensures this.data == \old(data); + @*/ + private FDBigInteger(int[] data, int offset) { + this.data = data; + this.offset = offset; + this.nWords = data.length; + trimLeadingZeros(); + } + + /** + * Constructs an <code>FDBigInteger</code> from a starting value and some + * decimal digits. + * + * @param lValue The starting value. + * @param digits The decimal digits. + * @param kDigits The initial index into <code>digits</code>. + * @param nDigits The final index into <code>digits</code>. + */ + /*@ + @ requires digits != null; + @ requires 0 <= kDigits && kDigits <= nDigits && nDigits <= digits.length; + @ requires (\forall int i; 0 <= i && i < nDigits; '0' <= digits[i] && digits[i] <= '9'); + @ ensures this.value() == \old(lValue * pow10(nDigits - kDigits) + (\sum int i; kDigits <= i && i < nDigits; (digits[i] - '0') * pow10(nDigits - i - 1))); + @*/ + public FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) { + int n = Math.max((nDigits + 8) / 9, 2); // estimate size needed. + data = new int[n]; // allocate enough space + data[0] = (int) lValue; // starting value + data[1] = (int) (lValue >>> 32); + offset = 0; + nWords = 2; + int i = kDigits; + int limit = nDigits - 5; // slurp digits 5 at a time. + int v; + while (i < limit) { + int ilim = i + 5; + v = (int) digits[i++] - (int) '0'; + while (i < ilim) { + v = 10 * v + (int) digits[i++] - (int) '0'; + } + multAddMe(100000, v); // ... where 100000 is 10^5. + } + int factor = 1; + v = 0; + while (i < nDigits) { + v = 10 * v + (int) digits[i++] - (int) '0'; + factor *= 10; + } + if (factor != 1) { + multAddMe(factor, v); + } + trimLeadingZeros(); + } + + /** + * Returns an <code>FDBigInteger</code> with the numerical value + * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. + * + * @param p5 The exponent of the power-of-five factor. + * @param p2 The exponent of the power-of-two factor. + * @return <code>5<sup>p5</sup> * 2<sup>p2</sup></code> + */ + /*@ + @ requires p5 >= 0 && p2 >= 0; + @ assignable \nothing; + @ ensures \result.value() == \old(pow52(p5, p2)); + @*/ + public static FDBigInteger valueOfPow52(int p5, int p2) { + if (p5 != 0) { + if (p2 == 0) { + return big5pow(p5); + } else if (p5 < SMALL_5_POW.length) { + int pow5 = SMALL_5_POW[p5]; + int wordcount = p2 >> 5; + int bitcount = p2 & 0x1f; + if (bitcount == 0) { + return new FDBigInteger(new int[]{pow5}, wordcount); + } else { + return new FDBigInteger(new int[]{ + pow5 << bitcount, + pow5 >>> (32 - bitcount) + }, wordcount); + } + } else { + return big5pow(p5).leftShift(p2); + } + } else { + return valueOfPow2(p2); + } + } + + /** + * Returns an <code>FDBigInteger</code> with the numerical value + * <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code>. + * + * @param value The constant factor. + * @param p5 The exponent of the power-of-five factor. + * @param p2 The exponent of the power-of-two factor. + * @return <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code> + */ + /*@ + @ requires p5 >= 0 && p2 >= 0; + @ assignable \nothing; + @ ensures \result.value() == \old(UNSIGNED(value) * pow52(p5, p2)); + @*/ + public static FDBigInteger valueOfMulPow52(long value, int p5, int p2) { + assert p5 >= 0 : p5; + assert p2 >= 0 : p2; + int v0 = (int) value; + int v1 = (int) (value >>> 32); + int wordcount = p2 >> 5; + int bitcount = p2 & 0x1f; + if (p5 != 0) { + if (p5 < SMALL_5_POW.length) { + long pow5 = SMALL_5_POW[p5] & LONG_MASK; + long carry = (v0 & LONG_MASK) * pow5; + v0 = (int) carry; + carry >>>= 32; + carry = (v1 & LONG_MASK) * pow5 + carry; + v1 = (int) carry; + int v2 = (int) (carry >>> 32); + if (bitcount == 0) { + return new FDBigInteger(new int[]{v0, v1, v2}, wordcount); + } else { + return new FDBigInteger(new int[]{ + v0 << bitcount, + (v1 << bitcount) | (v0 >>> (32 - bitcount)), + (v2 << bitcount) | (v1 >>> (32 - bitcount)), + v2 >>> (32 - bitcount) + }, wordcount); + } + } else { + FDBigInteger pow5 = big5pow(p5); + int[] r; + if (v1 == 0) { + r = new int[pow5.nWords + 1 + ((p2 != 0) ? 1 : 0)]; + mult(pow5.data, pow5.nWords, v0, r); + } else { + r = new int[pow5.nWords + 2 + ((p2 != 0) ? 1 : 0)]; + mult(pow5.data, pow5.nWords, v0, v1, r); + } + return (new FDBigInteger(r, pow5.offset)).leftShift(p2); + } + } else if (p2 != 0) { + if (bitcount == 0) { + return new FDBigInteger(new int[]{v0, v1}, wordcount); + } else { + return new FDBigInteger(new int[]{ + v0 << bitcount, + (v1 << bitcount) | (v0 >>> (32 - bitcount)), + v1 >>> (32 - bitcount) + }, wordcount); + } + } + return new FDBigInteger(new int[]{v0, v1}, 0); + } + + /** + * Returns an <code>FDBigInteger</code> with the numerical value + * <code>2<sup>p2</sup></code>. + * + * @param p2 The exponent of 2. + * @return <code>2<sup>p2</sup></code> + */ + /*@ + @ requires p2 >= 0; + @ assignable \nothing; + @ ensures \result.value() == pow52(0, p2); + @*/ + private static FDBigInteger valueOfPow2(int p2) { + int wordcount = p2 >> 5; + int bitcount = p2 & 0x1f; + return new FDBigInteger(new int[]{1 << bitcount}, wordcount); + } + + /** + * Removes all leading zeros from this <code>FDBigInteger</code> adjusting + * the offset and number of non-zero leading words accordingly. + */ + /*@ + @ requires data != null; + @ requires 0 <= nWords && nWords <= data.length && offset >= 0; + @ requires nWords == 0 ==> offset == 0; + @ ensures nWords == 0 ==> offset == 0; + @ ensures nWords > 0 ==> data[nWords - 1] != 0; + @*/ + private /*@ helper @*/ void trimLeadingZeros() { + int i = nWords; + if (i > 0 && (data[--i] == 0)) { + //for (; i > 0 && data[i - 1] == 0; i--) ; + while(i > 0 && data[i - 1] == 0) { + i--; + } + this.nWords = i; + if (i == 0) { // all words are zero + this.offset = 0; + } + } + } + + /** + * Retrieves the normalization bias of the <code>FDBigIntger</code>. The + * normalization bias is a left shift such that after it the highest word + * of the value will have the 4 highest bits equal to zero: + * {@code (highestWord & 0xf0000000) == 0}, but the next bit should be 1 + * {@code (highestWord & 0x08000000) != 0}. + * + * @return The normalization bias. + */ + /*@ + @ requires this.value() > 0; + @*/ + public /*@ pure @*/ int getNormalizationBias() { + if (nWords == 0) { + throw new IllegalArgumentException("Zero value cannot be normalized"); + } + int zeros = Integer.numberOfLeadingZeros(data[nWords - 1]); + return (zeros < 4) ? 28 + zeros : zeros - 4; + } + + // TODO: Why is anticount param needed if it is always 32 - bitcount? + /** + * Left shifts the contents of one int array into another. + * + * @param src The source array. + * @param idx The initial index of the source array. + * @param result The destination array. + * @param bitcount The left shift. + * @param anticount The left anti-shift, e.g., <code>32-bitcount</code>. + * @param prev The prior source value. + */ + /*@ + @ requires 0 < bitcount && bitcount < 32 && anticount == 32 - bitcount; + @ requires src.length >= idx && result.length > idx; + @ assignable result[*]; + @ ensures AP(result, \old(idx + 1)) == \old((AP(src, idx) + UNSIGNED(prev) << (idx*32)) << bitcount); + @*/ + private static void leftShift(int[] src, int idx, int result[], int bitcount, int anticount, int prev){ + for (; idx > 0; idx--) { + int v = (prev << bitcount); + prev = src[idx - 1]; + v |= (prev >>> anticount); + result[idx] = v; + } + int v = prev << bitcount; + result[0] = v; + } + + /** + * Shifts this <code>FDBigInteger</code> to the left. The shift is performed + * in-place unless the <code>FDBigInteger</code> is immutable in which case + * a new instance of <code>FDBigInteger</code> is returned. + * + * @param shift The number of bits to shift left. + * @return The shifted <code>FDBigInteger</code>. + */ + /*@ + @ requires this.value() == 0 || shift == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() > 0 && shift > 0 && this.isImmutable; + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() << shift); + @ + @ also + @ + @ requires this.value() > 0 && shift > 0 && this.isImmutable; + @ assignable \nothing; + @ ensures \result == this; + @ ensures \result.value() == \old(this.value() << shift); + @*/ + public FDBigInteger leftShift(int shift) { + if (shift == 0 || nWords == 0) { + return this; + } + int wordcount = shift >> 5; + int bitcount = shift & 0x1f; + if (this.isImmutable) { + if (bitcount == 0) { + return new FDBigInteger(Arrays.copyOf(data, nWords), offset + wordcount); + } else { + int anticount = 32 - bitcount; + int idx = nWords - 1; + int prev = data[idx]; + int hi = prev >>> anticount; + int[] result; + if (hi != 0) { + result = new int[nWords + 1]; + result[nWords] = hi; + } else { + result = new int[nWords]; + } + leftShift(data,idx,result,bitcount,anticount,prev); + return new FDBigInteger(result, offset + wordcount); + } + } else { + if (bitcount != 0) { + int anticount = 32 - bitcount; + if ((data[0] << bitcount) == 0) { + int idx = 0; + int prev = data[idx]; + for (; idx < nWords - 1; idx++) { + int v = (prev >>> anticount); + prev = data[idx + 1]; + v |= (prev << bitcount); + data[idx] = v; + } + int v = prev >>> anticount; + data[idx] = v; + if(v==0) { + nWords--; + } + offset++; + } else { + int idx = nWords - 1; + int prev = data[idx]; + int hi = prev >>> anticount; + int[] result = data; + int[] src = data; + if (hi != 0) { + if(nWords == data.length) { + data = result = new int[nWords + 1]; + } + result[nWords++] = hi; + } + leftShift(src,idx,result,bitcount,anticount,prev); + } + } + offset += wordcount; + return this; + } + } + + /** + * Returns the number of <code>int</code>s this <code>FDBigInteger</code> represents. + * + * @return Number of <code>int</code>s required to represent this <code>FDBigInteger</code>. + */ + /*@ + @ requires this.value() == 0; + @ ensures \result == 0; + @ + @ also + @ + @ requires this.value() > 0; + @ ensures ((\bigint)1) << (\result - 1) <= this.value() && this.value() <= ((\bigint)1) << \result; + @*/ + private /*@ pure @*/ int size() { + return nWords + offset; + } + + + /** + * Computes + * <pre> + * q = (int)( this / S ) + * this = 10 * ( this mod S ) + * Return q. + * </pre> + * This is the iteration step of digit development for output. + * We assume that S has been normalized, as above, and that + * "this" has been left-shifted accordingly. + * Also assumed, of course, is that the result, q, can be expressed + * as an integer, {@code 0 <= q < 10}. + * + * @param S The divisor of this <code>FDBigInteger</code>. + * @return <code>q = (int)(this / S)</code>. + */ + /*@ + @ requires !this.isImmutable; + @ requires this.size() <= S.size(); + @ requires this.data.length + this.offset >= S.size(); + @ requires S.value() >= ((\bigint)1) << (S.size()*32 - 4); + @ assignable this.nWords, this.offset, this.data, this.data[*]; + @ ensures \result == \old(this.value() / S.value()); + @ ensures this.value() == \old(10 * (this.value() % S.value())); + @*/ + public int quoRemIteration(FDBigInteger S) throws IllegalArgumentException { + assert !this.isImmutable : "cannot modify immutable value"; + // ensure that this and S have the same number of + // digits. If S is properly normalized and q < 10 then + // this must be so. + int thSize = this.size(); + int sSize = S.size(); + if (thSize < sSize) { + // this value is significantly less than S, result of division is zero. + // just mult this by 10. + int p = multAndCarryBy10(this.data, this.nWords, this.data); + if(p!=0) { + this.data[nWords++] = p; + } else { + trimLeadingZeros(); + } + return 0; + } else if (thSize > sSize) { + throw new IllegalArgumentException("disparate values"); + } + // estimate q the obvious way. We will usually be + // right. If not, then we're only off by a little and + // will re-add. + long q = (this.data[this.nWords - 1] & LONG_MASK) / (S.data[S.nWords - 1] & LONG_MASK); + long diff = multDiffMe(q, S); + if (diff != 0L) { + //@ assert q != 0; + //@ assert this.offset == \old(Math.min(this.offset, S.offset)); + //@ assert this.offset <= S.offset; + + // q is too big. + // add S back in until this turns +. This should + // not be very many times! + long sum = 0L; + int tStart = S.offset - this.offset; + //@ assert tStart >= 0; + int[] sd = S.data; + int[] td = this.data; + while (sum == 0L) { + for (int sIndex = 0, tIndex = tStart; tIndex < this.nWords; sIndex++, tIndex++) { + sum += (td[tIndex] & LONG_MASK) + (sd[sIndex] & LONG_MASK); + td[tIndex] = (int) sum; + sum >>>= 32; // Signed or unsigned, answer is 0 or 1 + } + // + // Originally the following line read + // "if ( sum !=0 && sum != -1 )" + // but that would be wrong, because of the + // treatment of the two values as entirely unsigned, + // it would be impossible for a carry-out to be interpreted + // as -1 -- it would have to be a single-bit carry-out, or +1. + // + assert sum == 0 || sum == 1 : sum; // carry out of division correction + q -= 1; + } + } + // finally, we can multiply this by 10. + // it cannot overflow, right, as the high-order word has + // at least 4 high-order zeros! + int p = multAndCarryBy10(this.data, this.nWords, this.data); + assert p == 0 : p; // Carry out of *10 + trimLeadingZeros(); + return (int) q; + } + + /** + * Multiplies this <code>FDBigInteger</code> by 10. The operation will be + * performed in place unless the <code>FDBigInteger</code> is immutable in + * which case a new <code>FDBigInteger</code> will be returned. + * + * @return The <code>FDBigInteger</code> multiplied by 10. + */ + /*@ + @ requires this.value() == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() > 0 && this.isImmutable; + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() * 10); + @ + @ also + @ + @ requires this.value() > 0 && !this.isImmutable; + @ assignable this.nWords, this.data, this.data[*]; + @ ensures \result == this; + @ ensures \result.value() == \old(this.value() * 10); + @*/ + public FDBigInteger multBy10() { + if (nWords == 0) { + return this; + } + if (isImmutable) { + int[] res = new int[nWords + 1]; + res[nWords] = multAndCarryBy10(data, nWords, res); + return new FDBigInteger(res, offset); + } else { + int p = multAndCarryBy10(this.data, this.nWords, this.data); + if (p != 0) { + if (nWords == data.length) { + if (data[0] == 0) { + System.arraycopy(data, 1, data, 0, --nWords); + offset++; + } else { + data = Arrays.copyOf(data, data.length + 1); + } + } + data[nWords++] = p; + } else { + trimLeadingZeros(); + } + return this; + } + } + + /** + * Multiplies this <code>FDBigInteger</code> by + * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. The operation will be + * performed in place if possible, otherwise a new <code>FDBigInteger</code> + * will be returned. + * + * @param p5 The exponent of the power-of-five factor. + * @param p2 The exponent of the power-of-two factor. + * @return The multiplication result. + */ + /*@ + @ requires this.value() == 0 || p5 == 0 && p2 == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() > 0 && (p5 > 0 && p2 >= 0 || p5 == 0 && p2 > 0 && this.isImmutable); + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() * pow52(p5, p2)); + @ + @ also + @ + @ requires this.value() > 0 && p5 == 0 && p2 > 0 && !this.isImmutable; + @ assignable this.nWords, this.data, this.data[*]; + @ ensures \result == this; + @ ensures \result.value() == \old(this.value() * pow52(p5, p2)); + @*/ + public FDBigInteger multByPow52(int p5, int p2) { + if (this.nWords == 0) { + return this; + } + FDBigInteger res = this; + if (p5 != 0) { + int[] r; + int extraSize = (p2 != 0) ? 1 : 0; + if (p5 < SMALL_5_POW.length) { + r = new int[this.nWords + 1 + extraSize]; + mult(this.data, this.nWords, SMALL_5_POW[p5], r); + res = new FDBigInteger(r, this.offset); + } else { + FDBigInteger pow5 = big5pow(p5); + r = new int[this.nWords + pow5.size() + extraSize]; + mult(this.data, this.nWords, pow5.data, pow5.nWords, r); + res = new FDBigInteger(r, this.offset + pow5.offset); + } + } + return res.leftShift(p2); + } + + /** + * Multiplies two big integers represented as int arrays. + * + * @param s1 The first array factor. + * @param s1Len The number of elements of <code>s1</code> to use. + * @param s2 The second array factor. + * @param s2Len The number of elements of <code>s2</code> to use. + * @param dst The product array. + */ + /*@ + @ requires s1 != dst && s2 != dst; + @ requires s1.length >= s1Len && s2.length >= s2Len && dst.length >= s1Len + s2Len; + @ assignable dst[0 .. s1Len + s2Len - 1]; + @ ensures AP(dst, s1Len + s2Len) == \old(AP(s1, s1Len) * AP(s2, s2Len)); + @*/ + private static void mult(int[] s1, int s1Len, int[] s2, int s2Len, int[] dst) { + for (int i = 0; i < s1Len; i++) { + long v = s1[i] & LONG_MASK; + long p = 0L; + for (int j = 0; j < s2Len; j++) { + p += (dst[i + j] & LONG_MASK) + v * (s2[j] & LONG_MASK); + dst[i + j] = (int) p; + p >>>= 32; + } + dst[i + s2Len] = (int) p; + } + } + + /** + * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this + * <code>FDBigInteger</code>. Assert that the result is positive. + * If the subtrahend is immutable, store the result in this(minuend). + * If this(minuend) is immutable a new <code>FDBigInteger</code> is created. + * + * @param subtrahend The <code>FDBigInteger</code> to be subtracted. + * @return This <code>FDBigInteger</code> less the subtrahend. + */ + /*@ + @ requires this.isImmutable; + @ requires this.value() >= subtrahend.value(); + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() - subtrahend.value()); + @ + @ also + @ + @ requires !subtrahend.isImmutable; + @ requires this.value() >= subtrahend.value(); + @ assignable this.nWords, this.offset, this.data, this.data[*]; + @ ensures \result == this; + @ ensures \result.value() == \old(this.value() - subtrahend.value()); + @*/ + public FDBigInteger leftInplaceSub(FDBigInteger subtrahend) { + assert this.size() >= subtrahend.size() : "result should be positive"; + FDBigInteger minuend; + if (this.isImmutable) { + minuend = new FDBigInteger(this.data.clone(), this.offset); + } else { + minuend = this; + } + int offsetDiff = subtrahend.offset - minuend.offset; + int[] sData = subtrahend.data; + int[] mData = minuend.data; + int subLen = subtrahend.nWords; + int minLen = minuend.nWords; + if (offsetDiff < 0) { + // need to expand minuend + int rLen = minLen - offsetDiff; + if (rLen < mData.length) { + System.arraycopy(mData, 0, mData, -offsetDiff, minLen); + Arrays.fill(mData, 0, -offsetDiff, 0); + } else { + int[] r = new int[rLen]; + System.arraycopy(mData, 0, r, -offsetDiff, minLen); + minuend.data = mData = r; + } + minuend.offset = subtrahend.offset; + minuend.nWords = minLen = rLen; + offsetDiff = 0; + } + long borrow = 0L; + int mIndex = offsetDiff; + for (int sIndex = 0; sIndex < subLen && mIndex < minLen; sIndex++, mIndex++) { + long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; + mData[mIndex] = (int) diff; + borrow = diff >> 32; // signed shift + } + for (; borrow != 0 && mIndex < minLen; mIndex++) { + long diff = (mData[mIndex] & LONG_MASK) + borrow; + mData[mIndex] = (int) diff; + borrow = diff >> 32; // signed shift + } + assert borrow == 0L : borrow; // borrow out of subtract, + // result should be positive + minuend.trimLeadingZeros(); + return minuend; + } + + /** + * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this + * <code>FDBigInteger</code>. Assert that the result is positive. + * If the this(minuend) is immutable, store the result in subtrahend. + * If subtrahend is immutable a new <code>FDBigInteger</code> is created. + * + * @param subtrahend The <code>FDBigInteger</code> to be subtracted. + * @return This <code>FDBigInteger</code> less the subtrahend. + */ + /*@ + @ requires subtrahend.isImmutable; + @ requires this.value() >= subtrahend.value(); + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() - subtrahend.value()); + @ + @ also + @ + @ requires !subtrahend.isImmutable; + @ requires this.value() >= subtrahend.value(); + @ assignable subtrahend.nWords, subtrahend.offset, subtrahend.data, subtrahend.data[*]; + @ ensures \result == subtrahend; + @ ensures \result.value() == \old(this.value() - subtrahend.value()); + @*/ + public FDBigInteger rightInplaceSub(FDBigInteger subtrahend) { + assert this.size() >= subtrahend.size() : "result should be positive"; + FDBigInteger minuend = this; + if (subtrahend.isImmutable) { + subtrahend = new FDBigInteger(subtrahend.data.clone(), subtrahend.offset); + } + int offsetDiff = minuend.offset - subtrahend.offset; + int[] sData = subtrahend.data; + int[] mData = minuend.data; + int subLen = subtrahend.nWords; + int minLen = minuend.nWords; + if (offsetDiff < 0) { + int rLen = minLen; + if (rLen < sData.length) { + System.arraycopy(sData, 0, sData, -offsetDiff, subLen); + Arrays.fill(sData, 0, -offsetDiff, 0); + } else { + int[] r = new int[rLen]; + System.arraycopy(sData, 0, r, -offsetDiff, subLen); + subtrahend.data = sData = r; + } + subtrahend.offset = minuend.offset; + subLen -= offsetDiff; + offsetDiff = 0; + } else { + int rLen = minLen + offsetDiff; + if (rLen >= sData.length) { + subtrahend.data = sData = Arrays.copyOf(sData, rLen); + } + } + //@ assert minuend == this && minuend.value() == \old(this.value()); + //@ assert mData == minuend.data && minLen == minuend.nWords; + //@ assert subtrahend.offset + subtrahend.data.length >= minuend.size(); + //@ assert sData == subtrahend.data; + //@ assert AP(subtrahend.data, subtrahend.data.length) << subtrahend.offset == \old(subtrahend.value()); + //@ assert subtrahend.offset == Math.min(\old(this.offset), minuend.offset); + //@ assert offsetDiff == minuend.offset - subtrahend.offset; + //@ assert 0 <= offsetDiff && offsetDiff + minLen <= sData.length; + int sIndex = 0; + long borrow = 0L; + for (; sIndex < offsetDiff; sIndex++) { + long diff = 0L - (sData[sIndex] & LONG_MASK) + borrow; + sData[sIndex] = (int) diff; + borrow = diff >> 32; // signed shift + } + //@ assert sIndex == offsetDiff; + for (int mIndex = 0; mIndex < minLen; sIndex++, mIndex++) { + //@ assert sIndex == offsetDiff + mIndex; + long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; + sData[sIndex] = (int) diff; + borrow = diff >> 32; // signed shift + } + assert borrow == 0L : borrow; // borrow out of subtract, + // result should be positive + subtrahend.nWords = sIndex; + subtrahend.trimLeadingZeros(); + return subtrahend; + + } + + /** + * Determines whether all elements of an array are zero for all indices less + * than a given index. + * + * @param a The array to be examined. + * @param from The index strictly below which elements are to be examined. + * @return Zero if all elements in range are zero, 1 otherwise. + */ + /*@ + @ requires 0 <= from && from <= a.length; + @ ensures \result == (AP(a, from) == 0 ? 0 : 1); + @*/ + private /*@ pure @*/ static int checkZeroTail(int[] a, int from) { + while (from > 0) { + if (a[--from] != 0) { + return 1; + } + } + return 0; + } + + /** + * Compares the parameter with this <code>FDBigInteger</code>. Returns an + * integer accordingly as: + * <pre>{@code + * > 0: this > other + * 0: this == other + * < 0: this < other + * }</pre> + * + * @param other The <code>FDBigInteger</code> to compare. + * @return A negative value, zero, or a positive value according to the + * result of the comparison. + */ + /*@ + @ ensures \result == (this.value() < other.value() ? -1 : this.value() > other.value() ? +1 : 0); + @*/ + public /*@ pure @*/ int cmp(FDBigInteger other) { + int aSize = nWords + offset; + int bSize = other.nWords + other.offset; + if (aSize > bSize) { + return 1; + } else if (aSize < bSize) { + return -1; + } + int aLen = nWords; + int bLen = other.nWords; + while (aLen > 0 && bLen > 0) { + int a = data[--aLen]; + int b = other.data[--bLen]; + if (a != b) { + return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; + } + } + if (aLen > 0) { + return checkZeroTail(data, aLen); + } + if (bLen > 0) { + return -checkZeroTail(other.data, bLen); + } + return 0; + } + + /** + * Compares this <code>FDBigInteger</code> with + * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. + * Returns an integer accordingly as: + * <pre>{@code + * > 0: this > other + * 0: this == other + * < 0: this < other + * }</pre> + * @param p5 The exponent of the power-of-five factor. + * @param p2 The exponent of the power-of-two factor. + * @return A negative value, zero, or a positive value according to the + * result of the comparison. + */ + /*@ + @ requires p5 >= 0 && p2 >= 0; + @ ensures \result == (this.value() < pow52(p5, p2) ? -1 : this.value() > pow52(p5, p2) ? +1 : 0); + @*/ + public /*@ pure @*/ int cmpPow52(int p5, int p2) { + if (p5 == 0) { + int wordcount = p2 >> 5; + int bitcount = p2 & 0x1f; + int size = this.nWords + this.offset; + if (size > wordcount + 1) { + return 1; + } else if (size < wordcount + 1) { + return -1; + } + int a = this.data[this.nWords -1]; + int b = 1 << bitcount; + if (a != b) { + return ( (a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; + } + return checkZeroTail(this.data, this.nWords - 1); + } + return this.cmp(big5pow(p5).leftShift(p2)); + } + + /** + * Compares this <code>FDBigInteger</code> with <code>x + y</code>. Returns a + * value according to the comparison as: + * <pre>{@code + * -1: this < x + y + * 0: this == x + y + * 1: this > x + y + * }</pre> + * @param x The first addend of the sum to compare. + * @param y The second addend of the sum to compare. + * @return -1, 0, or 1 according to the result of the comparison. + */ + /*@ + @ ensures \result == (this.value() < x.value() + y.value() ? -1 : this.value() > x.value() + y.value() ? +1 : 0); + @*/ + public /*@ pure @*/ int addAndCmp(FDBigInteger x, FDBigInteger y) { + FDBigInteger big; + FDBigInteger small; + int xSize = x.size(); + int ySize = y.size(); + int bSize; + int sSize; + if (xSize >= ySize) { + big = x; + small = y; + bSize = xSize; + sSize = ySize; + } else { + big = y; + small = x; + bSize = ySize; + sSize = xSize; + } + int thSize = this.size(); + if (bSize == 0) { + return thSize == 0 ? 0 : 1; + } + if (sSize == 0) { + return this.cmp(big); + } + if (bSize > thSize) { + return -1; + } + if (bSize + 1 < thSize) { + return 1; + } + long top = (big.data[big.nWords - 1] & LONG_MASK); + if (sSize == bSize) { + top += (small.data[small.nWords - 1] & LONG_MASK); + } + if ((top >>> 32) == 0) { + if (((top + 1) >>> 32) == 0) { + // good case - no carry extension + if (bSize < thSize) { + return 1; + } + // here sum.nWords == this.nWords + long v = (this.data[this.nWords - 1] & LONG_MASK); + if (v < top) { + return -1; + } + if (v > top + 1) { + return 1; + } + } + } else { // (top>>>32)!=0 guaranteed carry extension + if (bSize + 1 > thSize) { + return -1; + } + // here sum.nWords == this.nWords + top >>>= 32; + long v = (this.data[this.nWords - 1] & LONG_MASK); + if (v < top) { + return -1; + } + if (v > top + 1) { + return 1; + } + } + return this.cmp(big.add(small)); + } + + /** + * Makes this <code>FDBigInteger</code> immutable. + */ + /*@ + @ assignable this.isImmutable; + @ ensures this.isImmutable; + @*/ + public void makeImmutable() { + this.isImmutable = true; + } + + /** + * Multiplies this <code>FDBigInteger</code> by an integer. + * + * @param i The factor by which to multiply this <code>FDBigInteger</code>. + * @return This <code>FDBigInteger</code> multiplied by an integer. + */ + /*@ + @ requires this.value() == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() != 0; + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() * UNSIGNED(i)); + @*/ + private FDBigInteger mult(int i) { + if (this.nWords == 0) { + return this; + } + int[] r = new int[nWords + 1]; + mult(data, nWords, i, r); + return new FDBigInteger(r, offset); + } + + /** + * Multiplies this <code>FDBigInteger</code> by another <code>FDBigInteger</code>. + * + * @param other The <code>FDBigInteger</code> factor by which to multiply. + * @return The product of this and the parameter <code>FDBigInteger</code>s. + */ + /*@ + @ requires this.value() == 0; + @ assignable \nothing; + @ ensures \result == this; + @ + @ also + @ + @ requires this.value() != 0 && other.value() == 0; + @ assignable \nothing; + @ ensures \result == other; + @ + @ also + @ + @ requires this.value() != 0 && other.value() != 0; + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() * other.value()); + @*/ + private FDBigInteger mult(FDBigInteger other) { + if (this.nWords == 0) { + return this; + } + if (this.size() == 1) { + return other.mult(data[0]); + } + if (other.nWords == 0) { + return other; + } + if (other.size() == 1) { + return this.mult(other.data[0]); + } + int[] r = new int[nWords + other.nWords]; + mult(this.data, this.nWords, other.data, other.nWords, r); + return new FDBigInteger(r, this.offset + other.offset); + } + + /** + * Adds another <code>FDBigInteger</code> to this <code>FDBigInteger</code>. + * + * @param other The <code>FDBigInteger</code> to add. + * @return The sum of the <code>FDBigInteger</code>s. + */ + /*@ + @ assignable \nothing; + @ ensures \result.value() == \old(this.value() + other.value()); + @*/ + private FDBigInteger add(FDBigInteger other) { + FDBigInteger big, small; + int bigLen, smallLen; + int tSize = this.size(); + int oSize = other.size(); + if (tSize >= oSize) { + big = this; + bigLen = tSize; + small = other; + smallLen = oSize; + } else { + big = other; + bigLen = oSize; + small = this; + smallLen = tSize; + } + int[] r = new int[bigLen + 1]; + int i = 0; + long carry = 0L; + for (; i < smallLen; i++) { + carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ) + + ((i < small.offset ? 0L : (small.data[i - small.offset] & LONG_MASK))); + r[i] = (int) carry; + carry >>= 32; // signed shift. + } + for (; i < bigLen; i++) { + carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ); + r[i] = (int) carry; + carry >>= 32; // signed shift. + } + r[bigLen] = (int) carry; + return new FDBigInteger(r, 0); + } + + + /** + * Multiplies a <code>FDBigInteger</code> by an int and adds another int. The + * result is computed in place. This method is intended only to be invoked + * from + * <code> + * FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) + * </code>. + * + * @param iv The factor by which to multiply this <code>FDBigInteger</code>. + * @param addend The value to add to the product of this + * <code>FDBigInteger</code> and <code>iv</code>. + */ + /*@ + @ requires this.value()*UNSIGNED(iv) + UNSIGNED(addend) < ((\bigint)1) << ((this.data.length + this.offset)*32); + @ assignable this.data[*]; + @ ensures this.value() == \old(this.value()*UNSIGNED(iv) + UNSIGNED(addend)); + @*/ + private /*@ helper @*/ void multAddMe(int iv, int addend) { + long v = iv & LONG_MASK; + // unroll 0th iteration, doing addition. + long p = v * (data[0] & LONG_MASK) + (addend & LONG_MASK); + data[0] = (int) p; + p >>>= 32; + for (int i = 1; i < nWords; i++) { + p += v * (data[i] & LONG_MASK); + data[i] = (int) p; + p >>>= 32; + } + if (p != 0L) { + data[nWords++] = (int) p; // will fail noisily if illegal! + } + } + + // + // original doc: + // + // do this -=q*S + // returns borrow + // + /** + * Multiplies the parameters and subtracts them from this + * <code>FDBigInteger</code>. + * + * @param q The integer parameter. + * @param S The <code>FDBigInteger</code> parameter. + * @return <code>this - q*S</code>. + */ + /*@ + @ ensures nWords == 0 ==> offset == 0; + @ ensures nWords > 0 ==> data[nWords - 1] != 0; + @*/ + /*@ + @ requires 0 < q && q <= (1L << 31); + @ requires data != null; + @ requires 0 <= nWords && nWords <= data.length && offset >= 0; + @ requires !this.isImmutable; + @ requires this.size() == S.size(); + @ requires this != S; + @ assignable this.nWords, this.offset, this.data, this.data[*]; + @ ensures -q <= \result && \result <= 0; + @ ensures this.size() == \old(this.size()); + @ ensures this.value() + (\result << (this.size()*32)) == \old(this.value() - q*S.value()); + @ ensures this.offset == \old(Math.min(this.offset, S.offset)); + @ ensures \old(this.offset <= S.offset) ==> this.nWords == \old(this.nWords); + @ ensures \old(this.offset <= S.offset) ==> this.offset == \old(this.offset); + @ ensures \old(this.offset <= S.offset) ==> this.data == \old(this.data); + @ + @ also + @ + @ requires q == 0; + @ assignable \nothing; + @ ensures \result == 0; + @*/ + private /*@ helper @*/ long multDiffMe(long q, FDBigInteger S) { + long diff = 0L; + if (q != 0) { + int deltaSize = S.offset - this.offset; + if (deltaSize >= 0) { + int[] sd = S.data; + int[] td = this.data; + for (int sIndex = 0, tIndex = deltaSize; sIndex < S.nWords; sIndex++, tIndex++) { + diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); + td[tIndex] = (int) diff; + diff >>= 32; // N.B. SIGNED shift. + } + } else { + deltaSize = -deltaSize; + int[] rd = new int[nWords + deltaSize]; + int sIndex = 0; + int rIndex = 0; + int[] sd = S.data; + for (; rIndex < deltaSize && sIndex < S.nWords; sIndex++, rIndex++) { + diff -= q * (sd[sIndex] & LONG_MASK); + rd[rIndex] = (int) diff; + diff >>= 32; // N.B. SIGNED shift. + } + int tIndex = 0; + int[] td = this.data; + for (; sIndex < S.nWords; sIndex++, tIndex++, rIndex++) { + diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); + rd[rIndex] = (int) diff; + diff >>= 32; // N.B. SIGNED shift. + } + this.nWords += deltaSize; + this.offset -= deltaSize; + this.data = rd; + } + } + return diff; + } + + + /** + * Multiplies by 10 a big integer represented as an array. The final carry + * is returned. + * + * @param src The array representation of the big integer. + * @param srcLen The number of elements of <code>src</code> to use. + * @param dst The product array. + * @return The final carry of the multiplication. + */ + /*@ + @ requires src.length >= srcLen && dst.length >= srcLen; + @ assignable dst[0 .. srcLen - 1]; + @ ensures 0 <= \result && \result < 10; + @ ensures AP(dst, srcLen) + (\result << (srcLen*32)) == \old(AP(src, srcLen) * 10); + @*/ + private static int multAndCarryBy10(int[] src, int srcLen, int[] dst) { + long carry = 0; + for (int i = 0; i < srcLen; i++) { + long product = (src[i] & LONG_MASK) * 10L + carry; + dst[i] = (int) product; + carry = product >>> 32; + } + return (int) carry; + } + + /** + * Multiplies by a constant value a big integer represented as an array. + * The constant factor is an <code>int</code>. + * + * @param src The array representation of the big integer. + * @param srcLen The number of elements of <code>src</code> to use. + * @param value The constant factor by which to multiply. + * @param dst The product array. + */ + /*@ + @ requires src.length >= srcLen && dst.length >= srcLen + 1; + @ assignable dst[0 .. srcLen]; + @ ensures AP(dst, srcLen + 1) == \old(AP(src, srcLen) * UNSIGNED(value)); + @*/ + private static void mult(int[] src, int srcLen, int value, int[] dst) { + long val = value & LONG_MASK; + long carry = 0; + for (int i = 0; i < srcLen; i++) { + long product = (src[i] & LONG_MASK) * val + carry; + dst[i] = (int) product; + carry = product >>> 32; + } + dst[srcLen] = (int) carry; + } + + /** + * Multiplies by a constant value a big integer represented as an array. + * The constant factor is a long represent as two <code>int</code>s. + * + * @param src The array representation of the big integer. + * @param srcLen The number of elements of <code>src</code> to use. + * @param v0 The lower 32 bits of the long factor. + * @param v1 The upper 32 bits of the long factor. + * @param dst The product array. + */ + /*@ + @ requires src != dst; + @ requires src.length >= srcLen && dst.length >= srcLen + 2; + @ assignable dst[0 .. srcLen + 1]; + @ ensures AP(dst, srcLen + 2) == \old(AP(src, srcLen) * (UNSIGNED(v0) + (UNSIGNED(v1) << 32))); + @*/ + private static void mult(int[] src, int srcLen, int v0, int v1, int[] dst) { + long v = v0 & LONG_MASK; + long carry = 0; + for (int j = 0; j < srcLen; j++) { + long product = v * (src[j] & LONG_MASK) + carry; + dst[j] = (int) product; + carry = product >>> 32; + } + dst[srcLen] = (int) carry; + v = v1 & LONG_MASK; + carry = 0; + for (int j = 0; j < srcLen; j++) { + long product = (dst[j + 1] & LONG_MASK) + v * (src[j] & LONG_MASK) + carry; + dst[j + 1] = (int) product; + carry = product >>> 32; + } + dst[srcLen + 1] = (int) carry; + } + + // Fails assertion for negative exponent. + /** + * Computes <code>5</code> raised to a given power. + * + * @param p The exponent of 5. + * @return <code>5<sup>p</sup></code>. + */ + private static FDBigInteger big5pow(int p) { + assert p >= 0 : p; // negative power of 5 + if (p < MAX_FIVE_POW) { + return POW_5_CACHE[p]; + } + return big5powRec(p); + } + + // slow path + /** + * Computes <code>5</code> raised to a given power. + * + * @param p The exponent of 5. + * @return <code>5<sup>p</sup></code>. + */ + private static FDBigInteger big5powRec(int p) { + if (p < MAX_FIVE_POW) { + return POW_5_CACHE[p]; + } + // construct the value. + // recursively. + int q, r; + // in order to compute 5^p, + // compute its square root, 5^(p/2) and square. + // or, let q = p / 2, r = p -q, then + // 5^p = 5^(q+r) = 5^q * 5^r + q = p >> 1; + r = p - q; + FDBigInteger bigq = big5powRec(q); + if (r < SMALL_5_POW.length) { + return bigq.mult(SMALL_5_POW[r]); + } else { + return bigq.mult(big5powRec(r)); + } + } + + // for debugging ... + /** + * Converts this <code>FDBigInteger</code> to a hexadecimal string. + * + * @return The hexadecimal string representation. + */ + public String toHexString(){ + if(nWords ==0) { + return "0"; + } + StringBuilder sb = new StringBuilder((nWords +offset)*8); + for(int i= nWords -1; i>=0; i--) { + String subStr = Integer.toHexString(data[i]); + for(int j = subStr.length(); j<8; j++) { + sb.append('0'); + } + sb.append(subStr); + } + for(int i=offset; i>0; i--) { + sb.append("00000000"); + } + return sb.toString(); + } + + // for debugging ... + /** + * Converts this <code>FDBigInteger</code> to a <code>BigInteger</code>. + * + * @return The <code>BigInteger</code> representation. + */ + public BigInteger toBigInteger() { + byte[] magnitude = new byte[nWords * 4 + 1]; + for (int i = 0; i < nWords; i++) { + int w = data[i]; + magnitude[magnitude.length - 4 * i - 1] = (byte) w; + magnitude[magnitude.length - 4 * i - 2] = (byte) (w >> 8); + magnitude[magnitude.length - 4 * i - 3] = (byte) (w >> 16); + magnitude[magnitude.length - 4 * i - 4] = (byte) (w >> 24); + } + return new BigInteger(magnitude).shiftLeft(offset * 32); + } + + // for debugging ... + /** + * Converts this <code>FDBigInteger</code> to a string. + * + * @return The string representation. + */ + @Override + public String toString(){ + return toBigInteger().toString(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/math/FloatConsts.java Thu Dec 24 10:34:31 2015 -0800 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.math; + +/** + * This class contains additional constants documenting limits of the + * <code>float</code> type. + * + * @author Joseph D. Darcy + */ + +public class FloatConsts { + /** + * Don't let anyone instantiate this class. + */ + private FloatConsts() {} + + public static final float POSITIVE_INFINITY = java.lang.Float.POSITIVE_INFINITY; + public static final float NEGATIVE_INFINITY = java.lang.Float.NEGATIVE_INFINITY; + public static final float NaN = java.lang.Float.NaN; + public static final float MAX_VALUE = java.lang.Float.MAX_VALUE; + public static final float MIN_VALUE = java.lang.Float.MIN_VALUE; + + /** + * A constant holding the smallest positive normal value of type + * <code>float</code>, 2<sup>-126</sup>. It is equal to the value + * returned by <code>Float.intBitsToFloat(0x00800000)</code>. + */ + public static final float MIN_NORMAL = 1.17549435E-38f; + + /** + * The number of logical bits in the significand of a + * <code>float</code> number, including the implicit bit. + */ + public static final int SIGNIFICAND_WIDTH = 24; + + /** + * Maximum exponent a finite <code>float</code> number may have. + * It is equal to the value returned by + * <code>Math.ilogb(Float.MAX_VALUE)</code>. + */ + public static final int MAX_EXPONENT = 127; + + /** + * Minimum exponent a normalized <code>float</code> number may + * have. It is equal to the value returned by + * <code>Math.ilogb(Float.MIN_NORMAL)</code>. + */ + public static final int MIN_EXPONENT = -126; + + /** + * The exponent the smallest positive <code>float</code> subnormal + * value would have if it could be normalized. + */ + public static final int MIN_SUB_EXPONENT = MIN_EXPONENT - + (SIGNIFICAND_WIDTH - 1); + + /** + * Bias used in representing a <code>float</code> exponent. + */ + public static final int EXP_BIAS = 127; + + /** + * Bit mask to isolate the sign bit of a <code>float</code>. + */ + public static final int SIGN_BIT_MASK = 0x80000000; + + /** + * Bit mask to isolate the exponent field of a + * <code>float</code>. + */ + public static final int EXP_BIT_MASK = 0x7F800000; + + /** + * Bit mask to isolate the significand field of a + * <code>float</code>. + */ + public static final int SIGNIF_BIT_MASK = 0x007FFFFF; + + static { + // verify bit masks cover all bit positions and that the bit + // masks are non-overlapping + assert(((SIGN_BIT_MASK | EXP_BIT_MASK | SIGNIF_BIT_MASK) == ~0) && + (((SIGN_BIT_MASK & EXP_BIT_MASK) == 0) && + ((SIGN_BIT_MASK & SIGNIF_BIT_MASK) == 0) && + ((EXP_BIT_MASK & SIGNIF_BIT_MASK) == 0))); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/math/FloatingDecimal.java Thu Dec 24 10:34:31 2015 -0800 @@ -0,0 +1,2552 @@ +/* + * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.math; + +import java.util.Arrays; +import java.util.regex.*; + +/** + * A class for converting between ASCII and decimal representations of a single + * or double precision floating point number. Most conversions are provided via + * static convenience methods, although a <code>BinaryToASCIIConverter</code> + * instance may be obtained and reused. + */ +public class FloatingDecimal{ + // + // Constants of the implementation; + // most are IEEE-754 related. + // (There are more really boring constants at the end.) + // + static final int EXP_SHIFT = DoubleConsts.SIGNIFICAND_WIDTH - 1; + static final long FRACT_HOB = ( 1L<<EXP_SHIFT ); // assumed High-Order bit + static final long EXP_ONE = ((long)DoubleConsts.EXP_BIAS)<<EXP_SHIFT; // exponent of 1.0 + static final int MAX_SMALL_BIN_EXP = 62; + static final int MIN_SMALL_BIN_EXP = -( 63 / 3 ); + static final int MAX_DECIMAL_DIGITS = 15; + static final int MAX_DECIMAL_EXPONENT = 308; + static final int MIN_DECIMAL_EXPONENT = -324; + static final int BIG_DECIMAL_EXPONENT = 324; // i.e. abs(MIN_DECIMAL_EXPONENT) + static final int MAX_NDIGITS = 1100; + + static final int SINGLE_EXP_SHIFT = FloatConsts.SIGNIFICAND_WIDTH - 1; + static final int SINGLE_FRACT_HOB = 1<<SINGLE_EXP_SHIFT; + static final int SINGLE_MAX_DECIMAL_DIGITS = 7; + static final int SINGLE_MAX_DECIMAL_EXPONENT = 38; + static final int SINGLE_MIN_DECIMAL_EXPONENT = -45; + static final int SINGLE_MAX_NDIGITS = 200; + + static final int INT_DECIMAL_DIGITS = 9; + + /** + * Converts a double precision floating point value to a <code>String</code>. + * + * @param d The double precision value. + * @return The value converted to a <code>String</code>. + */ + public static String toJavaFormatString(double d) { + return getBinaryToASCIIConverter(d).toJavaFormatString(); + } + + /** + * Converts a single precision floating point value to a <code>String</code>. + * + * @param f The single precision value. + * @return The value converted to a <code>String</code>. + */ + public static String toJavaFormatString(float f) { + return getBinaryToASCIIConverter(f).toJavaFormatString(); + } + + /** + * Appends a double precision floating point value to an <code>Appendable</code>. + * @param d The double precision value. + * @param buf The <code>Appendable</code> with the value appended. + */ + public static void appendTo(double d, Appendable buf) { + getBinaryToASCIIConverter(d).appendTo(buf); + } + + /** + * Appends a single precision floating point value to an <code>Appendable</code>. + * @param f The single precision value. + * @param buf The <code>Appendable</code> with the value appended. + */ + public static void appendTo(float f, Appendable buf) { + getBinaryToASCIIConverter(f).appendTo(buf); + } + + /** + * Converts a <code>String</code> to a double precision floating point value. + * + * @param s The <code>String</code> to convert. + * @return The double precision value. + * @throws NumberFormatException If the <code>String</code> does not + * represent a properly formatted double precision value. + */ + public static double parseDouble(String s) throws NumberFormatException { + return readJavaFormatString(s).doubleValue(); + } + + /** + * Converts a <code>String</code> to a single precision floating point value. + * + * @param s The <code>String</code> to convert. + * @return The single precision value. + * @throws NumberFormatException If the <code>String</code> does not + * represent a properly formatted single precision value. + */ + public static float parseFloat(String s) throws NumberFormatException { + return readJavaFormatString(s).floatValue(); + } + + /** + * A converter which can process single or double precision floating point + * values into an ASCII <code>String</code> representation. + */ + public interface BinaryToASCIIConverter { + /** + * Converts a floating point value into an ASCII <code>String</code>. + * @return The value converted to a <code>String</code>. + */ + public String toJavaFormatString(); + + /** + * Appends a floating point value to an <code>Appendable</code>. + * @param buf The <code>Appendable</code> to receive the value. + */ + public void appendTo(Appendable buf); + + /** + * Retrieves the decimal exponent most closely corresponding to this value. + * @return The decimal exponent. + */ + public int getDecimalExponent(); + + /** + * Retrieves the value as an array of digits. + * @param digits The digit array. + * @return The number of valid digits copied into the array. + */ + public int getDigits(char[] digits); + + /** + * Indicates the sign of the value. + * @return {@code value < 0.0}. + */ + public boolean isNegative(); + + /** + * Indicates whether the value is either infinite or not a number. + * + * @return <code>true</code> if and only if the value is <code>NaN</code> + * or infinite. + */ + public boolean isExceptional(); + + /** + * Indicates whether the value was rounded up during the binary to ASCII + * conversion. + * + * @return <code>true</code> if and only if the value was rounded up. + */ + public boolean digitsRoundedUp(); + + /** + * Indicates whether the binary to ASCII conversion was exact. + * + * @return <code>true</code> if any only if the conversion was exact. + */ + public boolean decimalDigitsExact(); + } + + /** + * A <code>BinaryToASCIIConverter</code> which represents <code>NaN</code> + * and infinite values. + */ + private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter { + private final String image; + private boolean isNegative; + + public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) { + this.image = image; + this.isNegative = isNegative; + } + + @Override + public String toJavaFormatString() { + return image; + } + + @Override + public void appendTo(Appendable buf) { + if (buf instanceof StringBuilder) { + ((StringBuilder) buf).append(image); + } else if (buf instanceof StringBuffer) { + ((StringBuffer) buf).append(image); + } else { + assert false; + } + } + + @Override + public int getDecimalExponent() { + throw new IllegalArgumentException("Exceptional value does not have an exponent"); + } + + @Override + public int getDigits(char[] digits) { + throw new IllegalArgumentException("Exceptional value does not have digits"); + } + + @Override + public boolean isNegative() { + return isNegative; + } + + @Override + public boolean isExceptional() { + return true; + } + + @Override + public boolean digitsRoundedUp() { + throw new IllegalArgumentException("Exceptional value is not rounded"); + } + + @Override + public boolean decimalDigitsExact() { + throw new IllegalArgumentException("Exceptional value is not exact"); + } + } + + private static final String INFINITY_REP = "Infinity"; + private static final int INFINITY_LENGTH = INFINITY_REP.length(); + private static final String NAN_REP = "NaN"; + private static final int NAN_LENGTH = NAN_REP.length(); + + private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false); + private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true); + private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false); + private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'}); + private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new char[]{'0'}); + + /** + * A buffered implementation of <code>BinaryToASCIIConverter</code>. + */ + static class BinaryToASCIIBuffer implements BinaryToASCIIConverter { + private boolean isNegative; + private int decExponent; + private int firstDigitIndex; + private int nDigits; + private final char[] digits; + private final char[] buffer = new char[26]; + + // + // The fields below provide additional information about the result of + // the binary to decimal digits conversion done in dtoa() and roundup() + // methods. They are changed if needed by those two methods. + // + + // True if the dtoa() binary to decimal conversion was exact. + private boolean exactDecimalConversion = false; + + // True if the result of the binary to decimal conversion was rounded-up + // at the end of the conversion process, i.e. roundUp() method was called. + private boolean decimalDigitsRoundedUp = false; + + /** + * Default constructor; used for non-zero values, + * <code>BinaryToASCIIBuffer</code> may be thread-local and reused + */ + BinaryToASCIIBuffer(){ + this.digits = new char[20]; + } + + /** + * Creates a specialized value (positive and negative zeros). + */ + BinaryToASCIIBuffer(boolean isNegative, char[] digits){ + this.isNegative = isNegative; + this.decExponent = 0; + this.digits = digits; + this.firstDigitIndex = 0; + this.nDigits = digits.length; + } + + @Override + public String toJavaFormatString() { + int len = getChars(buffer); + return new String(buffer, 0, len); + } + + @Override + public void appendTo(Appendable buf) { + int len = getChars(buffer); + if (buf instanceof StringBuilder) { + ((StringBuilder) buf).append(buffer, 0, len); + } else if (buf instanceof StringBuffer) { + ((StringBuffer) buf).append(buffer, 0, len); + } else { + assert false; + } + } + + @Override + public int getDecimalExponent() { + return decExponent; + } + + @Override + public int getDigits(char[] digits) { + System.arraycopy(this.digits,firstDigitIndex,digits,0,this.nDigits); + return this.nDigits; + } + + @Override + public boolean isNegative() { + return isNegative; + } + + @Override + public boolean isExceptional() { + return false; + } + + @Override + public boolean digitsRoundedUp() { + return decimalDigitsRoundedUp; + } + + @Override + public boolean decimalDigitsExact() { + return exactDecimalConversion; + } + + private void setSign(boolean isNegative) { + this.isNegative = isNegative; + } + + /** + * This is the easy subcase -- + * all the significant bits, after scaling, are held in lvalue. + * negSign and decExponent tell us what processing and scaling + * has already been done. Exceptional cases have already been + * stripped out. + * In particular: + * lvalue is a finite number (not Inf, nor NaN) + * lvalue > 0L (not zero, nor negative). + * + * The only reason that we develop the digits here, rather than + * calling on Long.toString() is that we can do it a little faster, + * and besides want to treat trailing 0s specially. If Long.toString + * changes, we should re-evaluate this strategy! + */ + private void developLongDigits( int decExponent, long lvalue, int insignificantDigits ){ + if ( insignificantDigits != 0 ){ + // Discard non-significant low-order bits, while rounding, + // up to insignificant value. + long pow10 = FDBigInteger.LONG_5_POW[insignificantDigits] << insignificantDigits; // 10^i == 5^i * 2^i; + long residue = lvalue % pow10; + lvalue /= pow10; + decExponent += insignificantDigits; + if ( residue >= (pow10>>1) ){ + // round up based on the low-order bits we're discarding + lvalue++; + } + } + int digitno = digits.length -1; + int c; + if ( lvalue <= Integer.MAX_VALUE ){ + assert lvalue > 0L : lvalue; // lvalue <= 0 + // even easier subcase! + // can do int arithmetic rather than long! + int ivalue = (int)lvalue; + c = ivalue%10; + ivalue /= 10; + while ( c == 0 ){ + decExponent++; + c = ivalue%10; + ivalue /= 10; + } + while ( ivalue != 0){ + digits[digitno--] = (char)(c+'0'); + decExponent++; + c = ivalue%10; + ivalue /= 10; + } + digits[digitno] = (char)(c+'0'); + } else { + // same algorithm as above (same bugs, too ) + // but using long arithmetic. + c = (int)(lvalue%10L); + lvalue /= 10L; + while ( c == 0 ){ + decExponent++; + c = (int)(lvalue%10L); + lvalue /= 10L; + } + while ( lvalue != 0L ){ + digits[digitno--] = (char)(c+'0'); + decExponent++; + c = (int)(lvalue%10L); + lvalue /= 10; + } + digits[digitno] = (char)(c+'0'); + } + this.decExponent = decExponent+1; + this.firstDigitIndex = digitno; + this.nDigits = this.digits.length - digitno; + } + + private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat) + { + assert fractBits > 0 ; // fractBits here can't be zero or negative + assert (fractBits & FRACT_HOB)!=0 ; // Hi-order bit should be set + // Examine number. Determine if it is an easy case, + // which we can do pretty trivially using float/long conversion, + // or whether we must do real work. + final int tailZeros = Long.numberOfTrailingZeros(fractBits); + + // number of significant bits of fractBits; + final int nFractBits = EXP_SHIFT+1-tailZeros; + + // reset flags to default values as dtoa() does not always set these + // flags and a prior call to dtoa() might have set them to incorrect + // values with respect to the current state. + decimalDigitsRoundedUp = false; + exactDecimalConversion = false; + + // number of significant bits to the right of the point. + int nTinyBits = Math.max( 0, nFractBits - binExp - 1 ); + if ( binExp <= MAX_SMALL_BIN_EXP && binExp >= MIN_SMALL_BIN_EXP ){ + // Look more closely at the number to decide if, + // with scaling by 10^nTinyBits, the result will fit in + // a long. + if ( (nTinyBits < FDBigInteger.LONG_5_POW.length) && ((nFractBits + N_5_BITS[nTinyBits]) < 64 ) ){ + // + // We can do this: + // take the fraction bits, which are normalized. + // (a) nTinyBits == 0: Shift left or right appropriately + // to align the binary point at the extreme right, i.e. + // where a long int point is expected to be. The integer + // result is easily converted to a string. + // (b) nTinyBits > 0: Shift right by EXP_SHIFT-nFractBits, + // which effectively converts to long and scales by + // 2^nTinyBits. Then multiply by 5^nTinyBits to + // complete the scaling. We know this won't overflow + // because we just counted the number of bits necessary + // in the result. The integer you get from this can + // then be converted to a string pretty easily. + // + if ( nTinyBits == 0 ) { + int insignificant; + if ( binExp > nSignificantBits ){ + insignificant = insignificantDigitsForPow2(binExp-nSignificantBits-1); + } else { + insignificant = 0; + } + if ( binExp >= EXP_SHIFT ){ + fractBits <<= (binExp-EXP_SHIFT); + } else { + fractBits >>>= (EXP_SHIFT-binExp) ; + } + developLongDigits( 0, fractBits, insignificant ); + return; + } + // + // The following causes excess digits to be printed + // out in the single-float case. Our manipulation of + // halfULP here is apparently not correct. If we + // better understand how this works, perhaps we can + // use this special case again. But for the time being, + // we do not. + // else { + // fractBits >>>= EXP_SHIFT+1-nFractBits; + // fractBits//= long5pow[ nTinyBits ]; + // halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits); + // developLongDigits( -nTinyBits, fractBits, insignificantDigits(halfULP) ); + // return; + // } + // + } + } + // + // This is the hard case. We are going to compute large positive + // integers B and S and integer decExp, s.t. + // d = ( B / S )// 10^decExp + // 1 <= B / S < 10 + // Obvious choices are: + // decExp = floor( log10(d) ) + // B = d// 2^nTinyBits// 10^max( 0, -decExp ) + // S = 10^max( 0, decExp)// 2^nTinyBits + // (noting that nTinyBits has already been forced to non-negative) + // I am also going to compute a large positive integer + // M = (1/2^nSignificantBits)// 2^nTinyBits// 10^max( 0, -decExp ) + // i.e. M is (1/2) of the ULP of d, scaled like B. + // When we iterate through dividing B/S and picking off the + // quotient bits, we will know when to stop when the remainder + // is <= M. + // + // We keep track of powers of 2 and powers of 5. + // + int decExp = estimateDecExp(fractBits,binExp); + int B2, B5; // powers of 2 and powers of 5, respectively, in B + int S2, S5; // powers of 2 and powers of 5, respectively, in S + int M2, M5; // powers of 2 and powers of 5, respectively, in M + + B5 = Math.max( 0, -decExp ); + B2 = B5 + nTinyBits + binExp; + + S5 = Math.max( 0, decExp ); + S2 = S5 + nTinyBits; + + M5 = B5; + M2 = B2 - nSignificantBits; + + // + // the long integer fractBits contains the (nFractBits) interesting + // bits from the mantissa of d ( hidden 1 added if necessary) followed + // by (EXP_SHIFT+1-nFractBits) zeros. In the interest of compactness, + // I will shift out those zeros before turning fractBits into a + // FDBigInteger. The resulting whole number will be + // d * 2^(nFractBits-1-binExp). + // + fractBits >>>= tailZeros; + B2 -= nFractBits-1; + int common2factor = Math.min( B2, S2 ); + B2 -= common2factor; + S2 -= common2factor; + M2 -= common2factor; + + // + // HACK!! For exact powers of two, the next smallest number + // is only half as far away as we think (because the meaning of + // ULP changes at power-of-two bounds) for this reason, we + // hack M2. Hope this works. + // + if ( nFractBits == 1 ) { + M2 -= 1; + } + + if ( M2 < 0 ){ + // oops. + // since we cannot scale M down far enough, + // we must scale the other values up. + B2 -= M2; + S2 -= M2; + M2 = 0; + } + // + // Construct, Scale, iterate. + // Some day, we'll write a stopping test that takes + // account of the asymmetry of the spacing of floating-point + // numbers below perfect powers of 2 + // 26 Sept 96 is not that day. + // So we use a symmetric test. + // + int ndigit = 0; + boolean low, high; + long lowDigitDifference; + int q; + + // + // Detect the special cases where all the numbers we are about + // to compute will fit in int or long integers. + // In these cases, we will avoid doing FDBigInteger arithmetic. + // We use the same algorithms, except that we "normalize" + // our FDBigIntegers before iterating. This is to make division easier, + // as it makes our fist guess (quotient of high-order words) + // more accurate! + // + // Some day, we'll write a stopping test that takes + // account of the asymmetry of the spacing of floating-point + // numbers below perfect powers of 2 + // 26 Sept 96 is not that day. + // So we use a symmetric test. + // + // binary digits needed to represent B, approx. + int Bbits = nFractBits + B2 + (( B5 < N_5_BITS.length )? N_5_BITS[B5] : ( B5*3 )); + + // binary digits needed to represent 10*S, approx. + int tenSbits = S2+1 + (( (S5+1) < N_5_BITS.length )? N_5_BITS[(S5+1)] : ( (S5+1)*3 )); + if ( Bbits < 64 && tenSbits < 64){ + if ( Bbits < 32 && tenSbits < 32){ + // wa-hoo! They're all ints! + int b = ((int)fractBits * FDBigInteger.SMALL_5_POW[B5] ) << B2; + int s = FDBigInteger.SMALL_5_POW[S5] << S2; + int m = FDBigInteger.SMALL_5_POW[M5] << M2; + int tens = s * 10; + // + // Unroll the first iteration. If our decExp estimate + // was too high, our first quotient will be zero. In this + // case, we discard it and decrement decExp. + // + ndigit = 0; + q = b / s; + b = 10 * ( b % s ); + m *= 10; + low = (b < m ); + high = (b+m > tens ); + assert q < 10 : q; // excessively large digit + if ( (q == 0) && ! high ){ + // oops. Usually ignore leading zero. + decExp--; + } else { + digits[ndigit++] = (char)('0' + q); + } + // + // HACK! Java spec sez that we always have at least + // one digit after the . in either F- or E-form output. + // Thus we will need more than one digit if we're using + // E-form + // + if ( !isCompatibleFormat ||decExp < -3 || decExp >= 8 ){ + high = low = false; + } + while( ! low && ! high ){ + q = b / s; + b = 10 * ( b % s ); + m *= 10; + assert q < 10 : q; // excessively large digit + if ( m > 0L ){ + low = (b < m ); + high = (b+m > tens ); + } else { + // hack -- m might overflow! + // in this case, it is certainly > b, + // which won't + // and b+m > tens, too, since that has overflowed + // either! + low = true; + high = true; + } + digits[ndigit++] = (char)('0' + q); + } + lowDigitDifference = (b<<1) - tens; + exactDecimalConversion = (b == 0); + } else { + // still good! they're all longs! + long b = (fractBits * FDBigInteger.LONG_5_POW[B5] ) << B2; + long s = FDBigInteger.LONG_5_POW[S5] << S2; + long m = FDBigInteger.LONG_5_POW[M5] << M2; + long tens = s * 10L; + // + // Unroll the first iteration. If our decExp estimate + // was too high, our first quotient will be zero. In this + // case, we discard it and decrement decExp. + // + ndigit = 0; + q = (int) ( b / s ); + b = 10L * ( b % s ); + m *= 10L; + low = (b < m ); + high = (b+m > tens ); + assert q < 10 : q; // excessively large digit + if ( (q == 0) && ! high ){ + // oops. Usually ignore leading zero. + decExp--; + } else { + digits[ndigit++] = (char)('0' + q); + } + // + // HACK! Java spec sez that we always have at least + // one digit after the . in either F- or E-form output. + // Thus we will need more than one digit if we're using + // E-form + // + if ( !isCompatibleFormat || decExp < -3 || decExp >= 8 ){ + high = low = false; + } + while( ! low && ! high ){ + q = (int) ( b / s ); + b = 10 * ( b % s ); + m *= 10; + assert q < 10 : q; // excessively large digit + if ( m > 0L ){ + low = (b < m ); + high = (b+m > tens ); + } else { + // hack -- m might overflow! + // in this case, it is certainly > b, + // which won't + // and b+m > tens, too, since that has overflowed + // either! + low = true; + high = true; + } + digits[ndigit++] = (char)('0' + q); + } + lowDigitDifference = (b<<1) - tens; + exactDecimalConversion = (b == 0); + } + } else { + // + // We really must do FDBigInteger arithmetic. + // Fist, construct our FDBigInteger initial values. + // + FDBigInteger Sval = FDBigInteger.valueOfPow52(S5, S2); + int shiftBias = Sval.getNormalizationBias(); + Sval = Sval.leftShift(shiftBias); // normalize so that division works better + + FDBigInteger Bval = FDBigInteger.valueOfMulPow52(fractBits, B5, B2 + shiftBias); + FDBigInteger Mval = FDBigInteger.valueOfPow52(M5 + 1, M2 + shiftBias + 1); + + FDBigInteger tenSval = FDBigInteger.valueOfPow52(S5 + 1, S2 + shiftBias + 1); //Sval.mult( 10 ); + // + // Unroll the first iteration. If our decExp estimate + // was too high, our first quotient will be zero. In this + // case, we discard it and decrement decExp. + // + ndigit = 0; + q = Bval.quoRemIteration( Sval ); + low = (Bval.cmp( Mval ) < 0); + high = tenSval.addAndCmp(Bval,Mval)<=0; + + assert q < 10 : q; // excessively large digit + if ( (q == 0) && ! high ){ + // oops. Usually ignore leading zero. + decExp--; + } else { + digits[ndigit++] = (char)('0' + q); + } + // + // HACK! Java spec sez that we always have at least + // one digit after the . in either F- or E-form output. + // Thus we will need more than one digit if we're using + // E-form + // + if (!isCompatibleFormat || decExp < -3 || decExp >= 8 ){ + high = low = false; + } + while( ! low && ! high ){ + q = Bval.quoRemIteration( Sval ); + assert q < 10 : q; // excessively large digit + Mval = Mval.multBy10(); //Mval = Mval.mult( 10 ); + low = (Bval.cmp( Mval ) < 0); + high = tenSval.addAndCmp(Bval,Mval)<=0; + digits[ndigit++] = (char)('0' + q); + } + if ( high && low ){ + Bval = Bval.leftShift(1); + lowDigitDifference = Bval.cmp(tenSval); + } else { + lowDigitDifference = 0L; // this here only for flow analysis! + } + exactDecimalConversion = (Bval.cmp( FDBigInteger.ZERO ) == 0); + } + this.decExponent = decExp+1; + this.firstDigitIndex = 0; + this.nDigits = ndigit; + // + // Last digit gets rounded based on stopping condition. + // + if ( high ){ + if ( low ){ + if ( lowDigitDifference == 0L ){ + // it's a tie! + // choose based on which digits we like. + if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) { + roundup(); + } + } else if ( lowDigitDifference > 0 ){ + roundup(); + } + } else { + roundup(); + } + } + } + + // add one to the least significant digit. + // in the unlikely event there is a carry out, deal with it. + // assert that this will only happen where there + // is only one digit, e.g. (float)1e-44 seems to do it. + // + private void roundup() { + int i = (firstDigitIndex + nDigits - 1); + int q = digits[i]; + if (q == '9') { + while (q == '9' && i > firstDigitIndex) { + digits[i] = '0'; + q = digits[--i]; + } + if (q == '9') { + // carryout! High-order 1, rest 0s, larger exp. + decExponent += 1; + digits[firstDigitIndex] = '1'; + return; + } + // else fall through. + } + digits[i] = (char) (q + 1); + decimalDigitsRoundedUp = true; + } + + /** + * Estimate decimal exponent. (If it is small-ish, + * we could double-check.) + * + * First, scale the mantissa bits such that 1 <= d2 < 2. + * We are then going to estimate + * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5) + * and so we can estimate + * log10(d) ~=~ log10(d2) + binExp * log10(2) + * take the floor and call it decExp. + */ + static int estimateDecExp(long fractBits, int binExp) { + double d2 = Double.longBitsToDouble( EXP_ONE | ( fractBits & DoubleConsts.SIGNIF_BIT_MASK ) ); + double d = (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981; + long dBits = Double.doubleToRawLongBits(d); //can't be NaN here so use raw + int exponent = (int)((dBits & DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT) - DoubleConsts.EXP_BIAS; + boolean isNegative = (dBits & DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign + if(exponent>=0 && exponent<52) { // hot path + long mask = DoubleConsts.SIGNIF_BIT_MASK >> exponent; + int r = (int)(( (dBits&DoubleConsts.SIGNIF_BIT_MASK) | FRACT_HOB )>>(EXP_SHIFT-exponent)); + return isNegative ? (((mask & dBits) == 0L ) ? -r : -r-1 ) : r; + } else if (exponent < 0) { + return (((dBits&~DoubleConsts.SIGN_BIT_MASK) == 0) ? 0 : + ( (isNegative) ? -1 : 0) ); + } else { //if (exponent >= 52) + return (int)d; + } + } + + private static int insignificantDigits(int insignificant) { + int i; + for ( i = 0; insignificant >= 10L; i++ ) { + insignificant /= 10L; + } + return i; + } + + /** + * Calculates + * <pre> + * insignificantDigitsForPow2(v) == insignificantDigits(1L<<v) + * </pre> + */ + private static int insignificantDigitsForPow2(int p2) { + if(p2>1 && p2 < insignificantDigitsNumber.length) { + return insignificantDigitsNumber[p2]; + } + return 0; + } + + /** + * If insignificant==(1L << ixd) + * i = insignificantDigitsNumber[idx] is the same as: + * int i; + * for ( i = 0; insignificant >= 10L; i++ ) + * insignificant /= 10L; + */ + private static int[] insignificantDigitsNumber = { + 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, + 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, + 15, 15, 15, 15, 16, 16, 16, 17, 17, 17, + 18, 18, 18, 19 + }; + + // approximately ceil( log2( long5pow[i] ) ) + private static final int[] N_5_BITS = { + 0, + 3, + 5, + 7, + 10, + 12, + 14, + 17, + 19, + 21, + 24, + 26, + 28, + 31, + 33, + 35, + 38, + 40, + 42, + 45, + 47, + 49, + 52, + 54, + 56, + 59, + 61, + }; + + private int getChars(char[] result) { + assert nDigits <= 19 : nDigits; // generous bound on size of nDigits + int i = 0; + if (isNegative) { + result[0] = '-'; + i = 1; + } + if (decExponent > 0 && decExponent < 8) { + // print digits.digits. + int charLength = Math.min(nDigits, decExponent); + System.arraycopy(digits, firstDigitIndex, result, i, charLength); + i += charLength; + if (charLength < decExponent) { + charLength = decExponent - charLength; + Arrays.fill(result,i,i+charLength,'0'); + i += charLength; + result[i++] = '.'; + result[i++] = '0'; + } else { + result[i++] = '.'; + if (charLength < nDigits) { + int t = nDigits - charLength; + System.arraycopy(digits, firstDigitIndex+charLength, result, i, t); + i += t; + } else { + result[i++] = '0'; + } + } + } else if (decExponent <= 0 && decExponent > -3) { + result[i++] = '0'; + result[i++] = '.'; + if (decExponent != 0) { + Arrays.fill(result, i, i-decExponent, '0'); + i -= decExponent; + } + System.arraycopy(digits, firstDigitIndex, result, i, nDigits); + i += nDigits; + } else { + result[i++] = digits[firstDigitIndex]; + result[i++] = '.'; + if (nDigits > 1) { + System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1); + i += nDigits - 1; + } else { + result[i++] = '0'; + } + result[i++] = 'E'; + int e; + if (decExponent <= 0) { + result[i++] = '-'; + e = -decExponent + 1; + } else { + e = decExponent - 1; + } + // decExponent has 1, 2, or 3, digits + if (e <= 9) { + result[i++] = (char) (e + '0'); + } else if (e <= 99) { + result[i++] = (char) (e / 10 + '0'); + result[i++] = (char) (e % 10 + '0'); + } else { + result[i++] = (char) (e / 100 + '0'); + e %= 100; + result[i++] = (char) (e / 10 + '0'); + result[i++] = (char) (e % 10 + '0'); + } + } + return i; + } + + } + + private static final ThreadLocal<BinaryToASCIIBuffer> threadLocalBinaryToASCIIBuffer = + new ThreadLocal<BinaryToASCIIBuffer>() { + @Override + protected BinaryToASCIIBuffer initialValue() { + return new BinaryToASCIIBuffer(); + } + }; + + private static BinaryToASCIIBuffer getBinaryToASCIIBuffer() { + return threadLocalBinaryToASCIIBuffer.get(); + } + + /** + * A converter which can process an ASCII <code>String</code> representation + * of a single or double precision floating point value into a + * <code>float</code> or a <code>double</code>. + */ + interface ASCIIToBinaryConverter { + + double doubleValue(); + + float floatValue(); + + } + + /** + * A <code>ASCIIToBinaryConverter</code> container for a <code>double</code>. + */ + static class PreparedASCIIToBinaryBuffer implements ASCIIToBinaryConverter { + private final double doubleVal; + private final float floatVal; + + public PreparedASCIIToBinaryBuffer(double doubleVal, float floatVal) { + this.doubleVal = doubleVal; + this.floatVal = floatVal; + } + + @Override + public double doubleValue() { + return doubleVal; + } + + @Override + public float floatValue() { + return floatVal; + } + } + + static final ASCIIToBinaryConverter A2BC_POSITIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.POSITIVE_INFINITY, Float.POSITIVE_INFINITY); + static final ASCIIToBinaryConverter A2BC_NEGATIVE_INFINITY = new PreparedASCIIToBinaryBuffer(Double.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY); + static final ASCIIToBinaryConverter A2BC_NOT_A_NUMBER = new PreparedASCIIToBinaryBuffer(Double.NaN, Float.NaN); + static final ASCIIToBinaryConverter A2BC_POSITIVE_ZERO = new PreparedASCIIToBinaryBuffer(0.0d, 0.0f); + static final ASCIIToBinaryConverter A2BC_NEGATIVE_ZERO = new PreparedASCIIToBinaryBuffer(-0.0d, -0.0f); + + /** + * A buffered implementation of <code>ASCIIToBinaryConverter</code>. + */ + static class ASCIIToBinaryBuffer implements ASCIIToBinaryConverter { + boolean isNegative; + int decExponent; + char digits[]; + int nDigits; + + ASCIIToBinaryBuffer( boolean negSign, int decExponent, char[] digits, int n) + { + this.isNegative = negSign; + this.decExponent = decExponent; + this.digits = digits; + this.nDigits = n; + } + + /** + * Takes a FloatingDecimal, which we presumably just scanned in, + * and finds out what its value is, as a double. + * + * AS A SIDE EFFECT, SET roundDir TO INDICATE PREFERRED + * ROUNDING DIRECTION in case the result is really destined + * for a single-precision float. + */ + @Override + public double doubleValue() { + int kDigits = Math.min(nDigits, MAX_DECIMAL_DIGITS + 1); + // + // convert the lead kDigits to a long integer. + // + // (special performance hack: start to do it using int) + int iValue = (int) digits[0] - (int) '0'; + int iDigits = Math.min(kDigits, INT_DECIMAL_DIGITS); + for (int i = 1; i < iDigits; i++) { + iValue = iValue * 10 + (int) digits[i] - (int) '0'; + } + long lValue = (long) iValue; + for (int i = iDigits; i < kDigits; i++) { + lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0'); + } + double dValue = (double) lValue; + int exp = decExponent - kDigits; + // + // lValue now contains a long integer with the value of + // the first kDigits digits of the number. + // dValue contains the (double) of the same. + // + + if (nDigits <= MAX_DECIMAL_DIGITS) { + // + // possibly an easy case. + // We know that the digits can be represented + // exactly. And if the exponent isn't too outrageous, + // the whole thing can be done with one operation, + // thus one rounding error. + // Note that all our constructors trim all leading and + // trailing zeros, so simple values (including zero) + // will always end up here + // + if (exp == 0 || dValue == 0.0) { + return (isNegative) ? -dValue : dValue; // small floating integer + } + else if (exp >= 0) { + if (exp <= MAX_SMALL_TEN) { + // + // Can get the answer with one operation, + // thus one roundoff. + // + double rValue = dValue * SMALL_10_POW[exp]; + return (isNegative) ? -rValue : rValue; + } + int slop = MAX_DECIMAL_DIGITS - kDigits; + if (exp <= MAX_SMALL_TEN + slop) { + // + // We can multiply dValue by 10^(slop) + // and it is still "small" and exact. + // Then we can multiply by 10^(exp-slop) + // with one rounding. + // + dValue *= SMALL_10_POW[slop]; + double rValue = dValue * SMALL_10_POW[exp - slop]; + return (isNegative) ? -rValue : rValue; + } + // + // Else we have a hard case with a positive exp. + // + } else { + if (exp >= -MAX_SMALL_TEN) { + // + // Can get the answer in one division. + // + double rValue = dValue / SMALL_10_POW[-exp]; + return (isNegative) ? -rValue : rValue; + } + // + // Else we have a hard case with a negative exp. + // + } + } + + // + // Harder cases: + // The sum of digits plus exponent is greater than + // what we think we can do with one error. + // + // Start by approximating the right answer by, + // naively, scaling by powers of 10. + // + if (exp > 0) { + if (decExponent > MAX_DECIMAL_EXPONENT + 1) { + // + // Lets face it. This is going to be + // Infinity. Cut to the chase. + // + return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; + } + if ((exp & 15) != 0) { + dValue *= SMALL_10_POW[exp & 15]; + } + if ((exp >>= 4) != 0) { + int j; + for (j = 0; exp > 1; j++, exp >>= 1) { + if ((exp & 1) != 0) { + dValue *= BIG_10_POW[j]; + } + } + // + // The reason for the weird exp > 1 condition + // in the above loop was so that the last multiply + // would get unrolled. We handle it here. + // It could overflow. + // + double t = dValue * BIG_10_POW[j]; + if (Double.isInfinite(t)) { + // + // It did overflow. + // Look more closely at the result. + // If the exponent is just one too large, + // then use the maximum finite as our estimate + // value. Else call the result infinity + // and punt it. + // ( I presume this could happen because + // rounding forces the result here to be + // an ULP or two larger than + // Double.MAX_VALUE ). + // + t = dValue / 2.0; + t *= BIG_10_POW[j]; + if (Double.isInfinite(t)) { + return (isNegative) ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY; + } + t = Double.MAX_VALUE; + } + dValue = t; + } + } else if (exp < 0) { + exp = -exp; + if (decExponent < MIN_DECIMAL_EXPONENT - 1) { + // + // Lets face it. This is going to be + // zero. Cut to the chase. + // + return (isNegative) ? -0.0 : 0.0; + } + if ((exp & 15) != 0) { + dValue /= SMALL_10_POW[exp & 15]; + } + if ((exp >>= 4) != 0) { + int j; + for (j = 0; exp > 1; j++, exp >>= 1) { + if ((exp & 1) != 0) { + dValue *= TINY_10_POW[j]; + } + } + // + // The reason for the weird exp > 1 condition + // in the above loop was so that the last multiply + // would get unrolled. We handle it here. + // It could underflow. + // + double t = dValue * TINY_10_POW[j]; + if (t == 0.0) { + // + // It did underflow. + // Look more closely at the result. + // If the exponent is just one too small, + // then use the minimum finite as our estimate + // value. Else call the result 0.0 + // and punt it. + // ( I presume this could happen because + // rounding forces the result here to be + // an ULP or two less than + // Double.MIN_VALUE ). + // + t = dValue * 2.0; + t *= TINY_10_POW[j]; + if (t == 0.0) { + return (isNegative) ? -0.0 : 0.0; + } + t = Double.MIN_VALUE; + } + dValue = t; + } + } + + // + // dValue is now approximately the result. + // The hard part is adjusting it, by comparison + // with FDBigInteger arithmetic. + // Formulate the EXACT big-number result as + // bigD0 * 10^exp + // + if (nDigits > MAX_NDIGITS) { + nDigits = MAX_NDIGITS + 1; + digits[MAX_NDIGITS] = '1'; + } + FDBigInteger bigD0 = new FDBigInteger(lValue, digits, kDigits, nDigits); + exp = decExponent - nDigits; + + long ieeeBits = Double.doubleToRawLongBits(dValue); // IEEE-754 bits of double candidate + final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop + final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop + bigD0 = bigD0.multByPow52(D5, 0); + bigD0.makeImmutable(); // prevent bigD0 modification inside correctionLoop + FDBigInteger bigD = null; + int prevD2 = 0; + + correctionLoop: + while (true) { + // here ieeeBits can't be NaN, Infinity or zero + int binexp = (int) (ieeeBits >>> EXP_SHIFT); + long bigBbits = ieeeBits & DoubleConsts.SIGNIF_BIT_MASK; + if (binexp > 0) { + bigBbits |= FRACT_HOB; + } else { // Normalize denormalized numbers. + assert bigBbits != 0L : bigBbits; // doubleToBigInt(0.0) + int leadingZeros = Long.numberOfLeadingZeros(bigBbits); + int shift = leadingZeros - (63 - EXP_SHIFT); + bigBbits <<= shift; + binexp = 1 - shift; + } + binexp -= DoubleConsts.EXP_BIAS; + int lowOrderZeros = Long.numberOfTrailingZeros(bigBbits); + bigBbits >>>= lowOrderZeros; + final int bigIntExp = binexp - EXP_SHIFT + lowOrderZeros; + final int bigIntNBits = EXP_SHIFT + 1 - lowOrderZeros; + + // + // Scale bigD, bigB appropriately for + // big-integer operations. + // Naively, we multiply by powers of ten + // and powers of two. What we actually do + // is keep track of the powers of 5 and + // powers of 2 we would use, then factor out + // common divisors before doing the work. + // + int B2 = B5; // powers of 2 in bigB + int D2 = D5; // powers of 2 in bigD + int Ulp2; // powers of 2 in halfUlp. + if (bigIntExp >= 0) { + B2 += bigIntExp; + } else { + D2 -= bigIntExp; + } + Ulp2 = B2; + // shift bigB and bigD left by a number s. t. + // halfUlp is still an integer. + int hulpbias; + if (binexp <= -DoubleConsts.EXP_BIAS) { + // This is going to be a denormalized number + // (if not actually zero). + // half an ULP is at 2^-(DoubleConsts.EXP_BIAS+EXP_SHIFT+1) + hulpbias = binexp + lowOrderZeros + DoubleConsts.EXP_BIAS; + } else { + hulpbias = 1 + lowOrderZeros; + } + B2 += hulpbias; + D2 += hulpbias; + // if there are common factors of 2, we might just as well + // factor them out, as they add nothing useful. + int common2 = Math.min(B2, Math.min(D2, Ulp2)); + B2 -= common2; + D2 -= common2; + Ulp2 -= common2; + // do multiplications by powers of 5 and 2 + FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2); + if (bigD == null || prevD2 != D2) { + bigD = bigD0.leftShift(D2); + prevD2 = D2; + } + // + // to recap: + // bigB is the scaled-big-int version of our floating-point + // candidate. + // bigD is the scaled-big-int version of the exact value + // as we understand it. + // halfUlp is 1/2 an ulp of bigB, except for special cases + // of exact powers of 2 + // + // the plan is to compare bigB with bigD, and if the difference + // is less than halfUlp, then we're satisfied. Otherwise, + // use the ratio of difference to halfUlp to calculate a fudge + // factor to add to the floating value, then go 'round again. + // + FDBigInteger diff; + int cmpResult; + boolean overvalue; + if ((cmpResult = bigB.cmp(bigD)) > 0) { + overvalue = true; // our candidate is too big. + diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse + if ((bigIntNBits == 1) && (bigIntExp > -DoubleConsts.EXP_BIAS + 1)) { + // candidate is a normalized exact power of 2 and + // is too big (larger than Double.MIN_NORMAL). We will be subtracting. + // For our purposes, ulp is the ulp of the + // next smaller range. + Ulp2 -= 1; + if (Ulp2 < 0) { + // rats. Cannot de-scale ulp this far. + // must scale diff in other direction. + Ulp2 = 0; + diff = diff.leftShift(1); + } + } + } else if (cmpResult < 0) { + overvalue = false; // our candidate is too small. + diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse + } else { + // the candidate is exactly right! + // this happens with surprising frequency + break correctionLoop; + } + cmpResult = diff.cmpPow52(B5, Ulp2); + if ((cmpResult) < 0) { + // difference is small. + // this is close enough + break correctionLoop; + } else if (cmpResult == 0) { + // difference is exactly half an ULP + // round to some other value maybe, then finish + if ((ieeeBits & 1) != 0) { // half ties to even + ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp + } + break correctionLoop; + } else { + // difference is non-trivial. + // could scale addend by ratio of difference to + // halfUlp here, if we bothered to compute that difference. + // Most of the time ( I hope ) it is about 1 anyway. + ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp + if (ieeeBits == 0 || ieeeBits == DoubleConsts.EXP_BIT_MASK) { // 0.0 or Double.POSITIVE_INFINITY + break correctionLoop; // oops. Fell off end of range. + } + continue; // try again. + } + + } + if (isNegative) { + ieeeBits |= DoubleConsts.SIGN_BIT_MASK; + } + return Double.longBitsToDouble(ieeeBits); + } + + /** + * Takes a FloatingDecimal, which we presumably just scanned in, + * and finds out what its value is, as a float. + * This is distinct from doubleValue() to avoid the extremely + * unlikely case of a double rounding error, wherein the conversion + * to double has one rounding error, and the conversion of that double + * to a float has another rounding error, IN THE WRONG DIRECTION, + * ( because of the preference to a zero low-order bit ). + */ + @Override + public float floatValue() { + int kDigits = Math.min(nDigits, SINGLE_MAX_DECIMAL_DIGITS + 1); + // + // convert the lead kDigits to an integer. + // + int iValue = (int) digits[0] - (int) '0'; + for (int i = 1; i < kDigits; i++) { + iValue = iValue * 10 + (int) digits[i] - (int) '0'; + } + float fValue = (float) iValue; + int exp = decExponent - kDigits; + // + // iValue now contains an integer with the value of + // the first kDigits digits of the number. + // fValue contains the (float) of the same. + // + + if (nDigits <= SINGLE_MAX_DECIMAL_DIGITS) { + // + // possibly an easy case. + // We know that the digits can be represented + // exactly. And if the exponent isn't too outrageous, + // the whole thing can be done with one operation, + // thus one rounding error. + // Note that all our constructors trim all leading and + // trailing zeros, so simple values (including zero) + // will always end up here. + // + if (exp == 0 || fValue == 0.0f) { + return (isNegative) ? -fValue : fValue; // small floating integer + } else if (exp >= 0) { + if (exp <= SINGLE_MAX_SMALL_TEN) { + // + // Can get the answer with one operation, + // thus one roundoff. + // + fValue *= SINGLE_SMALL_10_POW[exp]; + return (isNegative) ? -fValue : fValue; + } + int slop = SINGLE_MAX_DECIMAL_DIGITS - kDigits; + if (exp <= SINGLE_MAX_SMALL_TEN + slop) { + // + // We can multiply fValue by 10^(slop) + // and it is still "small" and exact. + // Then we can multiply by 10^(exp-slop) + // with one rounding. + // + fValue *= SINGLE_SMALL_10_POW[slop]; + fValue *= SINGLE_SMALL_10_POW[exp - slop]; + return (isNegative) ? -fValue : fValue; + } + // + // Else we have a hard case with a positive exp. + // + } else { + if (exp >= -SINGLE_MAX_SMALL_TEN) { + // + // Can get the answer in one division. + // + fValue /= SINGLE_SMALL_10_POW[-exp]; + return (isNegative) ? -fValue : fValue; + } + // + // Else we have a hard case with a negative exp. + // + } + } else if ((decExponent >= nDigits) && (nDigits + decExponent <= MAX_DECIMAL_DIGITS)) { + // + // In double-precision, this is an exact floating integer. + // So we can compute to double, then shorten to float + // with one round, and get the right answer. + // + // First, finish accumulating digits. + // Then convert that integer to a double, multiply + // by the appropriate power of ten, and convert to float. + // + long lValue = (long) iValue; + for (int i = kDigits; i < nDigits; i++) { + lValue = lValue * 10L + (long) ((int) digits[i] - (int) '0'); + } + double dValue = (double) lValue; + exp = decExponent - nDigits; + dValue *= SMALL_10_POW[exp]; + fValue = (float) dValue; + return (isNegative) ? -fValue : fValue; + + } + // + // Harder cases: + // The sum of digits plus exponent is greater than + // what we think we can do with one error. + // + // Start by approximating the right answer by, + // naively, scaling by powers of 10. + // Scaling uses doubles to avoid overflow/underflow. + // + double dValue = fValue; + if (exp > 0) { + if (decExponent > SINGLE_MAX_DECIMAL_EXPONENT + 1) { + // + // Lets face it. This is going to be + // Infinity. Cut to the chase. + // + return (isNegative) ? Float.NEGATIVE_INFINITY : Float.POSITIVE_INFINITY; + } + if ((exp & 15) != 0) { + dValue *= SMALL_10_POW[exp & 15]; + } + if ((exp >>= 4) != 0) { + int j; + for (j = 0; exp > 0; j++, exp >>= 1) { + if ((exp & 1) != 0) { + dValue *= BIG_10_POW[j]; + } + } + } + } else if (exp < 0) { + exp = -exp; + if (decExponent < SINGLE_MIN_DECIMAL_EXPONENT - 1) { + // + // Lets face it. This is going to be + // zero. Cut to the chase. + // + return (isNegative) ? -0.0f : 0.0f; + } + if ((exp & 15) != 0) { + dValue /= SMALL_10_POW[exp & 15]; + } + if ((exp >>= 4) != 0) { + int j; + for (j = 0; exp > 0; j++, exp >>= 1) { + if ((exp & 1) != 0) { + dValue *= TINY_10_POW[j]; + } + } + } + } + fValue = Math.max(Float.MIN_VALUE, Math.min(Float.MAX_VALUE, (float) dValue)); + + // + // fValue is now approximately the result. + // The hard part is adjusting it, by comparison + // with FDBigInteger arithmetic. + // Formulate the EXACT big-number result as + // bigD0 * 10^exp + // + if (nDigits > SINGLE_MAX_NDIGITS) { + nDigits = SINGLE_MAX_NDIGITS + 1; + digits[SINGLE_MAX_NDIGITS] = '1'; + } + FDBigInteger bigD0 = new FDBigInteger(iValue, digits, kDigits, nDigits); + exp = decExponent - nDigits; + + int ieeeBits = Float.floatToRawIntBits(fValue); // IEEE-754 bits of float candidate + final int B5 = Math.max(0, -exp); // powers of 5 in bigB, value is not modified inside correctionLoop + final int D5 = Math.max(0, exp); // powers of 5 in bigD, value is not modified inside correctionLoop + bigD0 = bigD0.multByPow52(D5, 0); + bigD0.makeImmutable(); // prevent bigD0 modification inside correctionLoop + FDBigInteger bigD = null; + int prevD2 = 0; + + correctionLoop: + while (true) { + // here ieeeBits can't be NaN, Infinity or zero + int binexp = ieeeBits >>> SINGLE_EXP_SHIFT; + int bigBbits = ieeeBits & FloatConsts.SIGNIF_BIT_MASK; + if (binexp > 0) { + bigBbits |= SINGLE_FRACT_HOB; + } else { // Normalize denormalized numbers. + assert bigBbits != 0 : bigBbits; // floatToBigInt(0.0) + int leadingZeros = Integer.numberOfLeadingZeros(bigBbits); + int shift = leadingZeros - (31 - SINGLE_EXP_SHIFT); + bigBbits <<= shift; + binexp = 1 - shift; + } + binexp -= FloatConsts.EXP_BIAS; + int lowOrderZeros = Integer.numberOfTrailingZeros(bigBbits); + bigBbits >>>= lowOrderZeros; + final int bigIntExp = binexp - SINGLE_EXP_SHIFT + lowOrderZeros; + final int bigIntNBits = SINGLE_EXP_SHIFT + 1 - lowOrderZeros; + + // + // Scale bigD, bigB appropriately for + // big-integer operations. + // Naively, we multiply by powers of ten + // and powers of two. What we actually do + // is keep track of the powers of 5 and + // powers of 2 we would use, then factor out + // common divisors before doing the work. + // + int B2 = B5; // powers of 2 in bigB + int D2 = D5; // powers of 2 in bigD + int Ulp2; // powers of 2 in halfUlp. + if (bigIntExp >= 0) { + B2 += bigIntExp; + } else { + D2 -= bigIntExp; + } + Ulp2 = B2; + // shift bigB and bigD left by a number s. t. + // halfUlp is still an integer. + int hulpbias; + if (binexp <= -FloatConsts.EXP_BIAS) { + // This is going to be a denormalized number + // (if not actually zero). + // half an ULP is at 2^-(FloatConsts.EXP_BIAS+SINGLE_EXP_SHIFT+1) + hulpbias = binexp + lowOrderZeros + FloatConsts.EXP_BIAS; + } else { + hulpbias = 1 + lowOrderZeros; + } + B2 += hulpbias; + D2 += hulpbias; + // if there are common factors of 2, we might just as well + // factor them out, as they add nothing useful. + int common2 = Math.min(B2, Math.min(D2, Ulp2)); + B2 -= common2; + D2 -= common2; + Ulp2 -= common2; + // do multiplications by powers of 5 and 2 + FDBigInteger bigB = FDBigInteger.valueOfMulPow52(bigBbits, B5, B2); + if (bigD == null || prevD2 != D2) { + bigD = bigD0.leftShift(D2); + prevD2 = D2; + } + // + // to recap: + // bigB is the scaled-big-int version of our floating-point + // candidate. + // bigD is the scaled-big-int version of the exact value + // as we understand it. + // halfUlp is 1/2 an ulp of bigB, except for special cases + // of exact powers of 2 + // + // the plan is to compare bigB with bigD, and if the difference + // is less than halfUlp, then we're satisfied. Otherwise, + // use the ratio of difference to halfUlp to calculate a fudge + // factor to add to the floating value, then go 'round again. + // + FDBigInteger diff; + int cmpResult; + boolean overvalue; + if ((cmpResult = bigB.cmp(bigD)) > 0) { + overvalue = true; // our candidate is too big. + diff = bigB.leftInplaceSub(bigD); // bigB is not user further - reuse + if ((bigIntNBits == 1) && (bigIntExp > -FloatConsts.EXP_BIAS + 1)) { + // candidate is a normalized exact power of 2 and + // is too big (larger than Float.MIN_NORMAL). We will be subtracting. + // For our purposes, ulp is the ulp of the + // next smaller range. + Ulp2 -= 1; + if (Ulp2 < 0) { + // rats. Cannot de-scale ulp this far. + // must scale diff in other direction. + Ulp2 = 0; + diff = diff.leftShift(1); + } + } + } else if (cmpResult < 0) { + overvalue = false; // our candidate is too small. + diff = bigD.rightInplaceSub(bigB); // bigB is not user further - reuse + } else { + // the candidate is exactly right! + // this happens with surprising frequency + break correctionLoop; + } + cmpResult = diff.cmpPow52(B5, Ulp2); + if ((cmpResult) < 0) { + // difference is small. + // this is close enough + break correctionLoop; + } else if (cmpResult == 0) { + // difference is exactly half an ULP + // round to some other value maybe, then finish + if ((ieeeBits & 1) != 0) { // half ties to even + ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp + } + break correctionLoop; + } else { + // difference is non-trivial. + // could scale addend by ratio of difference to + // halfUlp here, if we bothered to compute that difference. + // Most of the time ( I hope ) it is about 1 anyway. + ieeeBits += overvalue ? -1 : 1; // nextDown or nextUp + if (ieeeBits == 0 || ieeeBits == FloatConsts.EXP_BIT_MASK) { // 0.0 or Float.POSITIVE_INFINITY + break correctionLoop; // oops. Fell off end of range. + } + continue; // try again. + } + + } + if (isNegative) { + ieeeBits |= FloatConsts.SIGN_BIT_MASK; + } + return Float.intBitsToFloat(ieeeBits); + } + + + /** + * All the positive powers of 10 that can be + * represented exactly in double/float. + */ + private static final double[] SMALL_10_POW = { + 1.0e0, + 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, + 1.0e6, 1.0e7, 1.0e8, 1.0e9, 1.0e10, + 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, + 1.0e16, 1.0e17, 1.0e18, 1.0e19, 1.0e20, + 1.0e21, 1.0e22 + }; + + private static final float[] SINGLE_SMALL_10_POW = { + 1.0e0f, + 1.0e1f, 1.0e2f, 1.0e3f, 1.0e4f, 1.0e5f, + 1.0e6f, 1.0e7f, 1.0e8f, 1.0e9f, 1.0e10f + }; + + private static final double[] BIG_10_POW = { + 1e16, 1e32, 1e64, 1e128, 1e256 }; + private static final double[] TINY_10_POW = { + 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 }; + + private static final int MAX_SMALL_TEN = SMALL_10_POW.length-1; + private static final int SINGLE_MAX_SMALL_TEN = SINGLE_SMALL_10_POW.length-1; + + } + + /** + * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>. + * The returned object is a <code>ThreadLocal</code> variable of this class. + * + * @param d The double precision value to convert. + * @return The converter. + */ + public static BinaryToASCIIConverter getBinaryToASCIIConverter(double d) { + return getBinaryToASCIIConverter(d, true); + } + + /** + * Returns a <code>BinaryToASCIIConverter</code> for a <code>double</code>. + * The returned object is a <code>ThreadLocal</code> variable of this class. + * + * @param d The double precision value to convert. + * @param isCompatibleFormat + * @return The converter. + */ + static BinaryToASCIIConverter getBinaryToASCIIConverter(double d, boolean isCompatibleFormat) { + long dBits = Double.doubleToRawLongBits(d); + boolean isNegative = (dBits&DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign + long fractBits = dBits & DoubleConsts.SIGNIF_BIT_MASK; + int binExp = (int)( (dBits&DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT ); + // Discover obvious special cases of NaN and Infinity. + if ( binExp == (int)(DoubleConsts.EXP_BIT_MASK>>EXP_SHIFT) ) { + if ( fractBits == 0L ){ + return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY; + } else { + return B2AC_NOT_A_NUMBER; + } + } + // Finish unpacking + // Normalize denormalized numbers. + // Insert assumed high-order bit for normalized numbers. + // Subtract exponent bias. + int nSignificantBits; + if ( binExp == 0 ){ + if ( fractBits == 0L ){ + // not a denorm, just a 0! + return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO; + } + int leadingZeros = Long.numberOfLeadingZeros(fractBits); + int shift = leadingZeros-(63-EXP_SHIFT); + fractBits <<= shift; + binExp = 1 - shift; + nSignificantBits = 64-leadingZeros; // recall binExp is - shift count. + } else { + fractBits |= FRACT_HOB; + nSignificantBits = EXP_SHIFT+1; + } + binExp -= DoubleConsts.EXP_BIAS; + BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer(); + buf.setSign(isNegative); + // call the routine that actually does all the hard work. + buf.dtoa(binExp, fractBits, nSignificantBits, isCompatibleFormat); + return buf; + } + + private static BinaryToASCIIConverter getBinaryToASCIIConverter(float f) { + int fBits = Float.floatToRawIntBits( f ); + boolean isNegative = (fBits&FloatConsts.SIGN_BIT_MASK) != 0; + int fractBits = fBits&FloatConsts.SIGNIF_BIT_MASK; + int binExp = (fBits&FloatConsts.EXP_BIT_MASK) >> SINGLE_EXP_SHIFT; + // Discover obvious special cases of NaN and Infinity. + if ( binExp == (FloatConsts.EXP_BIT_MASK>>SINGLE_EXP_SHIFT) ) { + if ( fractBits == 0L ){ + return isNegative ? B2AC_NEGATIVE_INFINITY : B2AC_POSITIVE_INFINITY; + } else { + return B2AC_NOT_A_NUMBER; + } + } + // Finish unpacking + // Normalize denormalized numbers. + // Insert assumed high-order bit for normalized numbers. + // Subtract exponent bias. + int nSignificantBits; + if ( binExp == 0 ){ + if ( fractBits == 0 ){ + // not a denorm, just a 0! + return isNegative ? B2AC_NEGATIVE_ZERO : B2AC_POSITIVE_ZERO; + } + int leadingZeros = Integer.numberOfLeadingZeros(fractBits); + int shift = leadingZeros-(31-SINGLE_EXP_SHIFT); + fractBits <<= shift; + binExp = 1 - shift; + nSignificantBits = 32 - leadingZeros; // recall binExp is - shift count. + } else { + fractBits |= SINGLE_FRACT_HOB; + nSignificantBits = SINGLE_EXP_SHIFT+1; + } + binExp -= FloatConsts.EXP_BIAS; + BinaryToASCIIBuffer buf = getBinaryToASCIIBuffer(); + buf.setSign(isNegative); + // call the routine that actually does all the hard work. + buf.dtoa(binExp, ((long)fractBits)<<(EXP_SHIFT-SINGLE_EXP_SHIFT), nSignificantBits, true); + return buf; + } + + @SuppressWarnings("fallthrough") + static ASCIIToBinaryConverter readJavaFormatString( String in ) throws NumberFormatException { + boolean isNegative = false; + boolean signSeen = false; + int decExp; + char c; + + parseNumber: + try{ + in = in.trim(); // don't fool around with white space. + // throws NullPointerException if null + int len = in.length(); + if ( len == 0 ) { + throw new NumberFormatException("empty String"); + } + int i = 0; + switch (in.charAt(i)){ + case '-': + isNegative = true; + //FALLTHROUGH + case '+': + i++; + signSeen = true; + } + c = in.charAt(i); + if(c == 'N') { // Check for NaN + if((len-i)==NAN_LENGTH && in.indexOf(NAN_REP,i)==i) { + return A2BC_NOT_A_NUMBER; + } + // something went wrong, throw exception + break parseNumber; + } else if(c == 'I') { // Check for Infinity strings + if((len-i)==INFINITY_LENGTH && in.indexOf(INFINITY_REP,i)==i) { + return isNegative? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY; + } + // something went wrong, throw exception + break parseNumber; + } else if (c == '0') { // check for hexadecimal floating-point number + if (len > i+1 ) { + char ch = in.charAt(i+1); + if (ch == 'x' || ch == 'X' ) { // possible hex string + return parseHexString(in); + } + } + } // look for and process decimal floating-point string + + char[] digits = new char[ len ]; + int nDigits= 0; + boolean decSeen = false; + int decPt = 0; + int nLeadZero = 0; + int nTrailZero= 0; + + skipLeadingZerosLoop: + while (i < len) { + c = in.charAt(i); + if (c == '0') { + nLeadZero++; + } else if (c == '.') { + if (decSeen) { + // already saw one ., this is the 2nd. + throw new NumberFormatException("multiple points"); + } + decPt = i; + if (signSeen) { + decPt -= 1; + } + decSeen = true; + } else { + break skipLeadingZerosLoop; + } + i++; + } + digitLoop: + while (i < len) { + c = in.charAt(i); + if (c >= '1' && c <= '9') { + digits[nDigits++] = c; + nTrailZero = 0; + } else if (c == '0') { + digits[nDigits++] = c; + nTrailZero++; + } else if (c == '.') { + if (decSeen) { + // already saw one ., this is the 2nd. + throw new NumberFormatException("multiple points"); + } + decPt = i; + if (signSeen) { + decPt -= 1; + } + decSeen = true; + } else { + break digitLoop; + } + i++; + } + nDigits -=nTrailZero; + // + // At this point, we've scanned all the digits and decimal + // point we're going to see. Trim off leading and trailing + // zeros, which will just confuse us later, and adjust + // our initial decimal exponent accordingly. + // To review: + // we have seen i total characters. + // nLeadZero of them were zeros before any other digits. + // nTrailZero of them were zeros after any other digits. + // if ( decSeen ), then a . was seen after decPt characters + // ( including leading zeros which have been discarded ) + // nDigits characters were neither lead nor trailing + // zeros, nor point + // + // + // special hack: if we saw no non-zero digits, then the + // answer is zero! + // Unfortunately, we feel honor-bound to keep parsing! + // + boolean isZero = (nDigits == 0); + if ( isZero && nLeadZero == 0 ){ + // we saw NO DIGITS AT ALL, + // not even a crummy 0! + // this is not allowed. + break parseNumber; // go throw exception + } + // + // Our initial exponent is decPt, adjusted by the number of + // discarded zeros. Or, if there was no decPt, + // then its just nDigits adjusted by discarded trailing zeros. + // + if ( decSeen ){ + decExp = decPt - nLeadZero; + } else { + decExp = nDigits + nTrailZero; + } + + // + // Look for 'e' or 'E' and an optionally signed integer. + // + if ( (i < len) && (((c = in.charAt(i) )=='e') || (c == 'E') ) ){ + int expSign = 1; + int expVal = 0; + int reallyBig = Integer.MAX_VALUE / 10; + boolean expOverflow = false; + switch( in.charAt(++i) ){ + case '-': + expSign = -1; + //FALLTHROUGH + case '+': + i++; + } + int expAt = i; + expLoop: + while ( i < len ){ + if ( expVal >= reallyBig ){ + // the next character will cause integer + // overflow. + expOverflow = true; + } + c = in.charAt(i++); + if(c>='0' && c<='9') { + expVal = expVal*10 + ( (int)c - (int)'0' ); + } else { + i--; // back up. + break expLoop; // stop parsing exponent. + } + } + int expLimit = BIG_DECIMAL_EXPONENT + nDigits + nTrailZero; + if (expOverflow || (expVal > expLimit)) { + // There is still a chance that the exponent will be safe to + // use: if it would eventually decrease due to a negative + // decExp, and that number is below the limit. We check for + // that here. + if (!expOverflow && (expSign == 1 && decExp < 0) + && (expVal + decExp) < expLimit) { + // Cannot overflow: adding a positive and negative number. + decExp += expVal; + } else { + // + // The intent here is to end up with + // infinity or zero, as appropriate. + // The reason for yielding such a small decExponent, + // rather than something intuitive such as + // expSign*Integer.MAX_VALUE, is that this value + // is subject to further manipulation in + // doubleValue() and floatValue(), and I don't want + // it to be able to cause overflow there! + // (The only way we can get into trouble here is for + // really outrageous nDigits+nTrailZero, such as 2 + // billion.) + // + decExp = expSign * expLimit; + } + } else { + // this should not overflow, since we tested + // for expVal > (MAX+N), where N >= abs(decExp) + decExp = decExp + expSign*expVal; + } + + // if we saw something not a digit ( or end of string ) + // after the [Ee][+-], without seeing any digits at all + // this is certainly an error. If we saw some digits, + // but then some trailing garbage, that might be ok. + // so we just fall through in that case. + // HUMBUG + if ( i == expAt ) { + break parseNumber; // certainly bad + } + } + // + // We parsed everything we could. + // If there are leftovers, then this is not good input! + // + if ( i < len && + ((i != len - 1) || + (in.charAt(i) != 'f' && + in.charAt(i) != 'F' && + in.charAt(i) != 'd' && + in.charAt(i) != 'D'))) { + break parseNumber; // go throw exception + } + if(isZero) { + return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO; + } + return new ASCIIToBinaryBuffer(isNegative, decExp, digits, nDigits); + } catch ( StringIndexOutOfBoundsException e ){ } + throw new NumberFormatException("For input string: \"" + in + "\""); + } + + private static class HexFloatPattern { + /** + * Grammar is compatible with hexadecimal floating-point constants + * described in section 6.4.4.2 of the C99 specification. + */ + private static final Pattern VALUE = Pattern.compile( + //1 234 56 7 8 9 + "([-+])?0[xX](((\\p{XDigit}+)\\.?)|((\\p{XDigit}*)\\.(\\p{XDigit}+)))[pP]([-+])?(\\p{Digit}+)[fFdD]?" + ); + } + + /** + * Converts string s to a suitable floating decimal; uses the + * double constructor and sets the roundDir variable appropriately + * in case the value is later converted to a float. + * + * @param s The <code>String</code> to parse. + */ + static ASCIIToBinaryConverter parseHexString(String s) { + // Verify string is a member of the hexadecimal floating-point + // string language. + Matcher m = HexFloatPattern.VALUE.matcher(s); + boolean validInput = m.matches(); + if (!validInput) { + // Input does not match pattern + throw new NumberFormatException("For input string: \"" + s + "\""); + } else { // validInput + // + // We must isolate the sign, significand, and exponent + // fields. The sign value is straightforward. Since + // floating-point numbers are stored with a normalized + // representation, the significand and exponent are + // interrelated. + // + // After extracting the sign, we normalized the + // significand as a hexadecimal value, calculating an + // exponent adjust for any shifts made during + // normalization. If the significand is zero, the + // exponent doesn't need to be examined since the output + // will be zero. + // + // Next the exponent in the input string is extracted. + // Afterwards, the significand is normalized as a *binary* + // value and the input value's normalized exponent can be + // computed. The significand bits are copied into a + // double significand; if the string has more logical bits + // than can fit in a double, the extra bits affect the + // round and sticky bits which are used to round the final + // value. + // + // Extract significand sign + String group1 = m.group(1); + boolean isNegative = ((group1 != null) && group1.equals("-")); + + // Extract Significand magnitude + // + // Based on the form of the significand, calculate how the + // binary exponent needs to be adjusted to create a + // normalized//hexadecimal* floating-point number; that + // is, a number where there is one nonzero hex digit to + // the left of the (hexa)decimal point. Since we are + // adjusting a binary, not hexadecimal exponent, the + // exponent is adjusted by a multiple of 4. + // + // There are a number of significand scenarios to consider; + // letters are used in indicate nonzero digits: + // + // 1. 000xxxx => x.xxx normalized + // increase exponent by (number of x's - 1)*4 + // + // 2. 000xxx.yyyy => x.xxyyyy normalized + // increase exponent by (number of x's - 1)*4 + // + // 3. .000yyy => y.yy normalized + // decrease exponent by (number of zeros + 1)*4 + // + // 4. 000.00000yyy => y.yy normalized + // decrease exponent by (number of zeros to right of point + 1)*4 + // + // If the significand is exactly zero, return a properly + // signed zero. + // + + String significandString = null; + int signifLength = 0; + int exponentAdjust = 0; + { + int leftDigits = 0; // number of meaningful digits to + // left of "decimal" point + // (leading zeros stripped) + int rightDigits = 0; // number of digits to right of + // "decimal" point; leading zeros + // must always be accounted for + // + // The significand is made up of either + // + // 1. group 4 entirely (integer portion only) + // + // OR + // + // 2. the fractional portion from group 7 plus any + // (optional) integer portions from group 6. + // + String group4; + if ((group4 = m.group(4)) != null) { // Integer-only significand + // Leading zeros never matter on the integer portion + significandString = stripLeadingZeros(group4); + leftDigits = significandString.length(); + } else { + // Group 6 is the optional integer; leading zeros + // never matter on the integer portion + String group6 = stripLeadingZeros(m.group(6)); + leftDigits = group6.length(); + + // fraction + String group7 = m.group(7); + rightDigits = group7.length(); + + // Turn "integer.fraction" into "integer"+"fraction" + significandString = + ((group6 == null) ? "" : group6) + // is the null + // check necessary? + group7; + } + + significandString = stripLeadingZeros(significandString); + signifLength = significandString.length(); + + // + // Adjust exponent as described above + // + if (leftDigits >= 1) { // Cases 1 and 2 + exponentAdjust = 4 * (leftDigits - 1); + } else { // Cases 3 and 4 + exponentAdjust = -4 * (rightDigits - signifLength + 1); + } + + // If the significand is zero, the exponent doesn't + // matter; return a properly signed zero. + + if (signifLength == 0) { // Only zeros in input + return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO; + } + } + + // Extract Exponent + // + // Use an int to read in the exponent value; this should + // provide more than sufficient range for non-contrived + // inputs. If reading the exponent in as an int does + // overflow, examine the sign of the exponent and + // significand to determine what to do. + // + String group8 = m.group(8); + boolean positiveExponent = (group8 == null) || group8.equals("+"); + long unsignedRawExponent; + try { + unsignedRawExponent = Integer.parseInt(m.group(9)); + } + catch (NumberFormatException e) { + // At this point, we know the exponent is + // syntactically well-formed as a sequence of + // digits. Therefore, if an NumberFormatException + // is thrown, it must be due to overflowing int's + // range. Also, at this point, we have already + // checked for a zero significand. Thus the signs + // of the exponent and significand determine the + // final result: + // + // significand + // + - + // exponent + +infinity -infinity + // - +0.0 -0.0 + return isNegative ? + (positiveExponent ? A2BC_NEGATIVE_INFINITY : A2BC_NEGATIVE_ZERO) + : (positiveExponent ? A2BC_POSITIVE_INFINITY : A2BC_POSITIVE_ZERO); + + } + + long rawExponent = + (positiveExponent ? 1L : -1L) * // exponent sign + unsignedRawExponent; // exponent magnitude + + // Calculate partially adjusted exponent + long exponent = rawExponent + exponentAdjust; + + // Starting copying non-zero bits into proper position in + // a long; copy explicit bit too; this will be masked + // later for normal values. + + boolean round = false; + boolean sticky = false; + int nextShift = 0; + long significand = 0L; + // First iteration is different, since we only copy + // from the leading significand bit; one more exponent + // adjust will be needed... + + // IMPORTANT: make leadingDigit a long to avoid + // surprising shift semantics! + long leadingDigit = getHexDigit(significandString, 0); + + // + // Left shift the leading digit (53 - (bit position of + // leading 1 in digit)); this sets the top bit of the + // significand to 1. The nextShift value is adjusted + // to take into account the number of bit positions of + // the leadingDigit actually used. Finally, the + // exponent is adjusted to normalize the significand + // as a binary value, not just a hex value. + // + if (leadingDigit == 1) { + significand |= leadingDigit << 52; + nextShift = 52 - 4; + // exponent += 0 + } else if (leadingDigit <= 3) { // [2, 3] + significand |= leadingDigit << 51; + nextShift = 52 - 5; + exponent += 1; + } else if (leadingDigit <= 7) { // [4, 7] + significand |= leadingDigit << 50; + nextShift = 52 - 6; + exponent += 2; + } else if (leadingDigit <= 15) { // [8, f] + significand |= leadingDigit << 49; + nextShift = 52 - 7; + exponent += 3; + } else { + throw new AssertionError("Result from digit conversion too large!"); + } + // The preceding if-else could be replaced by a single + // code block based on the high-order bit set in + // leadingDigit. Given leadingOnePosition, + + // significand |= leadingDigit << (SIGNIFICAND_WIDTH - leadingOnePosition); + // nextShift = 52 - (3 + leadingOnePosition); + // exponent += (leadingOnePosition-1); + + // + // Now the exponent variable is equal to the normalized + // binary exponent. Code below will make representation + // adjustments if the exponent is incremented after + // rounding (includes overflows to infinity) or if the + // result is subnormal. + // + + // Copy digit into significand until the significand can't + // hold another full hex digit or there are no more input + // hex digits. + int i = 0; + for (i = 1; + i < signifLength && nextShift >= 0; + i++) { + long currentDigit = getHexDigit(significandString, i); + significand |= (currentDigit << nextShift); + nextShift -= 4; + } + + // After the above loop, the bulk of the string is copied. + // Now, we must copy any partial hex digits into the + // significand AND compute the round bit and start computing + // sticky bit. + + if (i < signifLength) { // at least one hex input digit exists + long currentDigit = getHexDigit(significandString, i); + + // from nextShift, figure out how many bits need + // to be copied, if any + switch (nextShift) { // must be negative + case -1: + // three bits need to be copied in; can + // set round bit + significand |= ((currentDigit & 0xEL) >> 1); + round = (currentDigit & 0x1L) != 0L; + break; + + case -2: + // two bits need to be copied in; can + // set round and start sticky + significand |= ((currentDigit & 0xCL) >> 2); + round = (currentDigit & 0x2L) != 0L; + sticky = (currentDigit & 0x1L) != 0; + break; + + case -3: + // one bit needs to be copied in + significand |= ((currentDigit & 0x8L) >> 3); + // Now set round and start sticky, if possible + round = (currentDigit & 0x4L) != 0L; + sticky = (currentDigit & 0x3L) != 0; + break; + + case -4: + // all bits copied into significand; set + // round and start sticky + round = ((currentDigit & 0x8L) != 0); // is top bit set? + // nonzeros in three low order bits? + sticky = (currentDigit & 0x7L) != 0; + break; + + default: + throw new AssertionError("Unexpected shift distance remainder."); + // break; + } + + // Round is set; sticky might be set. + + // For the sticky bit, it suffices to check the + // current digit and test for any nonzero digits in + // the remaining unprocessed input. + i++; + while (i < signifLength && !sticky) { + currentDigit = getHexDigit(significandString, i); + sticky = sticky || (currentDigit != 0); + i++; + } + + } + // else all of string was seen, round and sticky are + // correct as false. + + // Float calculations + int floatBits = isNegative ? FloatConsts.SIGN_BIT_MASK : 0; + if (exponent >= FloatConsts.MIN_EXPONENT) { + if (exponent > FloatConsts.MAX_EXPONENT) { + // Float.POSITIVE_INFINITY + floatBits |= FloatConsts.EXP_BIT_MASK; + } else { + int threshShift = DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH - 1; + boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky; + int iValue = (int) (significand >>> threshShift); + if ((iValue & 3) != 1 || floatSticky) { + iValue++; + } + floatBits |= (((((int) exponent) + (FloatConsts.EXP_BIAS - 1))) << SINGLE_EXP_SHIFT) + (iValue >> 1); + } + } else { + if (exponent < FloatConsts.MIN_SUB_EXPONENT - 1) { + // 0 + } else { + // exponent == -127 ==> threshShift = 53 - 2 + (-149) - (-127) = 53 - 24 + int threshShift = (int) ((DoubleConsts.SIGNIFICAND_WIDTH - 2 + FloatConsts.MIN_SUB_EXPONENT) - exponent); + assert threshShift >= DoubleConsts.SIGNIFICAND_WIDTH - FloatConsts.SIGNIFICAND_WIDTH; + assert threshShift < DoubleConsts.SIGNIFICAND_WIDTH; + boolean floatSticky = (significand & ((1L << threshShift) - 1)) != 0 || round || sticky; + int iValue = (int) (significand >>> threshShift); + if ((iValue & 3) != 1 || floatSticky) { + iValue++; + } + floatBits |= iValue >> 1; + } + } + float fValue = Float.intBitsToFloat(floatBits); + + // Check for overflow and update exponent accordingly. + if (exponent > DoubleConsts.MAX_EXPONENT) { // Infinite result + // overflow to properly signed infinity + return isNegative ? A2BC_NEGATIVE_INFINITY : A2BC_POSITIVE_INFINITY; + } else { // Finite return value + if (exponent <= DoubleConsts.MAX_EXPONENT && // (Usually) normal result + exponent >= DoubleConsts.MIN_EXPONENT) { + + // The result returned in this block cannot be a + // zero or subnormal; however after the + // significand is adjusted from rounding, we could + // still overflow in infinity. + + // AND exponent bits into significand; if the + // significand is incremented and overflows from + // rounding, this combination will update the + // exponent correctly, even in the case of + // Double.MAX_VALUE overflowing to infinity. + + significand = ((( exponent + + (long) DoubleConsts.EXP_BIAS) << + (DoubleConsts.SIGNIFICAND_WIDTH - 1)) + & DoubleConsts.EXP_BIT_MASK) | + (DoubleConsts.SIGNIF_BIT_MASK & significand); + + } else { // Subnormal or zero + // (exponent < DoubleConsts.MIN_EXPONENT) + + if (exponent < (DoubleConsts.MIN_SUB_EXPONENT - 1)) { + // No way to round back to nonzero value + // regardless of significand if the exponent is + // less than -1075. + return isNegative ? A2BC_NEGATIVE_ZERO : A2BC_POSITIVE_ZERO; + } else { // -1075 <= exponent <= MIN_EXPONENT -1 = -1023 + // + // Find bit position to round to; recompute + // round and sticky bits, and shift + // significand right appropriately. + // + + sticky = sticky || round; + round = false; + + // Number of bits of significand to preserve is + // exponent - abs_min_exp +1 + // check: + // -1075 +1074 + 1 = 0 + // -1023 +1074 + 1 = 52 + + int bitsDiscarded = 53 - + ((int) exponent - DoubleConsts.MIN_SUB_EXPONENT + 1); + assert bitsDiscarded >= 1 && bitsDiscarded <= 53; + + // What to do here: + // First, isolate the new round bit + round = (significand & (1L << (bitsDiscarded - 1))) != 0L; + if (bitsDiscarded > 1) { + // create mask to update sticky bits; low + // order bitsDiscarded bits should be 1 + long mask = ~((~0L) << (bitsDiscarded - 1)); + sticky = sticky || ((significand & mask) != 0L); + } + + // Now, discard the bits + significand = significand >> bitsDiscarded; + + significand = ((((long) (DoubleConsts.MIN_EXPONENT - 1) + // subnorm exp. + (long) DoubleConsts.EXP_BIAS) << + (DoubleConsts.SIGNIFICAND_WIDTH - 1)) + & DoubleConsts.EXP_BIT_MASK) | + (DoubleConsts.SIGNIF_BIT_MASK & significand); + } + } + + // The significand variable now contains the currently + // appropriate exponent bits too. + + // + // Determine if significand should be incremented; + // making this determination depends on the least + // significant bit and the round and sticky bits. + // + // Round to nearest even rounding table, adapted from + // table 4.7 in "Computer Arithmetic" by IsraelKoren. + // The digit to the left of the "decimal" point is the + // least significant bit, the digits to the right of + // the point are the round and sticky bits + // + // Number Round(x) + // x0.00 x0. + // x0.01 x0. + // x0.10 x0. + // x0.11 x1. = x0. +1 + // x1.00 x1. + // x1.01 x1. + // x1.10 x1. + 1 + // x1.11 x1. + 1 + // + boolean leastZero = ((significand & 1L) == 0L); + if ((leastZero && round && sticky) || + ((!leastZero) && round)) { + significand++; + } + + double value = isNegative ? + Double.longBitsToDouble(significand | DoubleConsts.SIGN_BIT_MASK) : + Double.longBitsToDouble(significand ); + + return new PreparedASCIIToBinaryBuffer(value, fValue); + } + } + } + + /** + * Returns <code>s</code> with any leading zeros removed. + */ + static String stripLeadingZeros(String s) { +// return s.replaceFirst("^0+", ""); + if(!s.isEmpty() && s.charAt(0)=='0') { + for(int i=1; i<s.length(); i++) { + if(s.charAt(i)!='0') { + return s.substring(i); + } + } + return ""; + } + return s; + } + + /** + * Extracts a hexadecimal digit from position <code>position</code> + * of string <code>s</code>. + */ + static int getHexDigit(String s, int position) { + int value = Character.digit(s.charAt(position), 16); + if (value <= -1 || value >= 16) { + throw new AssertionError("Unexpected failure of digit conversion of " + + s.charAt(position)); + } + return value; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/src/java.base/share/classes/jdk/internal/math/FormattedFloatingDecimal.java Thu Dec 24 10:34:31 2015 -0800 @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code 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 General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.internal.math; + +import java.util.Arrays; + +public class FormattedFloatingDecimal{ + + public enum Form { SCIENTIFIC, COMPATIBLE, DECIMAL_FLOAT, GENERAL }; + + + public static FormattedFloatingDecimal valueOf(double d, int precision, Form form){ + FloatingDecimal.BinaryToASCIIConverter fdConverter = + FloatingDecimal.getBinaryToASCIIConverter(d, form == Form.COMPATIBLE); + return new FormattedFloatingDecimal(precision,form, fdConverter); + } + + private int decExponentRounded; + private char[] mantissa; + private char[] exponent; + + private static final ThreadLocal<Object> threadLocalCharBuffer = + new ThreadLocal<Object>() { + @Override + protected Object initialValue() { + return new char[20]; + } + }; + + private static char[] getBuffer(){ + return (char[]) threadLocalCharBuffer.get(); + } + + private FormattedFloatingDecimal(int precision, Form form, FloatingDecimal.BinaryToASCIIConverter fdConverter) { + if (fdConverter.isExceptional()) { + this.mantissa = fdConverter.toJavaFormatString().toCharArray(); + this.exponent = null; + return; + } + char[] digits = getBuffer(); + int nDigits = fdConverter.getDigits(digits); + int decExp = fdConverter.getDecimalExponent(); + int exp; + boolean isNegative = fdConverter.isNegative(); + switch (form) { + case COMPATIBLE: + exp = decExp; + this.decExponentRounded = exp; + fillCompatible(precision, digits, nDigits, exp, isNegative); + break; + case DECIMAL_FLOAT: + exp = applyPrecision(decExp, digits, nDigits, decExp + precision); + fillDecimal(precision, digits, nDigits, exp, isNegative); + this.decExponentRounded = exp; + break; + case SCIENTIFIC: + exp = applyPrecision(decExp, digits, nDigits, precision + 1); + fillScientific(precision, digits, nDigits, exp, isNegative); + this.decExponentRounded = exp; + break; + case GENERAL: + exp = applyPrecision(decExp, digits, nDigits, precision); + // adjust precision to be the number of digits to right of decimal + // the real exponent to be output is actually exp - 1, not exp + if (exp - 1 < -4 || exp - 1 >= precision) { + // form = Form.SCIENTIFIC; + precision--; + fillScientific(precision, digits, nDigits, exp, isNegative); + } else { + // form = Form.DECIMAL_FLOAT; + precision = precision - exp; + fillDecimal(precision, digits, nDigits, exp, isNegative); + } + this.decExponentRounded = exp; + break; + default: + assert false; + } + } + + // returns the exponent after rounding has been done by applyPrecision + public int getExponentRounded() { + return decExponentRounded - 1; + } + + public char[] getMantissa(){ + return mantissa; + } + + public char[] getExponent(){ + return exponent; + } + + /** + * Returns new decExp in case of overflow. + */ + private static int applyPrecision(int decExp, char[] digits, int nDigits, int prec) { + if (prec >= nDigits || prec < 0) { + // no rounding necessary + return decExp; + } + if (prec == 0) { + // only one digit (0 or 1) is returned because the precision + // excludes all significant digits + if (digits[0] >= '5') { + digits[0] = '1'; + Arrays.fill(digits, 1, nDigits, '0'); + return decExp + 1; + } else { + Arrays.fill(digits, 0, nDigits, '0'); + return decExp; + } + } + int q = digits[prec]; + if (q >= '5') { + int i = prec; + q = digits[--i]; + if ( q == '9' ) { + while ( q == '9' && i > 0 ){ + q = digits[--i]; + } + if ( q == '9' ){ + // carryout! High-order 1, rest 0s, larger exp. + digits[0] = '1'; + Arrays.fill(digits, 1, nDigits, '0'); + return decExp+1; + } + } + digits[i] = (char)(q + 1); + Arrays.fill(digits, i+1, nDigits, '0'); + } else { + Arrays.fill(digits, prec, nDigits, '0'); + } + return decExp; + } + + /** + * Fills mantissa and exponent char arrays for compatible format. + */ + private void fillCompatible(int precision, char[] digits, int nDigits, int exp, boolean isNegative) { + int startIndex = isNegative ? 1 : 0; + if (exp > 0 && exp < 8) { + // print digits.digits. + if (nDigits < exp) { + int extraZeros = exp - nDigits; + mantissa = create(isNegative, nDigits + extraZeros + 2); + System.arraycopy(digits, 0, mantissa, startIndex, nDigits); + Arrays.fill(mantissa, startIndex + nDigits, startIndex + nDigits + extraZeros, '0'); + mantissa[startIndex + nDigits + extraZeros] = '.'; + mantissa[startIndex + nDigits + extraZeros+1] = '0'; + } else if (exp < nDigits) { + int t = Math.min(nDigits - exp, precision); + mantissa = create(isNegative, exp + 1 + t); + System.arraycopy(digits, 0, mantissa, startIndex, exp); + mantissa[startIndex + exp ] = '.'; + System.arraycopy(digits, exp, mantissa, startIndex+exp+1, t); + } else { // exp == digits.length + mantissa = create(isNegative, nDigits + 2); + System.arraycopy(digits, 0, mantissa, startIndex, nDigits); + mantissa[startIndex + nDigits ] = '.'; + mantissa[startIndex + nDigits +1] = '0'; + } + } else if (exp <= 0 && exp > -3) { + int zeros = Math.max(0, Math.min(-exp, precision)); + int t = Math.max(0, Math.min(nDigits, precision + exp)); + // write '0' s before the significant digits + if (zeros > 0) { + mantissa = create(isNegative, zeros + 2 + t); + mantissa[startIndex] = '0'; + mantissa[startIndex+1] = '.'; + Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0'); + if (t > 0) { + // copy only when significant digits are within the precision + System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t); + } + } else if (t > 0) { + mantissa = create(isNegative, zeros + 2 + t); + mantissa[startIndex] = '0'; + mantissa[startIndex + 1] = '.'; + // copy only when significant digits are within the precision + System.arraycopy(digits, 0, mantissa, startIndex + 2, t); + } else { + this.mantissa = create(isNegative, 1); + this.mantissa[startIndex] = '0'; + } + } else { + if (nDigits > 1) { + mantissa = create(isNegative, nDigits + 1); + mantissa[startIndex] = digits[0]; + mantissa[startIndex + 1] = '.'; + System.arraycopy(digits, 1, mantissa, startIndex + 2, nDigits - 1); + } else { + mantissa = create(isNegative, 3); + mantissa[startIndex] = digits[0]; + mantissa[startIndex + 1] = '.'; + mantissa[startIndex + 2] = '0'; + } + int e, expStartIntex; + boolean isNegExp = (exp <= 0); + if (isNegExp) { + e = -exp + 1; + expStartIntex = 1; + } else { + e = exp - 1; + expStartIntex = 0; + } + // decExponent has 1, 2, or 3, digits + if (e <= 9) { + exponent = create(isNegExp,1); + exponent[expStartIntex] = (char) (e + '0'); + } else if (e <= 99) { + exponent = create(isNegExp,2); + exponent[expStartIntex] = (char) (e / 10 + '0'); + exponent[expStartIntex+1] = (char) (e % 10 + '0'); + } else { + exponent = create(isNegExp,3); + exponent[expStartIntex] = (char) (e / 100 + '0'); + e %= 100; + exponent[expStartIntex+1] = (char) (e / 10 + '0'); + exponent[expStartIntex+2] = (char) (e % 10 + '0'); + } + } + } + + private static char[] create(boolean isNegative, int size) { + if(isNegative) { + char[] r = new char[size +1]; + r[0] = '-'; + return r; + } else { + return new char[size]; + } + } + + /* + * Fills mantissa char arrays for DECIMAL_FLOAT format. + * Exponent should be equal to null. + */ + private void fillDecimal(int precision, char[] digits, int nDigits, int exp, boolean isNegative) { + int startIndex = isNegative ? 1 : 0; + if (exp > 0) { + // print digits.digits. + if (nDigits < exp) { + mantissa = create(isNegative,exp); + System.arraycopy(digits, 0, mantissa, startIndex, nDigits); + Arrays.fill(mantissa, startIndex + nDigits, startIndex + exp, '0'); + // Do not append ".0" for formatted floats since the user + // may request that it be omitted. It is added as necessary + // by the Formatter. + } else { + int t = Math.min(nDigits - exp, precision); + mantissa = create(isNegative, exp + (t > 0 ? (t + 1) : 0)); + System.arraycopy(digits, 0, mantissa, startIndex, exp); + // Do not append ".0" for formatted floats since the user + // may request that it be omitted. It is added as necessary + // by the Formatter. + if (t > 0) { + mantissa[startIndex + exp] = '.'; + System.arraycopy(digits, exp, mantissa, startIndex + exp + 1, t); + } + } + } else if (exp <= 0) { + int zeros = Math.max(0, Math.min(-exp, precision)); + int t = Math.max(0, Math.min(nDigits, precision + exp)); + // write '0' s before the significant digits + if (zeros > 0) { + mantissa = create(isNegative, zeros + 2 + t); + mantissa[startIndex] = '0'; + mantissa[startIndex+1] = '.'; + Arrays.fill(mantissa, startIndex + 2, startIndex + 2 + zeros, '0'); + if (t > 0) { + // copy only when significant digits are within the precision + System.arraycopy(digits, 0, mantissa, startIndex + 2 + zeros, t); + } + } else if (t > 0) { + mantissa = create(isNegative, zeros + 2 + t); + mantissa[startIndex] = '0'; + mantissa[startIndex + 1] = '.'; + // copy only when significant digits are within the precision + System.arraycopy(digits, 0, mantissa, startIndex + 2, t); + } else { + this.mantissa = create(isNegative, 1); + this.mantissa[startIndex] = '0'; + } + } + } + + /** + * Fills mantissa and exponent char arrays for SCIENTIFIC format. + */ + private void fillScientific(int precision, char[] digits, int nDigits, int exp, boolean isNegative) { + int startIndex = isNegative ? 1 : 0; + int t = Math.max(0, Math.min(nDigits - 1, precision)); + if (t > 0) { + mantissa = create(isNegative, t + 2); + mantissa[startIndex] = digits[0]; + mantissa[startIndex + 1] = '.'; + System.arraycopy(digits, 1, mantissa, startIndex + 2, t); + } else { + mantissa = create(isNegative, 1); + mantissa[startIndex] = digits[0]; + } + char expSign; + int e; + if (exp <= 0) { + expSign = '-'; + e = -exp + 1; + } else { + expSign = '+' ; + e = exp - 1; + } + // decExponent has 1, 2, or 3, digits + if (e <= 9) { + exponent = new char[] { expSign, + '0', (char) (e + '0') }; + } else if (e <= 99) { + exponent = new char[] { expSign, + (char) (e / 10 + '0'), (char) (e % 10 + '0') }; + } else { + char hiExpChar = (char) (e / 100 + '0'); + e %= 100; + exponent = new char[] { expSign, + hiExpChar, (char) (e / 10 + '0'), (char) (e % 10 + '0') }; + } + } +}
--- a/jdk/src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java Wed Dec 23 15:41:55 2015 -0800 +++ b/jdk/src/java.base/share/classes/jdk/internal/misc/CleanerImpl.java Thu Dec 24 10:34:31 2015 -0800 @@ -39,7 +39,6 @@ import java.util.function.Function; import sun.misc.InnocuousThread; -import sun.misc.ManagedLocalsThread; /** * CleanerImpl manages a set of object references and corresponding cleaning actions. @@ -130,8 +129,8 @@ */ public void run() { Thread t = Thread.currentThread(); - ManagedLocalsThread mlThread = (t instanceof ManagedLocalsThread) - ? (ManagedLocalsThread) t + InnocuousThread mlThread = (t instanceof InnocuousThread) + ? (InnocuousThread) t : null; while (!phantomCleanableList.isListEmpty() || !weakCleanableList.isListEmpty() || @@ -787,4 +786,3 @@ } } -
--- a/jdk/src/java.base/share/classes/sun/misc/CompoundEnumeration.java Wed Dec 23 15:41:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,63 +0,0 @@ -/* - * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.util.Enumeration; -import java.util.NoSuchElementException; - -/* - * A useful utility class that will enumerate over an array of - * enumerations. - */ -public class CompoundEnumeration<E> implements Enumeration<E> { - private Enumeration<E>[] enums; - private int index = 0; - - public CompoundEnumeration(Enumeration<E>[] enums) { - this.enums = enums; - } - - private boolean next() { - while (index < enums.length) { - if (enums[index] != null && enums[index].hasMoreElements()) { - return true; - } - index++; - } - return false; - } - - public boolean hasMoreElements() { - return next(); - } - - public E nextElement() { - if (!next()) { - throw new NoSuchElementException(); - } - return enums[index].nextElement(); - } -}
--- a/jdk/src/java.base/share/classes/sun/misc/DoubleConsts.java Wed Dec 23 15:41:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -/** - * This class contains additional constants documenting limits of the - * <code>double</code> type. - * - * @author Joseph D. Darcy - */ - -public class DoubleConsts { - /** - * Don't let anyone instantiate this class. - */ - private DoubleConsts() {} - - public static final double POSITIVE_INFINITY = java.lang.Double.POSITIVE_INFINITY; - public static final double NEGATIVE_INFINITY = java.lang.Double.NEGATIVE_INFINITY; - public static final double NaN = java.lang.Double.NaN; - public static final double MAX_VALUE = java.lang.Double.MAX_VALUE; - public static final double MIN_VALUE = java.lang.Double.MIN_VALUE; - - /** - * A constant holding the smallest positive normal value of type - * <code>double</code>, 2<sup>-1022</sup>. It is equal to the - * value returned by - * <code>Double.longBitsToDouble(0x0010000000000000L)</code>. - * - * @since 1.5 - */ - public static final double MIN_NORMAL = 2.2250738585072014E-308; - - - /** - * The number of logical bits in the significand of a - * <code>double</code> number, including the implicit bit. - */ - public static final int SIGNIFICAND_WIDTH = 53; - - /** - * Maximum exponent a finite <code>double</code> number may have. - * It is equal to the value returned by - * <code>Math.ilogb(Double.MAX_VALUE)</code>. - */ - public static final int MAX_EXPONENT = 1023; - - /** - * Minimum exponent a normalized <code>double</code> number may - * have. It is equal to the value returned by - * <code>Math.ilogb(Double.MIN_NORMAL)</code>. - */ - public static final int MIN_EXPONENT = -1022; - - /** - * The exponent the smallest positive <code>double</code> - * subnormal value would have if it could be normalized.. - */ - public static final int MIN_SUB_EXPONENT = MIN_EXPONENT - - (SIGNIFICAND_WIDTH - 1); - - /** - * Bias used in representing a <code>double</code> exponent. - */ - public static final int EXP_BIAS = 1023; - - /** - * Bit mask to isolate the sign bit of a <code>double</code>. - */ - public static final long SIGN_BIT_MASK = 0x8000000000000000L; - - /** - * Bit mask to isolate the exponent field of a - * <code>double</code>. - */ - public static final long EXP_BIT_MASK = 0x7FF0000000000000L; - - /** - * Bit mask to isolate the significand field of a - * <code>double</code>. - */ - public static final long SIGNIF_BIT_MASK = 0x000FFFFFFFFFFFFFL; - - static { - // verify bit masks cover all bit positions and that the bit - // masks are non-overlapping - assert(((SIGN_BIT_MASK | EXP_BIT_MASK | SIGNIF_BIT_MASK) == ~0L) && - (((SIGN_BIT_MASK & EXP_BIT_MASK) == 0L) && - ((SIGN_BIT_MASK & SIGNIF_BIT_MASK) == 0L) && - ((EXP_BIT_MASK & SIGNIF_BIT_MASK) == 0L))); - } -}
--- a/jdk/src/java.base/share/classes/sun/misc/FDBigInteger.java Wed Dec 23 15:41:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1508 +0,0 @@ -/* - * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package sun.misc; - -import java.math.BigInteger; -import java.util.Arrays; -//@ model import org.jmlspecs.models.JMLMath; - -/** - * A simple big integer package specifically for floating point base conversion. - */ -public /*@ spec_bigint_math @*/ class FDBigInteger { - - // - // This class contains many comments that start with "/*@" mark. - // They are behavourial specification in - // the Java Modelling Language (JML): - // http://www.eecs.ucf.edu/~leavens/JML//index.shtml - // - - /*@ - @ public pure model static \bigint UNSIGNED(int v) { - @ return v >= 0 ? v : v + (((\bigint)1) << 32); - @ } - @ - @ public pure model static \bigint UNSIGNED(long v) { - @ return v >= 0 ? v : v + (((\bigint)1) << 64); - @ } - @ - @ public pure model static \bigint AP(int[] data, int len) { - @ return (\sum int i; 0 <= 0 && i < len; UNSIGNED(data[i]) << (i*32)); - @ } - @ - @ public pure model static \bigint pow52(int p5, int p2) { - @ ghost \bigint v = 1; - @ for (int i = 0; i < p5; i++) v *= 5; - @ return v << p2; - @ } - @ - @ public pure model static \bigint pow10(int p10) { - @ return pow52(p10, p10); - @ } - @*/ - - static final int[] SMALL_5_POW = { - 1, - 5, - 5 * 5, - 5 * 5 * 5, - 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 - }; - - static final long[] LONG_5_POW = { - 1L, - 5L, - 5L * 5, - 5L * 5 * 5, - 5L * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - 5L * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5, - }; - - // Maximum size of cache of powers of 5 as FDBigIntegers. - private static final int MAX_FIVE_POW = 340; - - // Cache of big powers of 5 as FDBigIntegers. - private static final FDBigInteger POW_5_CACHE[]; - - // Initialize FDBigInteger cache of powers of 5. - static { - POW_5_CACHE = new FDBigInteger[MAX_FIVE_POW]; - int i = 0; - while (i < SMALL_5_POW.length) { - FDBigInteger pow5 = new FDBigInteger(new int[]{SMALL_5_POW[i]}, 0); - pow5.makeImmutable(); - POW_5_CACHE[i] = pow5; - i++; - } - FDBigInteger prev = POW_5_CACHE[i - 1]; - while (i < MAX_FIVE_POW) { - POW_5_CACHE[i] = prev = prev.mult(5); - prev.makeImmutable(); - i++; - } - } - - // Zero as an FDBigInteger. - public static final FDBigInteger ZERO = new FDBigInteger(new int[0], 0); - - // Ensure ZERO is immutable. - static { - ZERO.makeImmutable(); - } - - // Constant for casting an int to a long via bitwise AND. - private static final long LONG_MASK = 0xffffffffL; - - //@ spec_public non_null; - private int data[]; // value: data[0] is least significant - //@ spec_public; - private int offset; // number of least significant zero padding ints - //@ spec_public; - private int nWords; // data[nWords-1]!=0, all values above are zero - // if nWords==0 -> this FDBigInteger is zero - //@ spec_public; - private boolean isImmutable = false; - - /*@ - @ public invariant 0 <= nWords && nWords <= data.length && offset >= 0; - @ public invariant nWords == 0 ==> offset == 0; - @ public invariant nWords > 0 ==> data[nWords - 1] != 0; - @ public invariant (\forall int i; nWords <= i && i < data.length; data[i] == 0); - @ public pure model \bigint value() { - @ return AP(data, nWords) << (offset*32); - @ } - @*/ - - /** - * Constructs an <code>FDBigInteger</code> from data and padding. The - * <code>data</code> parameter has the least significant <code>int</code> at - * the zeroth index. The <code>offset</code> parameter gives the number of - * zero <code>int</code>s to be inferred below the least significant element - * of <code>data</code>. - * - * @param data An array containing all non-zero <code>int</code>s of the value. - * @param offset An offset indicating the number of zero <code>int</code>s to pad - * below the least significant element of <code>data</code>. - */ - /*@ - @ requires data != null && offset >= 0; - @ ensures this.value() == \old(AP(data, data.length) << (offset*32)); - @ ensures this.data == \old(data); - @*/ - private FDBigInteger(int[] data, int offset) { - this.data = data; - this.offset = offset; - this.nWords = data.length; - trimLeadingZeros(); - } - - /** - * Constructs an <code>FDBigInteger</code> from a starting value and some - * decimal digits. - * - * @param lValue The starting value. - * @param digits The decimal digits. - * @param kDigits The initial index into <code>digits</code>. - * @param nDigits The final index into <code>digits</code>. - */ - /*@ - @ requires digits != null; - @ requires 0 <= kDigits && kDigits <= nDigits && nDigits <= digits.length; - @ requires (\forall int i; 0 <= i && i < nDigits; '0' <= digits[i] && digits[i] <= '9'); - @ ensures this.value() == \old(lValue * pow10(nDigits - kDigits) + (\sum int i; kDigits <= i && i < nDigits; (digits[i] - '0') * pow10(nDigits - i - 1))); - @*/ - public FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) { - int n = Math.max((nDigits + 8) / 9, 2); // estimate size needed. - data = new int[n]; // allocate enough space - data[0] = (int) lValue; // starting value - data[1] = (int) (lValue >>> 32); - offset = 0; - nWords = 2; - int i = kDigits; - int limit = nDigits - 5; // slurp digits 5 at a time. - int v; - while (i < limit) { - int ilim = i + 5; - v = (int) digits[i++] - (int) '0'; - while (i < ilim) { - v = 10 * v + (int) digits[i++] - (int) '0'; - } - multAddMe(100000, v); // ... where 100000 is 10^5. - } - int factor = 1; - v = 0; - while (i < nDigits) { - v = 10 * v + (int) digits[i++] - (int) '0'; - factor *= 10; - } - if (factor != 1) { - multAddMe(factor, v); - } - trimLeadingZeros(); - } - - /** - * Returns an <code>FDBigInteger</code> with the numerical value - * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. - * - * @param p5 The exponent of the power-of-five factor. - * @param p2 The exponent of the power-of-two factor. - * @return <code>5<sup>p5</sup> * 2<sup>p2</sup></code> - */ - /*@ - @ requires p5 >= 0 && p2 >= 0; - @ assignable \nothing; - @ ensures \result.value() == \old(pow52(p5, p2)); - @*/ - public static FDBigInteger valueOfPow52(int p5, int p2) { - if (p5 != 0) { - if (p2 == 0) { - return big5pow(p5); - } else if (p5 < SMALL_5_POW.length) { - int pow5 = SMALL_5_POW[p5]; - int wordcount = p2 >> 5; - int bitcount = p2 & 0x1f; - if (bitcount == 0) { - return new FDBigInteger(new int[]{pow5}, wordcount); - } else { - return new FDBigInteger(new int[]{ - pow5 << bitcount, - pow5 >>> (32 - bitcount) - }, wordcount); - } - } else { - return big5pow(p5).leftShift(p2); - } - } else { - return valueOfPow2(p2); - } - } - - /** - * Returns an <code>FDBigInteger</code> with the numerical value - * <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code>. - * - * @param value The constant factor. - * @param p5 The exponent of the power-of-five factor. - * @param p2 The exponent of the power-of-two factor. - * @return <code>value * 5<sup>p5</sup> * 2<sup>p2</sup></code> - */ - /*@ - @ requires p5 >= 0 && p2 >= 0; - @ assignable \nothing; - @ ensures \result.value() == \old(UNSIGNED(value) * pow52(p5, p2)); - @*/ - public static FDBigInteger valueOfMulPow52(long value, int p5, int p2) { - assert p5 >= 0 : p5; - assert p2 >= 0 : p2; - int v0 = (int) value; - int v1 = (int) (value >>> 32); - int wordcount = p2 >> 5; - int bitcount = p2 & 0x1f; - if (p5 != 0) { - if (p5 < SMALL_5_POW.length) { - long pow5 = SMALL_5_POW[p5] & LONG_MASK; - long carry = (v0 & LONG_MASK) * pow5; - v0 = (int) carry; - carry >>>= 32; - carry = (v1 & LONG_MASK) * pow5 + carry; - v1 = (int) carry; - int v2 = (int) (carry >>> 32); - if (bitcount == 0) { - return new FDBigInteger(new int[]{v0, v1, v2}, wordcount); - } else { - return new FDBigInteger(new int[]{ - v0 << bitcount, - (v1 << bitcount) | (v0 >>> (32 - bitcount)), - (v2 << bitcount) | (v1 >>> (32 - bitcount)), - v2 >>> (32 - bitcount) - }, wordcount); - } - } else { - FDBigInteger pow5 = big5pow(p5); - int[] r; - if (v1 == 0) { - r = new int[pow5.nWords + 1 + ((p2 != 0) ? 1 : 0)]; - mult(pow5.data, pow5.nWords, v0, r); - } else { - r = new int[pow5.nWords + 2 + ((p2 != 0) ? 1 : 0)]; - mult(pow5.data, pow5.nWords, v0, v1, r); - } - return (new FDBigInteger(r, pow5.offset)).leftShift(p2); - } - } else if (p2 != 0) { - if (bitcount == 0) { - return new FDBigInteger(new int[]{v0, v1}, wordcount); - } else { - return new FDBigInteger(new int[]{ - v0 << bitcount, - (v1 << bitcount) | (v0 >>> (32 - bitcount)), - v1 >>> (32 - bitcount) - }, wordcount); - } - } - return new FDBigInteger(new int[]{v0, v1}, 0); - } - - /** - * Returns an <code>FDBigInteger</code> with the numerical value - * <code>2<sup>p2</sup></code>. - * - * @param p2 The exponent of 2. - * @return <code>2<sup>p2</sup></code> - */ - /*@ - @ requires p2 >= 0; - @ assignable \nothing; - @ ensures \result.value() == pow52(0, p2); - @*/ - private static FDBigInteger valueOfPow2(int p2) { - int wordcount = p2 >> 5; - int bitcount = p2 & 0x1f; - return new FDBigInteger(new int[]{1 << bitcount}, wordcount); - } - - /** - * Removes all leading zeros from this <code>FDBigInteger</code> adjusting - * the offset and number of non-zero leading words accordingly. - */ - /*@ - @ requires data != null; - @ requires 0 <= nWords && nWords <= data.length && offset >= 0; - @ requires nWords == 0 ==> offset == 0; - @ ensures nWords == 0 ==> offset == 0; - @ ensures nWords > 0 ==> data[nWords - 1] != 0; - @*/ - private /*@ helper @*/ void trimLeadingZeros() { - int i = nWords; - if (i > 0 && (data[--i] == 0)) { - //for (; i > 0 && data[i - 1] == 0; i--) ; - while(i > 0 && data[i - 1] == 0) { - i--; - } - this.nWords = i; - if (i == 0) { // all words are zero - this.offset = 0; - } - } - } - - /** - * Retrieves the normalization bias of the <code>FDBigIntger</code>. The - * normalization bias is a left shift such that after it the highest word - * of the value will have the 4 highest bits equal to zero: - * {@code (highestWord & 0xf0000000) == 0}, but the next bit should be 1 - * {@code (highestWord & 0x08000000) != 0}. - * - * @return The normalization bias. - */ - /*@ - @ requires this.value() > 0; - @*/ - public /*@ pure @*/ int getNormalizationBias() { - if (nWords == 0) { - throw new IllegalArgumentException("Zero value cannot be normalized"); - } - int zeros = Integer.numberOfLeadingZeros(data[nWords - 1]); - return (zeros < 4) ? 28 + zeros : zeros - 4; - } - - // TODO: Why is anticount param needed if it is always 32 - bitcount? - /** - * Left shifts the contents of one int array into another. - * - * @param src The source array. - * @param idx The initial index of the source array. - * @param result The destination array. - * @param bitcount The left shift. - * @param anticount The left anti-shift, e.g., <code>32-bitcount</code>. - * @param prev The prior source value. - */ - /*@ - @ requires 0 < bitcount && bitcount < 32 && anticount == 32 - bitcount; - @ requires src.length >= idx && result.length > idx; - @ assignable result[*]; - @ ensures AP(result, \old(idx + 1)) == \old((AP(src, idx) + UNSIGNED(prev) << (idx*32)) << bitcount); - @*/ - private static void leftShift(int[] src, int idx, int result[], int bitcount, int anticount, int prev){ - for (; idx > 0; idx--) { - int v = (prev << bitcount); - prev = src[idx - 1]; - v |= (prev >>> anticount); - result[idx] = v; - } - int v = prev << bitcount; - result[0] = v; - } - - /** - * Shifts this <code>FDBigInteger</code> to the left. The shift is performed - * in-place unless the <code>FDBigInteger</code> is immutable in which case - * a new instance of <code>FDBigInteger</code> is returned. - * - * @param shift The number of bits to shift left. - * @return The shifted <code>FDBigInteger</code>. - */ - /*@ - @ requires this.value() == 0 || shift == 0; - @ assignable \nothing; - @ ensures \result == this; - @ - @ also - @ - @ requires this.value() > 0 && shift > 0 && this.isImmutable; - @ assignable \nothing; - @ ensures \result.value() == \old(this.value() << shift); - @ - @ also - @ - @ requires this.value() > 0 && shift > 0 && this.isImmutable; - @ assignable \nothing; - @ ensures \result == this; - @ ensures \result.value() == \old(this.value() << shift); - @*/ - public FDBigInteger leftShift(int shift) { - if (shift == 0 || nWords == 0) { - return this; - } - int wordcount = shift >> 5; - int bitcount = shift & 0x1f; - if (this.isImmutable) { - if (bitcount == 0) { - return new FDBigInteger(Arrays.copyOf(data, nWords), offset + wordcount); - } else { - int anticount = 32 - bitcount; - int idx = nWords - 1; - int prev = data[idx]; - int hi = prev >>> anticount; - int[] result; - if (hi != 0) { - result = new int[nWords + 1]; - result[nWords] = hi; - } else { - result = new int[nWords]; - } - leftShift(data,idx,result,bitcount,anticount,prev); - return new FDBigInteger(result, offset + wordcount); - } - } else { - if (bitcount != 0) { - int anticount = 32 - bitcount; - if ((data[0] << bitcount) == 0) { - int idx = 0; - int prev = data[idx]; - for (; idx < nWords - 1; idx++) { - int v = (prev >>> anticount); - prev = data[idx + 1]; - v |= (prev << bitcount); - data[idx] = v; - } - int v = prev >>> anticount; - data[idx] = v; - if(v==0) { - nWords--; - } - offset++; - } else { - int idx = nWords - 1; - int prev = data[idx]; - int hi = prev >>> anticount; - int[] result = data; - int[] src = data; - if (hi != 0) { - if(nWords == data.length) { - data = result = new int[nWords + 1]; - } - result[nWords++] = hi; - } - leftShift(src,idx,result,bitcount,anticount,prev); - } - } - offset += wordcount; - return this; - } - } - - /** - * Returns the number of <code>int</code>s this <code>FDBigInteger</code> represents. - * - * @return Number of <code>int</code>s required to represent this <code>FDBigInteger</code>. - */ - /*@ - @ requires this.value() == 0; - @ ensures \result == 0; - @ - @ also - @ - @ requires this.value() > 0; - @ ensures ((\bigint)1) << (\result - 1) <= this.value() && this.value() <= ((\bigint)1) << \result; - @*/ - private /*@ pure @*/ int size() { - return nWords + offset; - } - - - /** - * Computes - * <pre> - * q = (int)( this / S ) - * this = 10 * ( this mod S ) - * Return q. - * </pre> - * This is the iteration step of digit development for output. - * We assume that S has been normalized, as above, and that - * "this" has been left-shifted accordingly. - * Also assumed, of course, is that the result, q, can be expressed - * as an integer, {@code 0 <= q < 10}. - * - * @param S The divisor of this <code>FDBigInteger</code>. - * @return <code>q = (int)(this / S)</code>. - */ - /*@ - @ requires !this.isImmutable; - @ requires this.size() <= S.size(); - @ requires this.data.length + this.offset >= S.size(); - @ requires S.value() >= ((\bigint)1) << (S.size()*32 - 4); - @ assignable this.nWords, this.offset, this.data, this.data[*]; - @ ensures \result == \old(this.value() / S.value()); - @ ensures this.value() == \old(10 * (this.value() % S.value())); - @*/ - public int quoRemIteration(FDBigInteger S) throws IllegalArgumentException { - assert !this.isImmutable : "cannot modify immutable value"; - // ensure that this and S have the same number of - // digits. If S is properly normalized and q < 10 then - // this must be so. - int thSize = this.size(); - int sSize = S.size(); - if (thSize < sSize) { - // this value is significantly less than S, result of division is zero. - // just mult this by 10. - int p = multAndCarryBy10(this.data, this.nWords, this.data); - if(p!=0) { - this.data[nWords++] = p; - } else { - trimLeadingZeros(); - } - return 0; - } else if (thSize > sSize) { - throw new IllegalArgumentException("disparate values"); - } - // estimate q the obvious way. We will usually be - // right. If not, then we're only off by a little and - // will re-add. - long q = (this.data[this.nWords - 1] & LONG_MASK) / (S.data[S.nWords - 1] & LONG_MASK); - long diff = multDiffMe(q, S); - if (diff != 0L) { - //@ assert q != 0; - //@ assert this.offset == \old(Math.min(this.offset, S.offset)); - //@ assert this.offset <= S.offset; - - // q is too big. - // add S back in until this turns +. This should - // not be very many times! - long sum = 0L; - int tStart = S.offset - this.offset; - //@ assert tStart >= 0; - int[] sd = S.data; - int[] td = this.data; - while (sum == 0L) { - for (int sIndex = 0, tIndex = tStart; tIndex < this.nWords; sIndex++, tIndex++) { - sum += (td[tIndex] & LONG_MASK) + (sd[sIndex] & LONG_MASK); - td[tIndex] = (int) sum; - sum >>>= 32; // Signed or unsigned, answer is 0 or 1 - } - // - // Originally the following line read - // "if ( sum !=0 && sum != -1 )" - // but that would be wrong, because of the - // treatment of the two values as entirely unsigned, - // it would be impossible for a carry-out to be interpreted - // as -1 -- it would have to be a single-bit carry-out, or +1. - // - assert sum == 0 || sum == 1 : sum; // carry out of division correction - q -= 1; - } - } - // finally, we can multiply this by 10. - // it cannot overflow, right, as the high-order word has - // at least 4 high-order zeros! - int p = multAndCarryBy10(this.data, this.nWords, this.data); - assert p == 0 : p; // Carry out of *10 - trimLeadingZeros(); - return (int) q; - } - - /** - * Multiplies this <code>FDBigInteger</code> by 10. The operation will be - * performed in place unless the <code>FDBigInteger</code> is immutable in - * which case a new <code>FDBigInteger</code> will be returned. - * - * @return The <code>FDBigInteger</code> multiplied by 10. - */ - /*@ - @ requires this.value() == 0; - @ assignable \nothing; - @ ensures \result == this; - @ - @ also - @ - @ requires this.value() > 0 && this.isImmutable; - @ assignable \nothing; - @ ensures \result.value() == \old(this.value() * 10); - @ - @ also - @ - @ requires this.value() > 0 && !this.isImmutable; - @ assignable this.nWords, this.data, this.data[*]; - @ ensures \result == this; - @ ensures \result.value() == \old(this.value() * 10); - @*/ - public FDBigInteger multBy10() { - if (nWords == 0) { - return this; - } - if (isImmutable) { - int[] res = new int[nWords + 1]; - res[nWords] = multAndCarryBy10(data, nWords, res); - return new FDBigInteger(res, offset); - } else { - int p = multAndCarryBy10(this.data, this.nWords, this.data); - if (p != 0) { - if (nWords == data.length) { - if (data[0] == 0) { - System.arraycopy(data, 1, data, 0, --nWords); - offset++; - } else { - data = Arrays.copyOf(data, data.length + 1); - } - } - data[nWords++] = p; - } else { - trimLeadingZeros(); - } - return this; - } - } - - /** - * Multiplies this <code>FDBigInteger</code> by - * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. The operation will be - * performed in place if possible, otherwise a new <code>FDBigInteger</code> - * will be returned. - * - * @param p5 The exponent of the power-of-five factor. - * @param p2 The exponent of the power-of-two factor. - * @return The multiplication result. - */ - /*@ - @ requires this.value() == 0 || p5 == 0 && p2 == 0; - @ assignable \nothing; - @ ensures \result == this; - @ - @ also - @ - @ requires this.value() > 0 && (p5 > 0 && p2 >= 0 || p5 == 0 && p2 > 0 && this.isImmutable); - @ assignable \nothing; - @ ensures \result.value() == \old(this.value() * pow52(p5, p2)); - @ - @ also - @ - @ requires this.value() > 0 && p5 == 0 && p2 > 0 && !this.isImmutable; - @ assignable this.nWords, this.data, this.data[*]; - @ ensures \result == this; - @ ensures \result.value() == \old(this.value() * pow52(p5, p2)); - @*/ - public FDBigInteger multByPow52(int p5, int p2) { - if (this.nWords == 0) { - return this; - } - FDBigInteger res = this; - if (p5 != 0) { - int[] r; - int extraSize = (p2 != 0) ? 1 : 0; - if (p5 < SMALL_5_POW.length) { - r = new int[this.nWords + 1 + extraSize]; - mult(this.data, this.nWords, SMALL_5_POW[p5], r); - res = new FDBigInteger(r, this.offset); - } else { - FDBigInteger pow5 = big5pow(p5); - r = new int[this.nWords + pow5.size() + extraSize]; - mult(this.data, this.nWords, pow5.data, pow5.nWords, r); - res = new FDBigInteger(r, this.offset + pow5.offset); - } - } - return res.leftShift(p2); - } - - /** - * Multiplies two big integers represented as int arrays. - * - * @param s1 The first array factor. - * @param s1Len The number of elements of <code>s1</code> to use. - * @param s2 The second array factor. - * @param s2Len The number of elements of <code>s2</code> to use. - * @param dst The product array. - */ - /*@ - @ requires s1 != dst && s2 != dst; - @ requires s1.length >= s1Len && s2.length >= s2Len && dst.length >= s1Len + s2Len; - @ assignable dst[0 .. s1Len + s2Len - 1]; - @ ensures AP(dst, s1Len + s2Len) == \old(AP(s1, s1Len) * AP(s2, s2Len)); - @*/ - private static void mult(int[] s1, int s1Len, int[] s2, int s2Len, int[] dst) { - for (int i = 0; i < s1Len; i++) { - long v = s1[i] & LONG_MASK; - long p = 0L; - for (int j = 0; j < s2Len; j++) { - p += (dst[i + j] & LONG_MASK) + v * (s2[j] & LONG_MASK); - dst[i + j] = (int) p; - p >>>= 32; - } - dst[i + s2Len] = (int) p; - } - } - - /** - * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this - * <code>FDBigInteger</code>. Assert that the result is positive. - * If the subtrahend is immutable, store the result in this(minuend). - * If this(minuend) is immutable a new <code>FDBigInteger</code> is created. - * - * @param subtrahend The <code>FDBigInteger</code> to be subtracted. - * @return This <code>FDBigInteger</code> less the subtrahend. - */ - /*@ - @ requires this.isImmutable; - @ requires this.value() >= subtrahend.value(); - @ assignable \nothing; - @ ensures \result.value() == \old(this.value() - subtrahend.value()); - @ - @ also - @ - @ requires !subtrahend.isImmutable; - @ requires this.value() >= subtrahend.value(); - @ assignable this.nWords, this.offset, this.data, this.data[*]; - @ ensures \result == this; - @ ensures \result.value() == \old(this.value() - subtrahend.value()); - @*/ - public FDBigInteger leftInplaceSub(FDBigInteger subtrahend) { - assert this.size() >= subtrahend.size() : "result should be positive"; - FDBigInteger minuend; - if (this.isImmutable) { - minuend = new FDBigInteger(this.data.clone(), this.offset); - } else { - minuend = this; - } - int offsetDiff = subtrahend.offset - minuend.offset; - int[] sData = subtrahend.data; - int[] mData = minuend.data; - int subLen = subtrahend.nWords; - int minLen = minuend.nWords; - if (offsetDiff < 0) { - // need to expand minuend - int rLen = minLen - offsetDiff; - if (rLen < mData.length) { - System.arraycopy(mData, 0, mData, -offsetDiff, minLen); - Arrays.fill(mData, 0, -offsetDiff, 0); - } else { - int[] r = new int[rLen]; - System.arraycopy(mData, 0, r, -offsetDiff, minLen); - minuend.data = mData = r; - } - minuend.offset = subtrahend.offset; - minuend.nWords = minLen = rLen; - offsetDiff = 0; - } - long borrow = 0L; - int mIndex = offsetDiff; - for (int sIndex = 0; sIndex < subLen && mIndex < minLen; sIndex++, mIndex++) { - long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; - mData[mIndex] = (int) diff; - borrow = diff >> 32; // signed shift - } - for (; borrow != 0 && mIndex < minLen; mIndex++) { - long diff = (mData[mIndex] & LONG_MASK) + borrow; - mData[mIndex] = (int) diff; - borrow = diff >> 32; // signed shift - } - assert borrow == 0L : borrow; // borrow out of subtract, - // result should be positive - minuend.trimLeadingZeros(); - return minuend; - } - - /** - * Subtracts the supplied <code>FDBigInteger</code> subtrahend from this - * <code>FDBigInteger</code>. Assert that the result is positive. - * If the this(minuend) is immutable, store the result in subtrahend. - * If subtrahend is immutable a new <code>FDBigInteger</code> is created. - * - * @param subtrahend The <code>FDBigInteger</code> to be subtracted. - * @return This <code>FDBigInteger</code> less the subtrahend. - */ - /*@ - @ requires subtrahend.isImmutable; - @ requires this.value() >= subtrahend.value(); - @ assignable \nothing; - @ ensures \result.value() == \old(this.value() - subtrahend.value()); - @ - @ also - @ - @ requires !subtrahend.isImmutable; - @ requires this.value() >= subtrahend.value(); - @ assignable subtrahend.nWords, subtrahend.offset, subtrahend.data, subtrahend.data[*]; - @ ensures \result == subtrahend; - @ ensures \result.value() == \old(this.value() - subtrahend.value()); - @*/ - public FDBigInteger rightInplaceSub(FDBigInteger subtrahend) { - assert this.size() >= subtrahend.size() : "result should be positive"; - FDBigInteger minuend = this; - if (subtrahend.isImmutable) { - subtrahend = new FDBigInteger(subtrahend.data.clone(), subtrahend.offset); - } - int offsetDiff = minuend.offset - subtrahend.offset; - int[] sData = subtrahend.data; - int[] mData = minuend.data; - int subLen = subtrahend.nWords; - int minLen = minuend.nWords; - if (offsetDiff < 0) { - int rLen = minLen; - if (rLen < sData.length) { - System.arraycopy(sData, 0, sData, -offsetDiff, subLen); - Arrays.fill(sData, 0, -offsetDiff, 0); - } else { - int[] r = new int[rLen]; - System.arraycopy(sData, 0, r, -offsetDiff, subLen); - subtrahend.data = sData = r; - } - subtrahend.offset = minuend.offset; - subLen -= offsetDiff; - offsetDiff = 0; - } else { - int rLen = minLen + offsetDiff; - if (rLen >= sData.length) { - subtrahend.data = sData = Arrays.copyOf(sData, rLen); - } - } - //@ assert minuend == this && minuend.value() == \old(this.value()); - //@ assert mData == minuend.data && minLen == minuend.nWords; - //@ assert subtrahend.offset + subtrahend.data.length >= minuend.size(); - //@ assert sData == subtrahend.data; - //@ assert AP(subtrahend.data, subtrahend.data.length) << subtrahend.offset == \old(subtrahend.value()); - //@ assert subtrahend.offset == Math.min(\old(this.offset), minuend.offset); - //@ assert offsetDiff == minuend.offset - subtrahend.offset; - //@ assert 0 <= offsetDiff && offsetDiff + minLen <= sData.length; - int sIndex = 0; - long borrow = 0L; - for (; sIndex < offsetDiff; sIndex++) { - long diff = 0L - (sData[sIndex] & LONG_MASK) + borrow; - sData[sIndex] = (int) diff; - borrow = diff >> 32; // signed shift - } - //@ assert sIndex == offsetDiff; - for (int mIndex = 0; mIndex < minLen; sIndex++, mIndex++) { - //@ assert sIndex == offsetDiff + mIndex; - long diff = (mData[mIndex] & LONG_MASK) - (sData[sIndex] & LONG_MASK) + borrow; - sData[sIndex] = (int) diff; - borrow = diff >> 32; // signed shift - } - assert borrow == 0L : borrow; // borrow out of subtract, - // result should be positive - subtrahend.nWords = sIndex; - subtrahend.trimLeadingZeros(); - return subtrahend; - - } - - /** - * Determines whether all elements of an array are zero for all indices less - * than a given index. - * - * @param a The array to be examined. - * @param from The index strictly below which elements are to be examined. - * @return Zero if all elements in range are zero, 1 otherwise. - */ - /*@ - @ requires 0 <= from && from <= a.length; - @ ensures \result == (AP(a, from) == 0 ? 0 : 1); - @*/ - private /*@ pure @*/ static int checkZeroTail(int[] a, int from) { - while (from > 0) { - if (a[--from] != 0) { - return 1; - } - } - return 0; - } - - /** - * Compares the parameter with this <code>FDBigInteger</code>. Returns an - * integer accordingly as: - * <pre>{@code - * > 0: this > other - * 0: this == other - * < 0: this < other - * }</pre> - * - * @param other The <code>FDBigInteger</code> to compare. - * @return A negative value, zero, or a positive value according to the - * result of the comparison. - */ - /*@ - @ ensures \result == (this.value() < other.value() ? -1 : this.value() > other.value() ? +1 : 0); - @*/ - public /*@ pure @*/ int cmp(FDBigInteger other) { - int aSize = nWords + offset; - int bSize = other.nWords + other.offset; - if (aSize > bSize) { - return 1; - } else if (aSize < bSize) { - return -1; - } - int aLen = nWords; - int bLen = other.nWords; - while (aLen > 0 && bLen > 0) { - int a = data[--aLen]; - int b = other.data[--bLen]; - if (a != b) { - return ((a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; - } - } - if (aLen > 0) { - return checkZeroTail(data, aLen); - } - if (bLen > 0) { - return -checkZeroTail(other.data, bLen); - } - return 0; - } - - /** - * Compares this <code>FDBigInteger</code> with - * <code>5<sup>p5</sup> * 2<sup>p2</sup></code>. - * Returns an integer accordingly as: - * <pre>{@code - * > 0: this > other - * 0: this == other - * < 0: this < other - * }</pre> - * @param p5 The exponent of the power-of-five factor. - * @param p2 The exponent of the power-of-two factor. - * @return A negative value, zero, or a positive value according to the - * result of the comparison. - */ - /*@ - @ requires p5 >= 0 && p2 >= 0; - @ ensures \result == (this.value() < pow52(p5, p2) ? -1 : this.value() > pow52(p5, p2) ? +1 : 0); - @*/ - public /*@ pure @*/ int cmpPow52(int p5, int p2) { - if (p5 == 0) { - int wordcount = p2 >> 5; - int bitcount = p2 & 0x1f; - int size = this.nWords + this.offset; - if (size > wordcount + 1) { - return 1; - } else if (size < wordcount + 1) { - return -1; - } - int a = this.data[this.nWords -1]; - int b = 1 << bitcount; - if (a != b) { - return ( (a & LONG_MASK) < (b & LONG_MASK)) ? -1 : 1; - } - return checkZeroTail(this.data, this.nWords - 1); - } - return this.cmp(big5pow(p5).leftShift(p2)); - } - - /** - * Compares this <code>FDBigInteger</code> with <code>x + y</code>. Returns a - * value according to the comparison as: - * <pre>{@code - * -1: this < x + y - * 0: this == x + y - * 1: this > x + y - * }</pre> - * @param x The first addend of the sum to compare. - * @param y The second addend of the sum to compare. - * @return -1, 0, or 1 according to the result of the comparison. - */ - /*@ - @ ensures \result == (this.value() < x.value() + y.value() ? -1 : this.value() > x.value() + y.value() ? +1 : 0); - @*/ - public /*@ pure @*/ int addAndCmp(FDBigInteger x, FDBigInteger y) { - FDBigInteger big; - FDBigInteger small; - int xSize = x.size(); - int ySize = y.size(); - int bSize; - int sSize; - if (xSize >= ySize) { - big = x; - small = y; - bSize = xSize; - sSize = ySize; - } else { - big = y; - small = x; - bSize = ySize; - sSize = xSize; - } - int thSize = this.size(); - if (bSize == 0) { - return thSize == 0 ? 0 : 1; - } - if (sSize == 0) { - return this.cmp(big); - } - if (bSize > thSize) { - return -1; - } - if (bSize + 1 < thSize) { - return 1; - } - long top = (big.data[big.nWords - 1] & LONG_MASK); - if (sSize == bSize) { - top += (small.data[small.nWords - 1] & LONG_MASK); - } - if ((top >>> 32) == 0) { - if (((top + 1) >>> 32) == 0) { - // good case - no carry extension - if (bSize < thSize) { - return 1; - } - // here sum.nWords == this.nWords - long v = (this.data[this.nWords - 1] & LONG_MASK); - if (v < top) { - return -1; - } - if (v > top + 1) { - return 1; - } - } - } else { // (top>>>32)!=0 guaranteed carry extension - if (bSize + 1 > thSize) { - return -1; - } - // here sum.nWords == this.nWords - top >>>= 32; - long v = (this.data[this.nWords - 1] & LONG_MASK); - if (v < top) { - return -1; - } - if (v > top + 1) { - return 1; - } - } - return this.cmp(big.add(small)); - } - - /** - * Makes this <code>FDBigInteger</code> immutable. - */ - /*@ - @ assignable this.isImmutable; - @ ensures this.isImmutable; - @*/ - public void makeImmutable() { - this.isImmutable = true; - } - - /** - * Multiplies this <code>FDBigInteger</code> by an integer. - * - * @param i The factor by which to multiply this <code>FDBigInteger</code>. - * @return This <code>FDBigInteger</code> multiplied by an integer. - */ - /*@ - @ requires this.value() == 0; - @ assignable \nothing; - @ ensures \result == this; - @ - @ also - @ - @ requires this.value() != 0; - @ assignable \nothing; - @ ensures \result.value() == \old(this.value() * UNSIGNED(i)); - @*/ - private FDBigInteger mult(int i) { - if (this.nWords == 0) { - return this; - } - int[] r = new int[nWords + 1]; - mult(data, nWords, i, r); - return new FDBigInteger(r, offset); - } - - /** - * Multiplies this <code>FDBigInteger</code> by another <code>FDBigInteger</code>. - * - * @param other The <code>FDBigInteger</code> factor by which to multiply. - * @return The product of this and the parameter <code>FDBigInteger</code>s. - */ - /*@ - @ requires this.value() == 0; - @ assignable \nothing; - @ ensures \result == this; - @ - @ also - @ - @ requires this.value() != 0 && other.value() == 0; - @ assignable \nothing; - @ ensures \result == other; - @ - @ also - @ - @ requires this.value() != 0 && other.value() != 0; - @ assignable \nothing; - @ ensures \result.value() == \old(this.value() * other.value()); - @*/ - private FDBigInteger mult(FDBigInteger other) { - if (this.nWords == 0) { - return this; - } - if (this.size() == 1) { - return other.mult(data[0]); - } - if (other.nWords == 0) { - return other; - } - if (other.size() == 1) { - return this.mult(other.data[0]); - } - int[] r = new int[nWords + other.nWords]; - mult(this.data, this.nWords, other.data, other.nWords, r); - return new FDBigInteger(r, this.offset + other.offset); - } - - /** - * Adds another <code>FDBigInteger</code> to this <code>FDBigInteger</code>. - * - * @param other The <code>FDBigInteger</code> to add. - * @return The sum of the <code>FDBigInteger</code>s. - */ - /*@ - @ assignable \nothing; - @ ensures \result.value() == \old(this.value() + other.value()); - @*/ - private FDBigInteger add(FDBigInteger other) { - FDBigInteger big, small; - int bigLen, smallLen; - int tSize = this.size(); - int oSize = other.size(); - if (tSize >= oSize) { - big = this; - bigLen = tSize; - small = other; - smallLen = oSize; - } else { - big = other; - bigLen = oSize; - small = this; - smallLen = tSize; - } - int[] r = new int[bigLen + 1]; - int i = 0; - long carry = 0L; - for (; i < smallLen; i++) { - carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ) - + ((i < small.offset ? 0L : (small.data[i - small.offset] & LONG_MASK))); - r[i] = (int) carry; - carry >>= 32; // signed shift. - } - for (; i < bigLen; i++) { - carry += (i < big.offset ? 0L : (big.data[i - big.offset] & LONG_MASK) ); - r[i] = (int) carry; - carry >>= 32; // signed shift. - } - r[bigLen] = (int) carry; - return new FDBigInteger(r, 0); - } - - - /** - * Multiplies a <code>FDBigInteger</code> by an int and adds another int. The - * result is computed in place. This method is intended only to be invoked - * from - * <code> - * FDBigInteger(long lValue, char[] digits, int kDigits, int nDigits) - * </code>. - * - * @param iv The factor by which to multiply this <code>FDBigInteger</code>. - * @param addend The value to add to the product of this - * <code>FDBigInteger</code> and <code>iv</code>. - */ - /*@ - @ requires this.value()*UNSIGNED(iv) + UNSIGNED(addend) < ((\bigint)1) << ((this.data.length + this.offset)*32); - @ assignable this.data[*]; - @ ensures this.value() == \old(this.value()*UNSIGNED(iv) + UNSIGNED(addend)); - @*/ - private /*@ helper @*/ void multAddMe(int iv, int addend) { - long v = iv & LONG_MASK; - // unroll 0th iteration, doing addition. - long p = v * (data[0] & LONG_MASK) + (addend & LONG_MASK); - data[0] = (int) p; - p >>>= 32; - for (int i = 1; i < nWords; i++) { - p += v * (data[i] & LONG_MASK); - data[i] = (int) p; - p >>>= 32; - } - if (p != 0L) { - data[nWords++] = (int) p; // will fail noisily if illegal! - } - } - - // - // original doc: - // - // do this -=q*S - // returns borrow - // - /** - * Multiplies the parameters and subtracts them from this - * <code>FDBigInteger</code>. - * - * @param q The integer parameter. - * @param S The <code>FDBigInteger</code> parameter. - * @return <code>this - q*S</code>. - */ - /*@ - @ ensures nWords == 0 ==> offset == 0; - @ ensures nWords > 0 ==> data[nWords - 1] != 0; - @*/ - /*@ - @ requires 0 < q && q <= (1L << 31); - @ requires data != null; - @ requires 0 <= nWords && nWords <= data.length && offset >= 0; - @ requires !this.isImmutable; - @ requires this.size() == S.size(); - @ requires this != S; - @ assignable this.nWords, this.offset, this.data, this.data[*]; - @ ensures -q <= \result && \result <= 0; - @ ensures this.size() == \old(this.size()); - @ ensures this.value() + (\result << (this.size()*32)) == \old(this.value() - q*S.value()); - @ ensures this.offset == \old(Math.min(this.offset, S.offset)); - @ ensures \old(this.offset <= S.offset) ==> this.nWords == \old(this.nWords); - @ ensures \old(this.offset <= S.offset) ==> this.offset == \old(this.offset); - @ ensures \old(this.offset <= S.offset) ==> this.data == \old(this.data); - @ - @ also - @ - @ requires q == 0; - @ assignable \nothing; - @ ensures \result == 0; - @*/ - private /*@ helper @*/ long multDiffMe(long q, FDBigInteger S) { - long diff = 0L; - if (q != 0) { - int deltaSize = S.offset - this.offset; - if (deltaSize >= 0) { - int[] sd = S.data; - int[] td = this.data; - for (int sIndex = 0, tIndex = deltaSize; sIndex < S.nWords; sIndex++, tIndex++) { - diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); - td[tIndex] = (int) diff; - diff >>= 32; // N.B. SIGNED shift. - } - } else { - deltaSize = -deltaSize; - int[] rd = new int[nWords + deltaSize]; - int sIndex = 0; - int rIndex = 0; - int[] sd = S.data; - for (; rIndex < deltaSize && sIndex < S.nWords; sIndex++, rIndex++) { - diff -= q * (sd[sIndex] & LONG_MASK); - rd[rIndex] = (int) diff; - diff >>= 32; // N.B. SIGNED shift. - } - int tIndex = 0; - int[] td = this.data; - for (; sIndex < S.nWords; sIndex++, tIndex++, rIndex++) { - diff += (td[tIndex] & LONG_MASK) - q * (sd[sIndex] & LONG_MASK); - rd[rIndex] = (int) diff; - diff >>= 32; // N.B. SIGNED shift. - } - this.nWords += deltaSize; - this.offset -= deltaSize; - this.data = rd; - } - } - return diff; - } - - - /** - * Multiplies by 10 a big integer represented as an array. The final carry - * is returned. - * - * @param src The array representation of the big integer. - * @param srcLen The number of elements of <code>src</code> to use. - * @param dst The product array. - * @return The final carry of the multiplication. - */ - /*@ - @ requires src.length >= srcLen && dst.length >= srcLen; - @ assignable dst[0 .. srcLen - 1]; - @ ensures 0 <= \result && \result < 10; - @ ensures AP(dst, srcLen) + (\result << (srcLen*32)) == \old(AP(src, srcLen) * 10); - @*/ - private static int multAndCarryBy10(int[] src, int srcLen, int[] dst) { - long carry = 0; - for (int i = 0; i < srcLen; i++) { - long product = (src[i] & LONG_MASK) * 10L + carry; - dst[i] = (int) product; - carry = product >>> 32; - } - return (int) carry; - } - - /** - * Multiplies by a constant value a big integer represented as an array. - * The constant factor is an <code>int</code>. - * - * @param src The array representation of the big integer. - * @param srcLen The number of elements of <code>src</code> to use. - * @param value The constant factor by which to multiply. - * @param dst The product array. - */ - /*@ - @ requires src.length >= srcLen && dst.length >= srcLen + 1; - @ assignable dst[0 .. srcLen]; - @ ensures AP(dst, srcLen + 1) == \old(AP(src, srcLen) * UNSIGNED(value)); - @*/ - private static void mult(int[] src, int srcLen, int value, int[] dst) { - long val = value & LONG_MASK; - long carry = 0; - for (int i = 0; i < srcLen; i++) { - long product = (src[i] & LONG_MASK) * val + carry; - dst[i] = (int) product; - carry = product >>> 32; - } - dst[srcLen] = (int) carry; - } - - /** - * Multiplies by a constant value a big integer represented as an array. - * The constant factor is a long represent as two <code>int</code>s. - * - * @param src The array representation of the big integer. - * @param srcLen The number of elements of <code>src</code> to use. - * @param v0 The lower 32 bits of the long factor. - * @param v1 The upper 32 bits of the long factor. - * @param dst The product array. - */ - /*@ - @ requires src != dst; - @ requires src.length >= srcLen && dst.length >= srcLen + 2; - @ assignable dst[0 .. srcLen + 1]; - @ ensures AP(dst, srcLen + 2) == \old(AP(src, srcLen) * (UNSIGNED(v0) + (UNSIGNED(v1) << 32))); - @*/ - private static void mult(int[] src, int srcLen, int v0, int v1, int[] dst) { - long v = v0 & LONG_MASK; - long carry = 0; - for (int j = 0; j < srcLen; j++) { - long product = v * (src[j] & LONG_MASK) + carry; - dst[j] = (int) product; - carry = product >>> 32; - } - dst[srcLen] = (int) carry; - v = v1 & LONG_MASK; - carry = 0; - for (int j = 0; j < srcLen; j++) { - long product = (dst[j + 1] & LONG_MASK) + v * (src[j] & LONG_MASK) + carry; - dst[j + 1] = (int) product; - carry = product >>> 32; - } - dst[srcLen + 1] = (int) carry; - } - - // Fails assertion for negative exponent. - /** - * Computes <code>5</code> raised to a given power. - * - * @param p The exponent of 5. - * @return <code>5<sup>p</sup></code>. - */ - private static FDBigInteger big5pow(int p) { - assert p >= 0 : p; // negative power of 5 - if (p < MAX_FIVE_POW) { - return POW_5_CACHE[p]; - } - return big5powRec(p); - } - - // slow path - /** - * Computes <code>5</code> raised to a given power. - * - * @param p The exponent of 5. - * @return <code>5<sup>p</sup></code>. - */ - private static FDBigInteger big5powRec(int p) { - if (p < MAX_FIVE_POW) { - return POW_5_CACHE[p]; - } - // construct the value. - // recursively. - int q, r; - // in order to compute 5^p, - // compute its square root, 5^(p/2) and square. - // or, let q = p / 2, r = p -q, then - // 5^p = 5^(q+r) = 5^q * 5^r - q = p >> 1; - r = p - q; - FDBigInteger bigq = big5powRec(q); - if (r < SMALL_5_POW.length) { - return bigq.mult(SMALL_5_POW[r]); - } else { - return bigq.mult(big5powRec(r)); - } - } - - // for debugging ... - /** - * Converts this <code>FDBigInteger</code> to a hexadecimal string. - * - * @return The hexadecimal string representation. - */ - public String toHexString(){ - if(nWords ==0) { - return "0"; - } - StringBuilder sb = new StringBuilder((nWords +offset)*8); - for(int i= nWords -1; i>=0; i--) { - String subStr = Integer.toHexString(data[i]); - for(int j = subStr.length(); j<8; j++) { - sb.append('0'); - } - sb.append(subStr); - } - for(int i=offset; i>0; i--) { - sb.append("00000000"); - } - return sb.toString(); - } - - // for debugging ... - /** - * Converts this <code>FDBigInteger</code> to a <code>BigInteger</code>. - * - * @return The <code>BigInteger</code> representation. - */ - public BigInteger toBigInteger() { - byte[] magnitude = new byte[nWords * 4 + 1]; - for (int i = 0; i < nWords; i++) { - int w = data[i]; - magnitude[magnitude.length - 4 * i - 1] = (byte) w; - magnitude[magnitude.length - 4 * i - 2] = (byte) (w >> 8); - magnitude[magnitude.length - 4 * i - 3] = (byte) (w >> 16); - magnitude[magnitude.length - 4 * i - 4] = (byte) (w >> 24); - } - return new BigInteger(magnitude).shiftLeft(offset * 32); - } - - // for debugging ... - /** - * Converts this <code>FDBigInteger</code> to a string. - * - * @return The string representation. - */ - @Override - public String toString(){ - return toBigInteger().toString(); - } -}
--- a/jdk/src/java.base/share/classes/sun/misc/FloatConsts.java Wed Dec 23 15:41:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -/** - * This class contains additional constants documenting limits of the - * <code>float</code> type. - * - * @author Joseph D. Darcy - */ - -public class FloatConsts { - /** - * Don't let anyone instantiate this class. - */ - private FloatConsts() {} - - public static final float POSITIVE_INFINITY = java.lang.Float.POSITIVE_INFINITY; - public static final float NEGATIVE_INFINITY = java.lang.Float.NEGATIVE_INFINITY; - public static final float NaN = java.lang.Float.NaN; - public static final float MAX_VALUE = java.lang.Float.MAX_VALUE; - public static final float MIN_VALUE = java.lang.Float.MIN_VALUE; - - /** - * A constant holding the smallest positive normal value of type - * <code>float</code>, 2<sup>-126</sup>. It is equal to the value - * returned by <code>Float.intBitsToFloat(0x00800000)</code>. - */ - public static final float MIN_NORMAL = 1.17549435E-38f; - - /** - * The number of logical bits in the significand of a - * <code>float</code> number, including the implicit bit. - */ - public static final int SIGNIFICAND_WIDTH = 24; - - /** - * Maximum exponent a finite <code>float</code> number may have. - * It is equal to the value returned by - * <code>Math.ilogb(Float.MAX_VALUE)</code>. - */ - public static final int MAX_EXPONENT = 127; - - /** - * Minimum exponent a normalized <code>float</code> number may - * have. It is equal to the value returned by - * <code>Math.ilogb(Float.MIN_NORMAL)</code>. - */ - public static final int MIN_EXPONENT = -126; - - /** - * The exponent the smallest positive <code>float</code> subnormal - * value would have if it could be normalized. - */ - public static final int MIN_SUB_EXPONENT = MIN_EXPONENT - - (SIGNIFICAND_WIDTH - 1); - - /** - * Bias used in representing a <code>float</code> exponent. - */ - public static final int EXP_BIAS = 127; - - /** - * Bit mask to isolate the sign bit of a <code>float</code>. - */ - public static final int SIGN_BIT_MASK = 0x80000000; - - /** - * Bit mask to isolate the exponent field of a - * <code>float</code>. - */ - public static final int EXP_BIT_MASK = 0x7F800000; - - /** - * Bit mask to isolate the significand field of a - * <code>float</code>. - */ - public static final int SIGNIF_BIT_MASK = 0x007FFFFF; - - static { - // verify bit masks cover all bit positions and that the bit - // masks are non-overlapping - assert(((SIGN_BIT_MASK | EXP_BIT_MASK | SIGNIF_BIT_MASK) == ~0) && - (((SIGN_BIT_MASK & EXP_BIT_MASK) == 0) && - ((SIGN_BIT_MASK & SIGNIF_BIT_MASK) == 0) && - ((EXP_BIT_MASK & SIGNIF_BIT_MASK) == 0))); - } -}
--- a/jdk/src/java.base/share/classes/sun/misc/FloatingDecimal.java Wed Dec 23 15:41:55 2015 -0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2552 +0,0 @@ -/* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code 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 General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package sun.misc; - -import java.util.Arrays; -import java.util.regex.*; - -/** - * A class for converting between ASCII and decimal representations of a single - * or double precision floating point number. Most conversions are provided via - * static convenience methods, although a <code>BinaryToASCIIConverter</code> - * instance may be obtained and reused. - */ -public class FloatingDecimal{ - // - // Constants of the implementation; - // most are IEEE-754 related. - // (There are more really boring constants at the end.) - // - static final int EXP_SHIFT = DoubleConsts.SIGNIFICAND_WIDTH - 1; - static final long FRACT_HOB = ( 1L<<EXP_SHIFT ); // assumed High-Order bit - static final long EXP_ONE = ((long)DoubleConsts.EXP_BIAS)<<EXP_SHIFT; // exponent of 1.0 - static final int MAX_SMALL_BIN_EXP = 62; - static final int MIN_SMALL_BIN_EXP = -( 63 / 3 ); - static final int MAX_DECIMAL_DIGITS = 15; - static final int MAX_DECIMAL_EXPONENT = 308; - static final int MIN_DECIMAL_EXPONENT = -324; - static final int BIG_DECIMAL_EXPONENT = 324; // i.e. abs(MIN_DECIMAL_EXPONENT) - static final int MAX_NDIGITS = 1100; - - static final int SINGLE_EXP_SHIFT = FloatConsts.SIGNIFICAND_WIDTH - 1; - static final int SINGLE_FRACT_HOB = 1<<SINGLE_EXP_SHIFT; - static final int SINGLE_MAX_DECIMAL_DIGITS = 7; - static final int SINGLE_MAX_DECIMAL_EXPONENT = 38; - static final int SINGLE_MIN_DECIMAL_EXPONENT = -45; - static final int SINGLE_MAX_NDIGITS = 200; - - static final int INT_DECIMAL_DIGITS = 9; - - /** - * Converts a double precision floating point value to a <code>String</code>. - * - * @param d The double precision value. - * @return The value converted to a <code>String</code>. - */ - public static String toJavaFormatString(double d) { - return getBinaryToASCIIConverter(d).toJavaFormatString(); - } - - /** - * Converts a single precision floating point value to a <code>String</code>. - * - * @param f The single precision value. - * @return The value converted to a <code>String</code>. - */ - public static String toJavaFormatString(float f) { - return getBinaryToASCIIConverter(f).toJavaFormatString(); - } - - /** - * Appends a double precision floating point value to an <code>Appendable</code>. - * @param d The double precision value. - * @param buf The <code>Appendable</code> with the value appended. - */ - public static void appendTo(double d, Appendable buf) { - getBinaryToASCIIConverter(d).appendTo(buf); - } - - /** - * Appends a single precision floating point value to an <code>Appendable</code>. - * @param f The single precision value. - * @param buf The <code>Appendable</code> with the value appended. - */ - public static void appendTo(float f, Appendable buf) { - getBinaryToASCIIConverter(f).appendTo(buf); - } - - /** - * Converts a <code>String</code> to a double precision floating point value. - * - * @param s The <code>String</code> to convert. - * @return The double precision value. - * @throws NumberFormatException If the <code>String</code> does not - * represent a properly formatted double precision value. - */ - public static double parseDouble(String s) throws NumberFormatException { - return readJavaFormatString(s).doubleValue(); - } - - /** - * Converts a <code>String</code> to a single precision floating point value. - * - * @param s The <code>String</code> to convert. - * @return The single precision value. - * @throws NumberFormatException If the <code>String</code> does not - * represent a properly formatted single precision value. - */ - public static float parseFloat(String s) throws NumberFormatException { - return readJavaFormatString(s).floatValue(); - } - - /** - * A converter which can process single or double precision floating point - * values into an ASCII <code>String</code> representation. - */ - public interface BinaryToASCIIConverter { - /** - * Converts a floating point value into an ASCII <code>String</code>. - * @return The value converted to a <code>String</code>. - */ - public String toJavaFormatString(); - - /** - * Appends a floating point value to an <code>Appendable</code>. - * @param buf The <code>Appendable</code> to receive the value. - */ - public void appendTo(Appendable buf); - - /** - * Retrieves the decimal exponent most closely corresponding to this value. - * @return The decimal exponent. - */ - public int getDecimalExponent(); - - /** - * Retrieves the value as an array of digits. - * @param digits The digit array. - * @return The number of valid digits copied into the array. - */ - public int getDigits(char[] digits); - - /** - * Indicates the sign of the value. - * @return {@code value < 0.0}. - */ - public boolean isNegative(); - - /** - * Indicates whether the value is either infinite or not a number. - * - * @return <code>true</code> if and only if the value is <code>NaN</code> - * or infinite. - */ - public boolean isExceptional(); - - /** - * Indicates whether the value was rounded up during the binary to ASCII - * conversion. - * - * @return <code>true</code> if and only if the value was rounded up. - */ - public boolean digitsRoundedUp(); - - /** - * Indicates whether the binary to ASCII conversion was exact. - * - * @return <code>true</code> if any only if the conversion was exact. - */ - public boolean decimalDigitsExact(); - } - - /** - * A <code>BinaryToASCIIConverter</code> which represents <code>NaN</code> - * and infinite values. - */ - private static class ExceptionalBinaryToASCIIBuffer implements BinaryToASCIIConverter { - private final String image; - private boolean isNegative; - - public ExceptionalBinaryToASCIIBuffer(String image, boolean isNegative) { - this.image = image; - this.isNegative = isNegative; - } - - @Override - public String toJavaFormatString() { - return image; - } - - @Override - public void appendTo(Appendable buf) { - if (buf instanceof StringBuilder) { - ((StringBuilder) buf).append(image); - } else if (buf instanceof StringBuffer) { - ((StringBuffer) buf).append(image); - } else { - assert false; - } - } - - @Override - public int getDecimalExponent() { - throw new IllegalArgumentException("Exceptional value does not have an exponent"); - } - - @Override - public int getDigits(char[] digits) { - throw new IllegalArgumentException("Exceptional value does not have digits"); - } - - @Override - public boolean isNegative() { - return isNegative; - } - - @Override - public boolean isExceptional() { - return true; - } - - @Override - public boolean digitsRoundedUp() { - throw new IllegalArgumentException("Exceptional value is not rounded"); - } - - @Override - public boolean decimalDigitsExact() { - throw new IllegalArgumentException("Exceptional value is not exact"); - } - } - - private static final String INFINITY_REP = "Infinity"; - private static final int INFINITY_LENGTH = INFINITY_REP.length(); - private static final String NAN_REP = "NaN"; - private static final int NAN_LENGTH = NAN_REP.length(); - - private static final BinaryToASCIIConverter B2AC_POSITIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer(INFINITY_REP, false); - private static final BinaryToASCIIConverter B2AC_NEGATIVE_INFINITY = new ExceptionalBinaryToASCIIBuffer("-" + INFINITY_REP, true); - private static final BinaryToASCIIConverter B2AC_NOT_A_NUMBER = new ExceptionalBinaryToASCIIBuffer(NAN_REP, false); - private static final BinaryToASCIIConverter B2AC_POSITIVE_ZERO = new BinaryToASCIIBuffer(false, new char[]{'0'}); - private static final BinaryToASCIIConverter B2AC_NEGATIVE_ZERO = new BinaryToASCIIBuffer(true, new char[]{'0'}); - - /** - * A buffered implementation of <code>BinaryToASCIIConverter</code>. - */ - static class BinaryToASCIIBuffer implements BinaryToASCIIConverter { - private boolean isNegative; - private int decExponent; - private int firstDigitIndex; - private int nDigits; - private final char[] digits; - private final char[] buffer = new char[26]; - - // - // The fields below provide additional information about the result of - // the binary to decimal digits conversion done in dtoa() and roundup() - // methods. They are changed if needed by those two methods. - // - - // True if the dtoa() binary to decimal conversion was exact. - private boolean exactDecimalConversion = false; - - // True if the result of the binary to decimal conversion was rounded-up - // at the end of the conversion process, i.e. roundUp() method was called. - private boolean decimalDigitsRoundedUp = false; - - /** - * Default constructor; used for non-zero values, - * <code>BinaryToASCIIBuffer</code> may be thread-local and reused - */ - BinaryToASCIIBuffer(){ - this.digits = new char[20]; - } - - /** - * Creates a specialized value (positive and negative zeros). - */ - BinaryToASCIIBuffer(boolean isNegative, char[] digits){ - this.isNegative = isNegative; - this.decExponent = 0; - this.digits = digits; - this.firstDigitIndex = 0; - this.nDigits = digits.length; - } - - @Override - public String toJavaFormatString() { - int len = getChars(buffer); - return new String(buffer, 0, len); - } - - @Override - public void appendTo(Appendable buf) { - int len = getChars(buffer); - if (buf instanceof StringBuilder) { - ((StringBuilder) buf).append(buffer, 0, len); - } else if (buf instanceof StringBuffer) { - ((StringBuffer) buf).append(buffer, 0, len); - } else { - assert false; - } - } - - @Override - public int getDecimalExponent() { - return decExponent; - } - - @Override - public int getDigits(char[] digits) { - System.arraycopy(this.digits,firstDigitIndex,digits,0,this.nDigits); - return this.nDigits; - } - - @Override - public boolean isNegative() { - return isNegative; - } - - @Override - public boolean isExceptional() { - return false; - } - - @Override - public boolean digitsRoundedUp() { - return decimalDigitsRoundedUp; - } - - @Override - public boolean decimalDigitsExact() { - return exactDecimalConversion; - } - - private void setSign(boolean isNegative) { - this.isNegative = isNegative; - } - - /** - * This is the easy subcase -- - * all the significant bits, after scaling, are held in lvalue. - * negSign and decExponent tell us what processing and scaling - * has already been done. Exceptional cases have already been - * stripped out. - * In particular: - * lvalue is a finite number (not Inf, nor NaN) - * lvalue > 0L (not zero, nor negative). - * - * The only reason that we develop the digits here, rather than - * calling on Long.toString() is that we can do it a little faster, - * and besides want to treat trailing 0s specially. If Long.toString - * changes, we should re-evaluate this strategy! - */ - private void developLongDigits( int decExponent, long lvalue, int insignificantDigits ){ - if ( insignificantDigits != 0 ){ - // Discard non-significant low-order bits, while rounding, - // up to insignificant value. - long pow10 = FDBigInteger.LONG_5_POW[insignificantDigits] << insignificantDigits; // 10^i == 5^i * 2^i; - long residue = lvalue % pow10; - lvalue /= pow10; - decExponent += insignificantDigits; - if ( residue >= (pow10>>1) ){ - // round up based on the low-order bits we're discarding - lvalue++; - } - } - int digitno = digits.length -1; - int c; - if ( lvalue <= Integer.MAX_VALUE ){ - assert lvalue > 0L : lvalue; // lvalue <= 0 - // even easier subcase! - // can do int arithmetic rather than long! - int ivalue = (int)lvalue; - c = ivalue%10; - ivalue /= 10; - while ( c == 0 ){ - decExponent++; - c = ivalue%10; - ivalue /= 10; - } - while ( ivalue != 0){ - digits[digitno--] = (char)(c+'0'); - decExponent++; - c = ivalue%10; - ivalue /= 10; - } - digits[digitno] = (char)(c+'0'); - } else { - // same algorithm as above (same bugs, too ) - // but using long arithmetic. - c = (int)(lvalue%10L); - lvalue /= 10L; - while ( c == 0 ){ - decExponent++; - c = (int)(lvalue%10L); - lvalue /= 10L; - } - while ( lvalue != 0L ){ - digits[digitno--] = (char)(c+'0'); - decExponent++; - c = (int)(lvalue%10L); - lvalue /= 10; - } - digits[digitno] = (char)(c+'0'); - } - this.decExponent = decExponent+1; - this.firstDigitIndex = digitno; - this.nDigits = this.digits.length - digitno; - } - - private void dtoa( int binExp, long fractBits, int nSignificantBits, boolean isCompatibleFormat) - { - assert fractBits > 0 ; // fractBits here can't be zero or negative - assert (fractBits & FRACT_HOB)!=0 ; // Hi-order bit should be set - // Examine number. Determine if it is an easy case, - // which we can do pretty trivially using float/long conversion, - // or whether we must do real work. - final int tailZeros = Long.numberOfTrailingZeros(fractBits); - - // number of significant bits of fractBits; - final int nFractBits = EXP_SHIFT+1-tailZeros; - - // reset flags to default values as dtoa() does not always set these - // flags and a prior call to dtoa() might have set them to incorrect - // values with respect to the current state. - decimalDigitsRoundedUp = false; - exactDecimalConversion = false; - - // number of significant bits to the right of the point. - int nTinyBits = Math.max( 0, nFractBits - binExp - 1 ); - if ( binExp <= MAX_SMALL_BIN_EXP && binExp >= MIN_SMALL_BIN_EXP ){ - // Look more closely at the number to decide if, - // with scaling by 10^nTinyBits, the result will fit in - // a long. - if ( (nTinyBits < FDBigInteger.LONG_5_POW.length) && ((nFractBits + N_5_BITS[nTinyBits]) < 64 ) ){ - // - // We can do this: - // take the fraction bits, which are normalized. - // (a) nTinyBits == 0: Shift left or right appropriately - // to align the binary point at the extreme right, i.e. - // where a long int point is expected to be. The integer - // result is easily converted to a string. - // (b) nTinyBits > 0: Shift right by EXP_SHIFT-nFractBits, - // which effectively converts to long and scales by - // 2^nTinyBits. Then multiply by 5^nTinyBits to - // complete the scaling. We know this won't overflow - // because we just counted the number of bits necessary - // in the result. The integer you get from this can - // then be converted to a string pretty easily. - // - if ( nTinyBits == 0 ) { - int insignificant; - if ( binExp > nSignificantBits ){ - insignificant = insignificantDigitsForPow2(binExp-nSignificantBits-1); - } else { - insignificant = 0; - } - if ( binExp >= EXP_SHIFT ){ - fractBits <<= (binExp-EXP_SHIFT); - } else { - fractBits >>>= (EXP_SHIFT-binExp) ; - } - developLongDigits( 0, fractBits, insignificant ); - return; - } - // - // The following causes excess digits to be printed - // out in the single-float case. Our manipulation of - // halfULP here is apparently not correct. If we - // better understand how this works, perhaps we can - // use this special case again. But for the time being, - // we do not. - // else { - // fractBits >>>= EXP_SHIFT+1-nFractBits; - // fractBits//= long5pow[ nTinyBits ]; - // halfULP = long5pow[ nTinyBits ] >> (1+nSignificantBits-nFractBits); - // developLongDigits( -nTinyBits, fractBits, insignificantDigits(halfULP) ); - // return; - // } - // - } - } - // - // This is the hard case. We are going to compute large positive - // integers B and S and integer decExp, s.t. - // d = ( B / S )// 10^decExp - // 1 <= B / S < 10 - // Obvious choices are: - // decExp = floor( log10(d) ) - // B = d// 2^nTinyBits// 10^max( 0, -decExp ) - // S = 10^max( 0, decExp)// 2^nTinyBits - // (noting that nTinyBits has already been forced to non-negative) - // I am also going to compute a large positive integer - // M = (1/2^nSignificantBits)// 2^nTinyBits// 10^max( 0, -decExp ) - // i.e. M is (1/2) of the ULP of d, scaled like B. - // When we iterate through dividing B/S and picking off the - // quotient bits, we will know when to stop when the remainder - // is <= M. - // - // We keep track of powers of 2 and powers of 5. - // - int decExp = estimateDecExp(fractBits,binExp); - int B2, B5; // powers of 2 and powers of 5, respectively, in B - int S2, S5; // powers of 2 and powers of 5, respectively, in S - int M2, M5; // powers of 2 and powers of 5, respectively, in M - - B5 = Math.max( 0, -decExp ); - B2 = B5 + nTinyBits + binExp; - - S5 = Math.max( 0, decExp ); - S2 = S5 + nTinyBits; - - M5 = B5; - M2 = B2 - nSignificantBits; - - // - // the long integer fractBits contains the (nFractBits) interesting - // bits from the mantissa of d ( hidden 1 added if necessary) followed - // by (EXP_SHIFT+1-nFractBits) zeros. In the interest of compactness, - // I will shift out those zeros before turning fractBits into a - // FDBigInteger. The resulting whole number will be - // d * 2^(nFractBits-1-binExp). - // - fractBits >>>= tailZeros; - B2 -= nFractBits-1; - int common2factor = Math.min( B2, S2 ); - B2 -= common2factor; - S2 -= common2factor; - M2 -= common2factor; - - // - // HACK!! For exact powers of two, the next smallest number - // is only half as far away as we think (because the meaning of - // ULP changes at power-of-two bounds) for this reason, we - // hack M2. Hope this works. - // - if ( nFractBits == 1 ) { - M2 -= 1; - } - - if ( M2 < 0 ){ - // oops. - // since we cannot scale M down far enough, - // we must scale the other values up. - B2 -= M2; - S2 -= M2; - M2 = 0; - } - // - // Construct, Scale, iterate. - // Some day, we'll write a stopping test that takes - // account of the asymmetry of the spacing of floating-point - // numbers below perfect powers of 2 - // 26 Sept 96 is not that day. - // So we use a symmetric test. - // - int ndigit = 0; - boolean low, high; - long lowDigitDifference; - int q; - - // - // Detect the special cases where all the numbers we are about - // to compute will fit in int or long integers. - // In these cases, we will avoid doing FDBigInteger arithmetic. - // We use the same algorithms, except that we "normalize" - // our FDBigIntegers before iterating. This is to make division easier, - // as it makes our fist guess (quotient of high-order words) - // more accurate! - // - // Some day, we'll write a stopping test that takes - // account of the asymmetry of the spacing of floating-point - // numbers below perfect powers of 2 - // 26 Sept 96 is not that day. - // So we use a symmetric test. - // - // binary digits needed to represent B, approx. - int Bbits = nFractBits + B2 + (( B5 < N_5_BITS.length )? N_5_BITS[B5] : ( B5*3 )); - - // binary digits needed to represent 10*S, approx. - int tenSbits = S2+1 + (( (S5+1) < N_5_BITS.length )? N_5_BITS[(S5+1)] : ( (S5+1)*3 )); - if ( Bbits < 64 && tenSbits < 64){ - if ( Bbits < 32 && tenSbits < 32){ - // wa-hoo! They're all ints! - int b = ((int)fractBits * FDBigInteger.SMALL_5_POW[B5] ) << B2; - int s = FDBigInteger.SMALL_5_POW[S5] << S2; - int m = FDBigInteger.SMALL_5_POW[M5] << M2; - int tens = s * 10; - // - // Unroll the first iteration. If our decExp estimate - // was too high, our first quotient will be zero. In this - // case, we discard it and decrement decExp. - // - ndigit = 0; - q = b / s; - b = 10 * ( b % s ); - m *= 10; - low = (b < m ); - high = (b+m > tens ); - assert q < 10 : q; // excessively large digit - if ( (q == 0) && ! high ){ - // oops. Usually ignore leading zero. - decExp--; - } else { - digits[ndigit++] = (char)('0' + q); - } - // - // HACK! Java spec sez that we always have at least - // one digit after the . in either F- or E-form output. - // Thus we will need more than one digit if we're using - // E-form - // - if ( !isCompatibleFormat ||decExp < -3 || decExp >= 8 ){ - high = low = false; - } - while( ! low && ! high ){ - q = b / s; - b = 10 * ( b % s ); - m *= 10; - assert q < 10 : q; // excessively large digit - if ( m > 0L ){ - low = (b < m ); - high = (b+m > tens ); - } else { - // hack -- m might overflow! - // in this case, it is certainly > b, - // which won't - // and b+m > tens, too, since that has overflowed - // either! - low = true; - high = true; - } - digits[ndigit++] = (char)('0' + q); - } - lowDigitDifference = (b<<1) - tens; - exactDecimalConversion = (b == 0); - } else { - // still good! they're all longs! - long b = (fractBits * FDBigInteger.LONG_5_POW[B5] ) << B2; - long s = FDBigInteger.LONG_5_POW[S5] << S2; - long m = FDBigInteger.LONG_5_POW[M5] << M2; - long tens = s * 10L; - // - // Unroll the first iteration. If our decExp estimate - // was too high, our first quotient will be zero. In this - // case, we discard it and decrement decExp. - // - ndigit = 0; - q = (int) ( b / s ); - b = 10L * ( b % s ); - m *= 10L; - low = (b < m ); - high = (b+m > tens ); - assert q < 10 : q; // excessively large digit - if ( (q == 0) && ! high ){ - // oops. Usually ignore leading zero. - decExp--; - } else { - digits[ndigit++] = (char)('0' + q); - } - // - // HACK! Java spec sez that we always have at least - // one digit after the . in either F- or E-form output. - // Thus we will need more than one digit if we're using - // E-form - // - if ( !isCompatibleFormat || decExp < -3 || decExp >= 8 ){ - high = low = false; - } - while( ! low && ! high ){ - q = (int) ( b / s ); - b = 10 * ( b % s ); - m *= 10; - assert q < 10 : q; // excessively large digit - if ( m > 0L ){ - low = (b < m ); - high = (b+m > tens ); - } else { - // hack -- m might overflow! - // in this case, it is certainly > b, - // which won't - // and b+m > tens, too, since that has overflowed - // either! - low = true; - high = true; - } - digits[ndigit++] = (char)('0' + q); - } - lowDigitDifference = (b<<1) - tens; - exactDecimalConversion = (b == 0); - } - } else { - // - // We really must do FDBigInteger arithmetic. - // Fist, construct our FDBigInteger initial values. - // - FDBigInteger Sval = FDBigInteger.valueOfPow52(S5, S2); - int shiftBias = Sval.getNormalizationBias(); - Sval = Sval.leftShift(shiftBias); // normalize so that division works better - - FDBigInteger Bval = FDBigInteger.valueOfMulPow52(fractBits, B5, B2 + shiftBias); - FDBigInteger Mval = FDBigInteger.valueOfPow52(M5 + 1, M2 + shiftBias + 1); - - FDBigInteger tenSval = FDBigInteger.valueOfPow52(S5 + 1, S2 + shiftBias + 1); //Sval.mult( 10 ); - // - // Unroll the first iteration. If our decExp estimate - // was too high, our first quotient will be zero. In this - // case, we discard it and decrement decExp. - // - ndigit = 0; - q = Bval.quoRemIteration( Sval ); - low = (Bval.cmp( Mval ) < 0); - high = tenSval.addAndCmp(Bval,Mval)<=0; - - assert q < 10 : q; // excessively large digit - if ( (q == 0) && ! high ){ - // oops. Usually ignore leading zero. - decExp--; - } else { - digits[ndigit++] = (char)('0' + q); - } - // - // HACK! Java spec sez that we always have at least - // one digit after the . in either F- or E-form output. - // Thus we will need more than one digit if we're using - // E-form - // - if (!isCompatibleFormat || decExp < -3 || decExp >= 8 ){ - high = low = false; - } - while( ! low && ! high ){ - q = Bval.quoRemIteration( Sval ); - assert q < 10 : q; // excessively large digit - Mval = Mval.multBy10(); //Mval = Mval.mult( 10 ); - low = (Bval.cmp( Mval ) < 0); - high = tenSval.addAndCmp(Bval,Mval)<=0; - digits[ndigit++] = (char)('0' + q); - } - if ( high && low ){ - Bval = Bval.leftShift(1); - lowDigitDifference = Bval.cmp(tenSval); - } else { - lowDigitDifference = 0L; // this here only for flow analysis! - } - exactDecimalConversion = (Bval.cmp( FDBigInteger.ZERO ) == 0); - } - this.decExponent = decExp+1; - this.firstDigitIndex = 0; - this.nDigits = ndigit; - // - // Last digit gets rounded based on stopping condition. - // - if ( high ){ - if ( low ){ - if ( lowDigitDifference == 0L ){ - // it's a tie! - // choose based on which digits we like. - if ( (digits[firstDigitIndex+nDigits-1]&1) != 0 ) { - roundup(); - } - } else if ( lowDigitDifference > 0 ){ - roundup(); - } - } else { - roundup(); - } - } - } - - // add one to the least significant digit. - // in the unlikely event there is a carry out, deal with it. - // assert that this will only happen where there - // is only one digit, e.g. (float)1e-44 seems to do it. - // - private void roundup() { - int i = (firstDigitIndex + nDigits - 1); - int q = digits[i]; - if (q == '9') { - while (q == '9' && i > firstDigitIndex) { - digits[i] = '0'; - q = digits[--i]; - } - if (q == '9') { - // carryout! High-order 1, rest 0s, larger exp. - decExponent += 1; - digits[firstDigitIndex] = '1'; - return; - } - // else fall through. - } - digits[i] = (char) (q + 1); - decimalDigitsRoundedUp = true; - } - - /** - * Estimate decimal exponent. (If it is small-ish, - * we could double-check.) - * - * First, scale the mantissa bits such that 1 <= d2 < 2. - * We are then going to estimate - * log10(d2) ~=~ (d2-1.5)/1.5 + log(1.5) - * and so we can estimate - * log10(d) ~=~ log10(d2) + binExp * log10(2) - * take the floor and call it decExp. - */ - static int estimateDecExp(long fractBits, int binExp) { - double d2 = Double.longBitsToDouble( EXP_ONE | ( fractBits & DoubleConsts.SIGNIF_BIT_MASK ) ); - double d = (d2-1.5D)*0.289529654D + 0.176091259 + (double)binExp * 0.301029995663981; - long dBits = Double.doubleToRawLongBits(d); //can't be NaN here so use raw - int exponent = (int)((dBits & DoubleConsts.EXP_BIT_MASK) >> EXP_SHIFT) - DoubleConsts.EXP_BIAS; - boolean isNegative = (dBits & DoubleConsts.SIGN_BIT_MASK) != 0; // discover sign - if(exponent>=0 && exponent<52) { // hot path - long mask = DoubleConsts.SIGNIF_BIT_MASK >> exponent; - int r = (int)(( (dBits&DoubleConsts.SIGNIF_BIT_MASK) | FRACT_HOB )>>(EXP_SHIFT-exponent)); - return isNegative ? (((mask & dBits) == 0L ) ? -r : -r-1 ) : r; - } else if (exponent < 0) { - return (((dBits&~DoubleConsts.SIGN_BIT_MASK) == 0) ? 0 : - ( (isNegative) ? -1 : 0) ); - } else { //if (exponent >= 52) - return (int)d; - } - } - - private static int insignificantDigits(int insignificant) { - int i; - for ( i = 0; insignificant >= 10L; i++ ) { - insignificant /= 10L; - } - return i; - } - - /** - * Calculates - * <pre> - * insignificantDigitsForPow2(v) == insignificantDigits(1L<<v) - * </pre> - */ - private static int insignificantDigitsForPow2(int p2) { - if(p2>1 && p2 < insignificantDigitsNumber.length) { - return insignificantDigitsNumber[p2]; - } - return 0; - } - - /** - * If insignificant==(1L << ixd) - * i = insignificantDigitsNumber[idx] is the same as: - * int i; - * for ( i = 0; insignificant >= 10L; i++ ) - * insignificant /= 10L; - */ - private static int[] insignificantDigitsNumber = { - 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, - 4, 4, 4, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, - 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 11, - 12, 12, 12, 12, 13, 13, 13, 14, 14, 14, - 15, 15, 15, 15, 16, 16, 16, 17, 17, 17, - 18, 18, 18, 19 - }; - - // approximately ceil( log2( long5pow[i] ) ) - private static final int[] N_5_BITS = { - 0, - 3, - 5, - 7, - 10, - 12, - 14, - 17, - 19, - 21, - 24, - 26, - 28, - 31, - 33, - 35, - 38, - 40, - 42, - 45, - 47, - 49, - 52, - 54, - 56, - 59, - 61, - }; - - private int getChars(char[] result) { - assert nDigits <= 19 : nDigits; // generous bound on size of nDigits - int i = 0; - if (isNegative) { - result[0] = '-'; - i = 1; - } - if (decExponent > 0 && decExponent < 8) { - // print digits.digits. - int charLength = Math.min(nDigits, decExponent); - System.arraycopy(digits, firstDigitIndex, result, i, charLength); - i += charLength; - if (charLength < decExponent) { - charLength = decExponent - charLength; - Arrays.fill(result,i,i+charLength,'0'); - i += charLength; - result[i++] = '.'; - result[i++] = '0'; - } else { - result[i++] = '.'; - if (charLength < nDigits) { - int t = nDigits - charLength; - System.arraycopy(digits, firstDigitIndex+charLength, result, i, t); - i += t; - } else { - result[i++] = '0'; - } - } - } else if (decExponent <= 0 && decExponent > -3) { - result[i++] = '0'; - result[i++] = '.'; - if (decExponent != 0) { - Arrays.fill(result, i, i-decExponent, '0'); - i -= decExponent; - } - System.arraycopy(digits, firstDigitIndex, result, i, nDigits); - i += nDigits; - } else { - result[i++] = digits[firstDigitIndex]; - result[i++] = '.'; - if (nDigits > 1) { - System.arraycopy(digits, firstDigitIndex+1, result, i, nDigits - 1); - i += nDigits - 1; - } else { - result[i++] = '0'; - } - result[i++] = 'E'; - int e; - if (decExponent <= 0) { - result[i++] = '-'; - e = -decExponent + 1; - } else { - e = decExponent - 1; - } - // decExponent has 1, 2, or 3, digits - if (e <= 9) { - result[i++] = (char) (e + '0'); - } else if (e <= 99) { - result[i++] = (char) (e / 10 + '0'); - result[i++] = (char) (e % 10 + '0'); -